Python 多协程爬虫

多协程爬虫

除了多线程多进程外,Python的网络爬虫还可以使用协程(Coroutine)
协程是种用户态的轻量级线程,使用协程有众多好处:
(1)第一个好处是协程像种在程序级别模拟系统级别的进程,由于是单线程,并且少了上下文切换,因此相对来说系统消耗很少,而且网上的各种测试也表明协程确实拥有惊人的速度。
(2)第二个好处是协程方便切换控制流,这就简化了编程模型。协程能保留上一次调用时的状态(所有局部状态的一个特定组合),每次过程重入时,就相当于进入了上一次调用的状态。
(3)第三个好处是协程的高扩展性和高并发性,一个CPU支持(上万协程都不是问题,所以很适合用于高并发处理。
(4)协程也有缺点。第一,协程的本质是一个单线程,不能同时使用单个CPU的多核,需要和进程配合才能运行在多CPU上。第二,有长时间阻塞的IO操作时不要用协程,因为可能会阻塞整个程序。
在Python的协程中可以使用gevent库。gevent库也可以使用pip安装。
pip install gevnet

爬虫代码如下:

import gevent
from gevent.queue import Queue, Empty
import time
import requests

from gevent import monkey #把下面有可能有IO操作的单独做上标记
monkey.patch_all() #将IO转为异步执行的函数

link_list = []
with open('alexa.txt', 'r') as file:
    file_list = file.readlines()
    for eachone in file_list:
        link = eachone.split('\t')[1]
        link = link.replace('\n','')
        link_list.append(link)
        
start = time.time()
def crawler(index):
    Process_id = 'Process-' + str(index)
    while not workQueue.empty():
        url = workQueue.get(timeout=2)
        try:
            r = requests.get(url, timeout=20)
            print(Process_id, workQueue.qsize(), r.status_code, url)
        except Exception as e:
            print(Process_id, workQueue.qsize(), url, 'Error: ', e)

def boss():
    for url in link_list:
        workQueue.put_nowait(url)
        
if __name__ == '__main__':
    workQueue = Queue(1000)
    
    gevent.spawn(boss).join()
    jobs = []
    for i in range(10):
        jobs.append(gevent.spawn(crawler, i))
    gevent.joinall(jobs)
    
    end = time.time()
    print('gevent + Queue多协程爬虫的总时间为:', end-start)
    print('Main Ended')

在上述代码中,我们使用了:

from gevent import monkey #把下面有可能有IO操作的单独做上标记
monkey.patch_all() #将IO转为异步执行的函数

这样可以实现爬虫的并发能力,如果没有这两句,整个抓取过程就会变成依次抓取。gevent库中的monkey能把可能有IO的操作的单独做上标记,将IO变成可以异步执行的函数。

你可能感兴趣的:(网络爬虫)