爬虫--高性能异步爬虫
目的:在爬虫中使用异步实现高性能的数据爬取操作
# 单线程下的串行数据爬取
1.阻塞式的爬虫
2.依次,单线程,效率低
import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome...' } urls = [ 'http:www.baidu.com/ceshi/aaa.rar', 'http:www.baidu.com/ceshi/bbb.rar', 'http:www.baidu.com/ceshi/bbb.rar', ] def get_content(url): print('正在爬取:',url) response = requests.get(url=url,headers=headers) if response.status_code == 200: return response.content def parse_content(content): print('响应数据的长度:',len(content)) for url in urls: content = get_content(url) parse_content(content)
异步爬虫的方式:
--多线程,多进程(不建议)
优点:为阻塞操作开启线程或者进程,阻塞操作异步执行
弊端:无法无限制的开启多线程或者多进程,需要频繁的创建和销毁进程和线程,过分耗费资源
--线程池,进程池(适当使用)
优点:可以降低进程和线程创建和销毁的频率,减少系统资源耗费
弊端:池中线程或进程数量是有上限的 进程process 线程thread
多进程池基础代码:
import requests from multiprocessing.dummy import Pool headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome...' } urls = [ 'https://xxxxxxx/page/1/', 'https://xxxxxxx/page/2/', 'https://xxxxxxx/page/3/', 'https://xxxxxxx/page/4/', ] pool = Pool(4) def get_content(url): print('正在爬取:', url) response = requests.get(url=url, headers=headers) if response.status_code == 200: return response.text def parse_content(content): print('响应数据的长度:', len(content)) def test(url): content = get_content(url) parse_content(content) pool.map(test,urls)
# 调用结束后关闭线程池,主线程等待子线程结束后再结束
poll.close()
poll.join()
线程池进程池使用基本原则: 进程线程池处理的是阻塞且耗时的操作
单线程+异步协程(推荐):
evnet_loop:事件循环,相当于一个无限循环,当把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行.
coroutine:协程对象,将协程对象注册到事件循环中,它会被事件循环调用;一般使用async关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象.
task:任务,它是对协程对象的进一步封装,包含了任务的各个状态
future:代表将来执行或还没有执行的任务,实际上和task没有本质区别
async:定义一个协程
await:用来挂起阻塞方法的执行
协程基础代码:
import asyncio async def request(url): print('正在请求的url是',url) print('请求成功,',url) # async修饰的函数,调用之后返回一个协程对象 cort = request('www.baidu.com') # 创建一个事件循环对象 loop = asyncio.get_event_loop() # 将协程对象注册到loop中,然后启动loop loop.run_until_complete(cort)
# task的使用
loop = asyncio.get_event_loop()
# 基于loop创建了一个task对象
task = loop.create_task(cort)
# 将task注册到loop中,然后启动loop
loop.run_until_complete(task) # future的使用,和task非常类似
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(cort)
loop.run_until_complete(future) # 需求:当事件循环对象执行结束后运行一个回调函数
# 回调绑定
def callback_func(future):
print(future.result())
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(cort)
# 将回调函数绑定到任务对象中
future.add_done_callback(callback_func)
loop.run_until_complete(future)
多任务异步协程基础代码:
import asyncio import time async def request(url): print('正在下载',url) # 在异步协程中如果出现了同步模块相关的代码,那么就无法实现异步,time模块就是同步模块 # time.sleep(2) # 当在asyncio中遇到阻塞操作必须进行手动挂起 await asyncio.sleep(2) # 异步模块中的时间 print('下载完毕',url) urls = [ 'www.baidu.com', 'www.sougou.com', 'www.163.com' ] # 任务列表:存放多个任务对象 tasks = [] for url in urls: c = request(url) task =asyncio.ensure_future(c) tasks.append(task) loop = asyncio.get_event_loop() # 需要将任务列表封装到wait中,列表的固定语法格式 # 多任务协程异步执行 loop.run_until_complete(asyncio.wait(tasks))
aiohttp模块:基于异步网络请求的模块
requests模块是基于同步网络请求的模块,而在异步协程中如果出现了同步模块相关的代码,那么就无法实现异步,time模块也是同步模块
因此,aiohttp模块就能够在异步工作中代替requests模块
import asyncio import aiohttp import time urls = [ 'https://www.baidu.com', 'https://www.sougou.com', 'https://www.163.com' ] async def get_page(url): async with aiohttp.ClientSession() as session: # get(),post(): # headers,params/data,proxy='http://ip:port',同步中是用的proxies # 任何会有阻塞的地方都要手动挂起await async with await session.get(url) as response: # text()返回字符串形式的响应数据 # read()返回的二进制形式的相应数据 # json()返回的就是json对象 page_text = await response.text() print(page_text) # 任务列表:存放多个任务对象 tasks = [] for url in urls: c = get_page(url) task =asyncio.ensure_future(c) tasks.append(task) loop = asyncio.get_event_loop() # 需要将任务列表封装到wait中,列表的固定语法格式 # 多任务协程异步执行 loop.run_until_complete(asyncio.wait(tasks))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通