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

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

爬虫

前言

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

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


一、多线程爬虫:

对于大量数据要多次发送请求可以利用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文件中,所以在下载的时候也可以多任务异步协程同时下载。

相关文章
|
9月前
|
数据采集 存储 JSON
Python爬取知乎评论:多线程与异步爬虫的性能优化
Python爬取知乎评论:多线程与异步爬虫的性能优化
|
9月前
|
数据采集 存储 C++
Python异步爬虫(aiohttp)加速微信公众号图片下载
Python异步爬虫(aiohttp)加速微信公众号图片下载
|
6月前
|
数据采集 人工智能 JSON
Prompt 工程实战:如何让 AI 生成高质量的 aiohttp 异步爬虫代码
Prompt 工程实战:如何让 AI 生成高质量的 aiohttp 异步爬虫代码
|
7月前
|
数据采集 网络协议 API
协程+连接池:高并发Python爬虫的底层优化逻辑
协程+连接池:高并发Python爬虫的底层优化逻辑
|
8月前
|
数据采集 机器学习/深度学习 监控
代理IP并发控制:多线程爬虫的加速引擎
在数据采集领域,多线程爬虫结合代理IP并发控制技术,有效突破反爬机制。通过动态代理池与智能并发策略,显著提升采集效率并降低封禁率,成为高效数据抓取的关键方案。
290 0
|
9月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
9月前
|
数据采集 存储 Java
多线程Python爬虫:加速大规模学术文献采集
多线程Python爬虫:加速大规模学术文献采集
|
10月前
|
数据采集 网络协议 前端开发
Python多线程爬虫模板:从原理到实战的完整指南
多线程爬虫通过并发请求大幅提升数据采集效率,适用于大规模网页抓取。本文详解其原理与实现,涵盖任务队列、线程池、会话保持、异常处理、反爬对抗等核心技术,并提供可扩展的Python模板代码,助力高效稳定的数据采集实践。
534 0
|
9月前
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
427 83
|
6月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
279 6