让我们来详细讲解一下“Python利用yield from实现异步协程爬虫”的完整攻略。
什么是异步协程
在介绍异步协程之前,先了解一下同步、异步、阻塞和非阻塞的概念。
同步指的是调用一个函数时需要等待其执行结束后才能执行下一步操作;
异步指的是调用一个函数时不需要等待其执行结束,会继续执行下一步操作,但是需要一个通知机制告诉调用者何时执行结束;
阻塞指的是调用一个函数时需要一直等待其执行结束;
非阻塞指的是调用一个函数时不需要等待其执行结束,可以继续执行下一步操作。
协程指的是一种比线程更轻量级的并发方式,协程之间的切换不需要操作系统帮助,切换开销较小。异步协程指的是使用协程来实现异步编程。
Python异步编程的发展
Python异步编程的发展经历了以下几个阶段:
-
Callback回调函数:最早的异步编程方式是使用回调函数,但是嵌套过多导致代码难以维护。
-
Promise承诺:Promise是一种解决回调嵌套的方案,但是写法繁琐。
-
async/await关键字:async/await是Python 3.5引入的关键字,可以简化异步编程的写法,但是只能在协程函数中使用。
-
yield from语法:yield from在Python 3.3引入,可以实现协程并能处理异步编程,是目前Python异步编程的主流方式。
yield from实现异步协程爬虫的步骤
下面介绍yield from实现异步协程爬虫的步骤:
- 创建异步任务
使用asyncio模块的异步函数来定义需要执行的异步任务,使用async with实现异步上下文管理器,保证异步关闭。
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://www.example.com')
print(html)
- 创建事件循环
在主函数中创建事件循环,使用run_until_complete方法启动异步任务。
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://www.example.com')
print(html)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
运行上述代码,会输出https://www.example.com的HTML源码。
- 实现多任务异步爬虫
我们可以使用列表存储多个URL,然后遍历这个列表,每次获取一个URL的HTML源码。
async def main():
async with aiohttp.ClientSession() as session:
urls = [
'https://www.example.com',
'https://www.baidu.com',
'https://www.google.com',
]
tasks = [fetch(session, url) for url in urls]
htmls = await asyncio.gather(*tasks)
for html in htmls:
print(len(html))
运行上述代码,会输出三个URL的HTML源码的长度。这里使用了asyncio.gather()方法可以并发执行多个协程任务,同时也等待所有协程任务执行完毕后返回其结果的列表。
示例
下面给出一个完整的示例代码,可以爬取豆瓣Top 250电影的名称和评分信息。
import aiohttp
import asyncio
import re
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def parse(html):
pattern = re.compile('<span class="title">([\u4e00-\u9fa5]+)</span>.*?<span class="rating_num" property="v:average">([0-9].[0-9])<')
items = re.findall(pattern, html)
return items
async def main():
async with aiohttp.ClientSession() as session:
urls = []
for i in range(0, 250, 25):
url = f'https://movie.douban.com/top250?start={i}'
urls.append(url)
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
items = []
for html in results:
item = await parse(html)
items.extend(item)
for item in items:
print(item)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
运行这段代码,可以爬取豆瓣Top 250电影的名称和评分信息。
总结
Python利用yield from实现异步协程爬虫是目前Python异步编程的主流方式,其对于网络I/O密集型任务非常高效。在实际应用中,我们需要根据业务逻辑来合理分配和利用协程,以提高代码的可读性和性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python利用yield form实现异步协程爬虫 - Python技术站