使用aiohttp 抓取起点小说网

使用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

微信公众号,欢迎扫码关注:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

裸睡的雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值