多线程与多任务异步协程高效爬虫

简介: 多线程与多任务异步协程高效爬虫

爬虫

前言

线程与进程的讲解:
进程是一个资源单位,每一个进程至少有一个线程,而线程是一个执行单位。

而一个程序若是只有一个线程,那么该程序将会串行运行,如果要爬取大量的数据那么执行效率将会显得比较低下。


一、多线程爬虫:

对于大量数据要多次发送请求可以利用python中内置库threaing开启多个线程,但是这样子的话就只能手动一个一个的开启线程,所以还有一种方法使用线程池来进行多线程操作
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(50) as T:

这样就开启了50个线程的线程池

比如下面一个场景:
要爬取一个网站多页的数据,而该网站每一页url的请求体中有第几页的参数
所以想要爬取50页就遍历(1,52)即可。如果此时并没开启线程池去请求50次,就很慢,但是如果开启了50个线程那么就可以同时去进行,速度自然快得多得多了

样例代码:

import requests
from concurrent.futures import ThreadPoolExecutor




def DownLoad_OnePage(Url,i):

    headers={
   
        'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
    }

    data={
   
        "current":i
    }
    resp=requests.post(Url,data=data)
    for price in (resp.json()['list']):
        data_row=price['prodName']+':'+price['avgPrice']
        print(f'第{i}页数据{data_row}爬取完毕')
        f.write(data_row)
        f.write('\n')



if __name__=='__main__':
    f = open('data.txt', 'w', encoding='utf-8')
    with ThreadPoolExecutor(50) as T:
        for i in range(1,50):
            T.submit(DownLoad_OnePage,Url="http://www.xinfadi.com.cn/getPriceData.html",i=i)
    print('爬取完毕')
    f.close()

二、多任务异步协程爬虫

概述:

当程序中遇到了如input,sleep等会阻塞程序运行的操作时,使用协程就可以跳过该阻塞运行其他的代码,再当阻塞停止时返回。

而requests.get(**)在网络请求返回数据之前,程序也是处于阻塞状态的一般情况下,当程序处于IO操作的时候。线程都会处于阻塞状态

协程:
当程序遇见了IO操作的时候,可以选择性的切换到其他任务上.

在微观上是一个任务一个任务的进行切换.切换条件一般就是IO操作
在宏观上,我们能看到的其实是多个任务一起在执行

例如:

import asyncio
import time
async def func1():
    print("协程1")
    # time.sleep(4) 当程序出现了同步的操作,异步就断掉了。
    await asyncio.sleep(4)  # 阻塞时进行await
    print("协程1")


async def func2():
    print("协程2")
    # time.sleep(3)
    await asyncio.sleep(3)
    print("协程2")
async def func3():
    print("协程3")
    await asyncio.sleep(2)
    print("协程3")

async def main():
    tasks=[
        func1(),
        func2(),
        func3()
    ]    # 添加多任务异步协程
    await asyncio.wait(tasks)
if __name__=='__main__':
    # 主线程最好不出现协程,所以应在写一个main函数在主线程运行
    t1=time.time()
    asyncio.run(main())   # 协程运行
    t2=time.time()
    print(t2-t1)

这一段代码如果没有利用协程,三个time.sleep()至少也会运行9s了
但是这段代码只会运行4s多一点点。

而实际上多任务异步协程进行爬取时模板与上面样例实际是差不多的

实战样例:

import asyncio
import aiohttp   
import requests
import aiofile   
import json
async def aioDownLoad(cid,b_id,title):
    data = {
   
        "book_id" :b_id,
        "cid":f"{b_id}|{cid}",
        "need_bookinfo":1
    }
    data = json.dumps(data)
    url = "https://dushu.baidu.com/api/pc/getChapterContent?data={%22book_id%22:%22"+str(b_id)+"%22,%22cid%22:%22"+str(b_id)+"|"+str(cid)+"%22,%22need_bookinfo%22:1}"
    async  with aiohttp.ClientSession() as Session:
        async with Session.get(url) as resp:
            dic = await resp.json()
            async with aiofile.AIOFile(f'novel/{title}.txt','w','utf-8') as f:
                await f.write(dic['data']['novel']['content'])
async def getCatlog(url):
    resp = requests.get(url)
    dic=resp.json()
    tasks = []
    for item in dic['data']['novel']['items']:
        title = item['title']
        cid = item['cid']
        tasks.append(aioDownLoad(cid,b_id,title))
    await asyncio.wait(tasks)
if __name__ == '__main__':
    b_id='4306063500'
    url='https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"'+b_id+'"}'
    asyncio.run(getCatlog(url))

aiohttp是python的⼀个⾮常优秀的第三⽅异步http请求库
举一反三aiofile就是第三方异步文件操作库

这两个的操作与requests和文件操作都是极其类似的,看上面的样例就能很容易理解。

总结

提示:这里对文章进行总结:

除了爬取多页这种要发送大量请求的的案例可以用多任务异步协程节省大量时间外,还有就是下载到本地也会处于阻塞状态,例如在爬取下载视频的时候,要知道现在视频都是分割成了海量几秒的视频放在一个m3u8文件中,所以在下载的时候也可以多任务异步协程同时下载。

相关文章
|
1月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
91 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
1月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第16天】进程、线程和协程是计算机程序执行的三种基本形式。进程是操作系统资源分配和调度的基本单位,具有独立的内存空间,稳定性高但资源消耗大。线程是进程内的执行单元,共享内存,轻量级且并发性好,但同步复杂。协程是用户态的轻量级调度单位,适用于高并发和IO密集型任务,资源消耗最小,但不支持多核并行。
46 1
|
1月前
|
存储 消息中间件 人工智能
进程,线程,协程 - 你了解多少?
本故事采用简洁明了的对话方式,尽洪荒之力让你在轻松无负担的氛围中,稍微深入地理解进程、线程和协程的相关原理知识
41 2
进程,线程,协程 - 你了解多少?
|
1月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第15天】进程、线程和协程是操作系统中三种不同的执行单元。进程是资源分配和调度的基本单位,每个进程有独立的内存空间;线程是进程内的执行路径,共享进程资源,切换成本较低;协程则更轻量,由用户态调度,适合处理高并发和IO密集型任务。进程提供高隔离性和安全性,线程支持高并发,协程则在资源消耗和调度灵活性方面表现优异。
50 2
|
1月前
|
数据采集 前端开发 NoSQL
Python编程异步爬虫实战案例
Python编程异步爬虫实战案例
|
1月前
|
存储 运维 API
源码解密协程队列和线程队列的实现原理(一)
源码解密协程队列和线程队列的实现原理(一)
35 1
|
1月前
|
数据采集 存储 NoSQL
提高爬虫性能的 5 个关键技巧:从并发到异步执行
本文介绍了提高网络爬虫性能的五个关键技巧:并发请求、异步执行、使用代理IP、限制请求频率与休眠时间、优化数据提取与存储。结合拼多多的实际案例,展示了如何通过这些技术优化爬虫效率,确保数据采集的高效性和稳定性。
146 0
|
1月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
1月前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
67 0
|
1月前
|
数据采集 JSON 网络协议
Python编程异步爬虫——aiohttp的使用
Python编程异步爬虫——aiohttp的使用