使用aiohttp 抓取起点小说网
主要是为了学习异步协程抓取库,包括asyncio, aiohttp,等库的用法,顺便学习。感受一下并发的速度。
所以代码也不是很难,都是直接找到小说目录接口,找到目录之后抓取正本小说。
基础概念:
event_loop 事件循环:理解为一个循环的池,里面存放一些async关键词定义的协程函数,只有放到循环池里才能执行
coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。
future:代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
async/await 关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口
协程的启动:(多协程并发)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))
loop.run_until_complete(asyncio.wait(*tasks))
gather和wait的区别在于,gather根据任务列表的顺序依次输出而wait则是乱序的。
停止协程任务
实现结束task有两种方式:关闭单个task、关闭loop,涉及主要函数:
asyncio.Task.all_tasks()获取事件循环任务列表
KeyboardInterrupt捕获停止异常(Ctrl+C)
loop.stop()停止任务循环
task.cancel()取消单个任务
loop.run_forever()
loop.close()关闭事件循环,不然会重启
重启
关于对异步生成器进行切片
使用异步并发的时候,很容易任务task中的数量过多,
当并发超多2000的时候就会报错
ValueError: too many file descriptors in select()
报错的原因字面上看是 Python 调取的 select 对打开的文件有最大数量的限制,这个其实是操作系统的限制,linux打开文件的最大数默认是1024,windows默认是509,超过了这个值,程序就开始报错
这里我们有三种方法解决这个问题:
1.限制并发数量。(一次不要塞那么多任务,或者限制最大并发数量)
2.使用回调的方式。
3.修改操作系统打开文件数的最大限制,在系统里有个配置文件可以修改默认值,具体步骤不再说明了。
限制并发数量
不修改系统默认配置的话,个人推荐限制并发数的方法,设置并发数为500,处理速度更快。
#coding:utf-8
import time,asyncio,aiohttp
url = 'https://www.baidu.com/'
async def hello(url,semaphore):
async with semaphore:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.read()
async def run():
semaphore = asyncio.Semaphore(500) # 限制并发量为500
to_get = [hello(url.format(),semaphore) for _ in range(1000)] #总共1000任务
await asyncio.wait(to_get)
if __name__ == '__main__':
# now=lambda :time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
对异步生成器进行切片
async def branch(self, coros, limit=10):
'''
使用aiostream模块对异步生成器做一个切片操作。这里并发量为10.
:param coros: 异步生成器
:param limit: 并发次数
:return:
'''
index = 0
while True:
xs = stream.preserve(coros)
ys = xs[index:index + limit]
t = await stream.list(ys)
if not t:
break
await asyncio.ensure_future(asyncio.gather(*t))
index += limit + 1
具体使用
抓取起点小说网:
这里就是写点碰到的错误吧
第一个错误
推荐陈佬的博客:https://www.cnblogs.com/c-x-a/p/10208179.html
这个问题具体的解决就是去掉for前面的async
第二个错误
应该是超时了。设置的超时为5秒。
解决就是异常,超过5秒就跳过。
最后一个错误
这个错误我手写。使用协程并发的时候,使用gather它的顺序是正常的,但是写入的文件里是乱序的。
按理说写入也是顺序的,所以这个错误现在还有点没太明白。希望大家能指点一下。
最后通过使用队列+协程。将每次抓取的内容保存到字典中。
最后对字典进行处理。这样抓取的数据就是有顺序的。
关于在协程中使用队列:
https://www.cnblogs.com/c-x-a/p/10668977.html
微信公众号,欢迎扫码关注: