Python网络爬虫的同步和异步

一、同步与异步


《Python网络爬虫的同步和异步》

模板

《Python网络爬虫的同步和异步》

tips:

await表达式中的对象必须是awaitable

requests不支持非阻塞

aiohttp是用于异步请求的库

代码


《Python网络爬虫的同步和异步》

gevent简介

gevent是一个python的并发库,它为各种并发和网络相关的任务提供了整洁的API。

gevent中用到的主要模式是greenlet,它是以C扩展模块形式接入Python的轻量级协程。 greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

猴子补丁

requests库是阻塞式的,为了将requests同步更改为异步。只有将requests库阻塞式更改为非阻塞,异步操作才能实现。

而gevent库中的猴子补丁(monkey patch),gevent能够修改标准库里面大部分的阻塞式系统调用。这样在不改变原有代码的情况下,将应用的阻塞式方法,变成协程式的(异步)。

代码


《Python网络爬虫的同步和异步》

gevent:异步理论与实战

《Python网络爬虫的同步和异步》

gevent库中使用的最核心的是Greenlet-一种用C写的轻量级python模块。在任意时间,系统只能允许一个Greenlet处于运行状态

一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

串行和异步

高并发的核心是让一个大的任务分成一批子任务,并且子任务会被被系统高效率的调度,实现同步或者异步。在两个子任务之间切换,也就是经常说到的上下文切换。

同步就是让子任务串行,而异步有点影分身之术,但在任意时间点,真身只有一个,子任务并不是真正的并行,而是充分利用了碎片化的时间,让程序不要浪费在等待上。这就是异步,效率杠杆的。

gevent中的上下文切换是通过yield实现。在这个例子中,我们会有两个子任务,互相利用对方等待的时间做自己的事情。这里我们使用gevent.sleep(0)代表程序会在这里停0秒。

《Python网络爬虫的同步和异步》

运行的顺序:

《Python网络爬虫的同步和异步》

同步异步的顺序问题

同步运行就是串行,123456…,但是异步的顺序是随机的任意的(根据子任务消耗的时间而定)

代码


《Python网络爬虫的同步和异步》

输出

《Python网络爬虫的同步和异步》

同步案例中所有的任务都是按照顺序执行,这导致主程序是阻塞式的(阻塞会暂停主程序的执行)。

gevent.spawn会对传入的任务(子任务集合)进行进行调度,gevent.joinall方法会阻塞当前程序,除非所有的greenlet都执行完毕,程序才会结束。

实战

实现gevent到底怎么用,把异步访问得到的数据提取出来。

在有道词典搜索框输入“hello”按回车。观察数据请求情况 观察有道的url构建。

分析url规律

《Python网络爬虫的同步和异步》

解析网页数据


《Python网络爬虫的同步和异步》

因为requests库在任何时候只允许有一个访问结束完全结束后,才能进行下一次访问。无法通过正规途径拓展成异步,因此这里使用了monkey补丁

同步代码


《Python网络爬虫的同步和异步》

异步代码


《Python网络爬虫的同步和异步》

我们可以对待爬网站实时异步访问,速度会大大提高。我们现在是爬取12个词语的信息,也就是说一瞬间我们对网站访问了12次,这还没啥问题,假如爬10000+个词语,使用gevent的话,那几秒钟之内就给网站一股脑的发请求,说不定网站就把爬虫封了。

解决办法

将列表等分为若干个子列表,分批爬取。举例我们有一个数字列表(0-19),要均匀的等分为4份,也就是子列表有5个数。下面是我在stackoverflow查找到的列表等分方案:

方法1


《Python网络爬虫的同步和异步》

方法2


《Python网络爬虫的同步和异步》

方法3


《Python网络爬虫的同步和异步》

数据量不大的情况下,选哪一种方法都可以。如果特别大,建议使用方法3.

动手实现


《Python网络爬虫的同步和异步》

    原文作者:我爱学python
    原文地址: https://www.jianshu.com/p/12082955c52e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞