更多课程 选择中心


Python培训

400-996-5531

Python异步爬虫详解

  • 发布:大邓
  • 来源:大邓带你玩python
  • 时间:2017-11-30 14:48

一、同步与异步

异步编程可以大幅度的提高系统的吞吐量,提高单位时间内发出的请求数目。之前大邓写的爬虫都是同步,就是对aurl发起请求,等待响应。然后再访问burl,等待响应。。。

大量的时间消耗在等待上,如果能近似的同时对多个网址发起请求,等待响应,速度回快很多倍。这里的同时其实是为了让大家便于理解,其实所谓的同时也是有先后顺序的,所以叫异步。

文字描述太别扭,我们水平方向代表时间

#同步编程(同一时间只能做一件事,做完了才能做下一件事情)<-a_url-><-b_url-><-c_url->#异步编程 (可以近似的理解成同一时间有多个事情在做,但有先后)<-a_url->

<-b_url->

<-c_url->

<-d_url->

<-e_url->

<-f_url->

<-g_url->

<-h_url->

<--i_url-->

<--j_url-->

你看同步编程同样的时间访问了3个网址,但是异步编程访问的效率提高了很多倍。

二、async&await

在python3.5之后,开始引入async和await语法结构,通过async关键词定义一个协程(不用管啥名字,总之就理解成异步吧)。其实我也有很多地方不熟悉,没关系,先会用,孰而知之。

2.1 并不成功的套路

网上看了些教程,总结出来大概是以下的模板:

import asyncio#函数名:做现在的任务时不等待,能继续做别的任务。async def donow_meantime_dontwait(url):

response = await requests.get(url)#函数名:快速高效的做任务async def fast_do_your_thing():

await asyncio.wait([donow_meantime_dontwait(url) for url in urls])

#下面两行都是套路,记住就好loop = asyncio.get_event_loop()loop.run_until_complete(fast_do_your_thing())

将模板改造,开始实验

import asyncioimport requestsimport time

urls = ['#/tag/小说','#/tag/科幻',

'#/tag/漫画','#/tag/奇幻',

'#/tag/历史','#/tag/经济学']async def requests_meantime_dont_wait(url):

print(url)

response = await requests.get(url)

print("{url} 得到响应".format(url=url))async def fast_requsts():

start = time.time()

await asyncio.wait([requests_meantime_dont_wait(url) for url in urls])

end = time.time()

print("耗时 {} 秒".format(end - start))loop = asyncio.get_event_loop()loop.run_until_complete(fast_requsts())

正以为成功了,出现bug。requests库返回的响应对象不能使用await关键词。

TypeError: object Response can't be used in 'await' expression

百度一下,await表达式中的对象必须是awaitable。

PEP 492 -- Coroutines with async and await syntax #/dev/peps/pep-0492/

awaitable对象

A native coroutine object returned from a native coroutine function

A generator-based coroutine object returned from a function decorated with types.coroutine() .

An object with an await method returning an iterator.

又百度了下,说是封装下就可变成原生异步函数。不懂啥意思,还是copy代码直接运行试试吧。

import asyncioimport requestsimport time

urls = ['#/tag/小说','#/tag/科幻',

'#/tag/漫画','#/tag/奇幻',

'#/tag/历史','#/tag/经济学']async def requests_meantime_dont_wait(url):

"""注意这里没有await关键词"""

resp = requests.get(url)

print(resp.status_code)

async def package_requests(url):

"""将requests_meantime_dont_wait封装成awaitbale。"""

print(url)

await requests_meantime_dont_wait(url)

print("{url} 得到响应".format(url=url))async def fast_requsts(urls):

start = time.time()

await asyncio.wait([package_requests(url) for url in urls])

end = time.time()

print("Complete in {} seconds".format(end - start))loop = asyncio.get_event_loop()loop.run_until_complete(fast_requsts(urls))loop.close()

#/tag/经济学200#/tag/经济学 得到响应

#/tag/奇幻200#/tag/奇幻 得到响应

#/tag/历史200#/tag/历史 得到响应

#/tag/漫画200#/tag/漫画 得到响应

#/tag/小说200#/tag/小说 得到响应

#/tag/科幻200#/tag/科幻 得到响应Complete in 3.8158602714538574 seconds

代码正常运行,可是打印出来的东西不对啊。应该是几个网址在一起,然后是200状态吗在一起才对的。这应该不是异步,后来去掉异步的这些关键词单独运行,运行效率没有啥大区别。

2.2 终于找到正确的套路

继续百度,奥,requests不支持非阻塞。即使使用异步编程,requests库还是按照同步那样访问完aurl,得到响应后才再访问burl。。。。

坑爹啊,继续百度发现aiohttp,用于异步请求的库。还是不懂,陆陆续续,经过数小时的百度,copy,试运行,终于成品出来了。

import asyncioimport requestsimport timeimport aiohttp#urls = ['#/tag/小说','#/tag/科幻',

#'#/tag/漫画','#/tag/奇幻',

#'#/tag/历史','#/tag/经济学']urls = ['#/p/b59453dd38cf','#/','#/pathlib-intro.html']async def requests_meantime_dont_wait(url):

print(url)

async with aiohttp.ClientSession() as session:

async with session.get(url) as resp:

print(resp.status)

print("{url} 得到响应".format(url=url))async def fast_requsts(urls):

start = time.time()

await asyncio.wait([requests_meantime_dont_wait(url) for url in urls])

end = time.time()

print("Complete in {} seconds".format(end - start))loop = asyncio.get_event_loop()loop.run_until_complete(fast_requsts(urls))loop.close()

由于我的行径对豆瓣太恶劣了,访问次数过多。出现一些异常,在写文字时随便抽取了三个网址作为测试用的网址。结果很符合预期,实现了异步,先对多个网址发起请求,慢慢的等待结果的到来。

#/p/b59453dd38cf

#/pathlib-intro.html

#/

200

#/ 得到响应

200

#/p/b59453dd38cf 得到响应

200

#/pathlib-intro.html 得到响应

Complete in 1.152311086654663 seconds

本文内容转载自网络,本着分享与传播的原则,版权归原作者所有,如有侵权请联系我们进行删除!

预约申请免费试听课

填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:Python中定义字符串知识点讲解
下一篇:Python简介和开发环境构建教程

2021年Python全套免费视频教程在哪里?

Python编程学习路线

Python最高有几级?

人工智能与语音遥控的区别?

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省