asyncio的学习与应用
一直在制作完善pixiv的爬虫,最近遇到了一个问题,学校的网络环境太差了,导致了IO阻塞时间过长,常常出现线程长时间阻塞,占用了时间和内存。
为了解决这个问题,我决定尝试制定一个超时的图片删除重新爬取的过程,三次爬取不全则log报错不再爬取。
同时将整个脚本搬运至3.5版本,重新用asyncio异步编写,减少线程使用。
首先上一个asyncio的例子:
1 import asyncio
2
3 @asyncio.coroutine
4 def hello():
5 print("Hello world!")
6 # 异步调用asyncio.sleep(1):
7 r = yield from asyncio.sleep(1)
8 print("Hello again!")
9
10 # 获取EventLoop:
11 loop = asyncio.get_event_loop()
12 # 执行coroutine
13 loop.run_until_complete(hello())
14 loop.close()
@asyncio.coroutine
把一个generator标记为coroutine类型,然后把这个coroutine放入EventLoop中执行。
2017年更新
经过测试,协程的大数据IO使用协程爬取效率并没有想象的高,考虑到这一丢丢的进程不会达到吃电脑性能的程度,不再全面使用协程。这里仅记录下一些代码,一便下次查阅:
1 loop = asyncio.get_event_loop()
2 s = requests.session()
3 s.headers = headers1
4
5
6 def get(url, asession=s):
7 return loop.run_in_executor(None, asession.get, url)
8
9
10 def async_save(dataids, cookies, path):
11 s.cookies = requests.utils.cookiejar_from_dict(cookies)
12 tasks = []
13 for i in dataids:
14 tasks.append(simgle_async_save(i, path))
15 loop.run_until_complete(asyncio.wait(tasks))
16 loop.close()
17 return 0
18
19
20 async def simgle_async_save(i, path, ceiling=4):
21 b = 0
22 ·······
23 if not is_exists:
24 pic = await get(originaltu)
25 fp = open(path, 'wb')
26 fp.write(pic.content)
27 fp.close() # 保存图片
28 '''print(i+'-'+str(b) + ' download is Success')'''
4 December 2016