感受python异步爬虫的强大(gevent、async、await)

948 阅读2分钟

网络爬虫,这种io高密集型的应用由于大部分的时间在等待响应方面,所以CPU的使用率一直不高,速度也不快,为了解决这些问题,我们使用异步的方式来进行爬虫程序。

串行的时候,如果我们要爬一个网站,那么我们通常都是一页的内容完成了,再到下一页,这样的话,CPU的90%以上的时间用在了等待网页响应上面。

异步的话,我们可以同时发起多个请求,一个请求发起了之后就不等待这个请求的响应,马上发起第二个请求,第三个请求...... 然后响应过来的内容我们再一个个进行处理,这样的效率就高了很多。

举个栗子: 首先我们搭建一个flask的服务器,故意降低它的响应速度:

from flask import Flask
import time

app = Flask(__name__)

@app.route('/')
def hello_world():
    # 休眠三秒,展示异步的速度
    time.sleep(3)
    return 'Hello World!'

if __name__ == '__main__':
    app.run(threaded=True)

首先我们使用python 3.5以上版本的async、await以及异步http请求库aiohttp:

import asyncio
import time
import aiohttp

start = time.time()

async def get(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as res:
            print(res.status)
            text = await res.text()
            return text

async def hello():
    url = "http://127.0.0.1:5000/"
    print('Waiting for',url)
    res = await get(url)
    print('Result:',res)

loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(hello()) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))

end = time.time()
print('Cost time:',end-start)

使用python的第三方库:gevent也可以实现网络异步(主要用于python2的版本):

from gevent import monkey
# 猴子补丁一定要先打,不然就会报错
monkey.patch_all()
import gevent
import requests
import time


def get(url):
    print("Get from: ",url)
    r = requests.session()
    res = r.get(url)
    print(res.status_code,url,res.text)

def synchronous_times(url):
    start = time.time()
    for i in range(5):
        get(url)
    end = time.time()
    print("同步执行的时间:", start-end)

def asynchronous_times(url):
    start = time.time()
    gevent.joinall([gevent.spawn(get,url) for i in range(5)])
    end = time.time()
    print("异步执行的时间:", start-end)

synchronous_times("http://127.0.0.1:5000/")
asynchronous_times("http://127.0.0.1:5000/")

以上就使用aiohttp、genvent实现了异步的网络请求。