Python记录-异步爬虫1

196 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情 朱颜渐老,白发知多少.

又到了每天学习写文章的时候了,又搬出来崔老师的爬虫书,继续学习 要实现异步机制的爬虫,那自然和协成脱不了关系

协成的基本原理

1.引入 话说啊,有这么一个网站,我是网站 这个网站等待五秒才有结果,这是因为啊,服务器强制等了五秒才返回响应,如果我们发送一个请求,都要经过五秒或者更长时间时才能得到相应的响应时,我们的爬虫的效率就会非常低. 举个例子

import requests
import  logging
import time

logging.basicConfig(level=logging.INFO,format='%(levelname)s:%(message)s')

total_number = 10
url = "https://www.httpbin.org/delay/5"
start_time = time.time()

for  i in  range(1,total_number):
    logging.info('scraping %s',url)
    response = requests.get(url)

end_time = time.time()

logging.info("total time %s",end_time - start_time)

得到的结果 如图所示

image.png 每个请求都等了5秒 仅仅十个请求就花了63秒

所以我们需要更好的解决方案.

协程实现

使用Python 3.4 以后才加入的功能 协程和 async关键字 3.5以上async已成为关键字

import asyncio
import requests
import time

start = time.time()

async def requeset():
    url = "https://www.httpbin.org/delay/5"
    print("wait for",url)
    response = requests.get(url)
    print('get response from',url,'response',response)

task = [asyncio.ensure_future(requeset()) for i in range(10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))

end = time.time()
print("total time %s",end - start)

来查看结果

image.png 好家伙,68秒了,代码写的猛如虎,一看自己原地杵

其实我们上面的代码依然是顺序执行了,并不是异步的,所以才会出现这种情况. 我们需要 了解一下 await 将协程挂起 await用来声明程序挂起。

比如异步程序执行到某一步时需要等待的时间很长,就将此挂起,去执行其他的异步程序。

await 后面只能跟异步程序或有__await__属性的对象,因为异步程序与一般程序不同。 aiohttp是一个为Python提供异步HTTP 客户端/服务端编程,asyncio可以实现单线程并发IO操作,其实现了TCP、UDP、SSL等协议,aiohttp就是基于asyncio实现的http框架。

import asyncio
import requests
import time
import aiohttp

start = time.time()


async def get(url):
    session = aiohttp.ClientSession()
    response = await session.get(url)
    await response.text()
    await session.close()
    return response


async def requeset():
    url = "http://www.httpbin.org/delay/5"
    print("wait for", url)
    response = await get(url)
    print('get response from', url, 'response', response)


task = [asyncio.ensure_future(requeset()) for i in range(10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))

end = time.time()
print("total time %s", end - start)

得到结果

image.png

只有6秒了,很好我们完成了我们的期望