从一个爬虫说起
Python 2 的时代使用生成器协程,Python 3.7 提供了新的基于 asyncio 和 async / await 的方法。先看一个简单的爬虫代码,爬虫的 scrawl_page 函数为休眠数秒,休眠时间取决于 url 最后的那个数字。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import timedef crawl_page(url):print('crawling {}'.format(url))sleep_time = int(url.split('_')[-1])time.sleep(sleep_time)print('OK {}'.format(url))def main(urls):for url in urls:crawl_page(url)%time main(['url_1', 'url_2', 'url_3', 'url_4'])######### 输出 ##########crawling url_1
OK url_1
crawling url_2
OK url_2
crawling url_3
OK url_3
crawling url_4
OK url_4
Wall time: 10 s
由于是同步执行,因此用了10秒。
试着用协程实现:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import asyncio
import nest_asyncio
nest_asyncio.apply()async def crawl_page(url):print('crawling {}'.format(url))sleep_time = int(url.split('_')[-1])await asyncio.sleep(sleep_time)print('OK {}'.format(url))async def main(urls):for url in urls:await crawl_page(url)%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))########## 输出 ##########crawling url_1
OK url_1
crawling url_2
OK url_2
crawling url_3
OK url_3
crawling url_4
OK url_4
Wall time: 10 s
首先来看 import asyncio,这个库包含了大部分我们实现协程所需的魔法工具。async 修饰词声明异步函数,于是,这里的 crawl_page 和 main 都变成了异步函数。可以通过 await 来调用异步函数。await 执行的效果和 Python 正常执行是一样的,也就是说程序会阻塞在这里,进入被调用的协程函数,执行完毕返回后再继续,而这也是 await 的字面意思。代码中 await asyncio.sleep(sleep_time) 会在这里休息若干秒,await crawl_page(url) 则会执行 crawl_page() 函数。
上面的代码仍然是同步执行的,所以同样是用了10秒。
如果要异步执行,可以用Task任务的概念。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import asyncio
import nest_asyncio
nest_asyncio.apply()async def crawl_page(url):
print('crawling {}'.format(url))
sleep_time = int(url.split('_')[-1])
await asyncio.sleep(sleep_time)
print('OK {}'.format(url))async def main(urls):
tasks = [ate_task(crawl_page(url)) for url in urls]
for task in tasks:
await task%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))######### 输出 ##########crawling url_1
crawling url_2
crawling url_3
crawling url_4
OK url_1
OK url_2
OK url_3
OK url_4
Wall time: 4.01 s
在create_task创建任务后,任务就会马上由事件循环调度执行。如果不调用await task,代码就不会阻塞。我们想要等所有任务结束再往下走,因此用for task in tasks: await task。现在时间就4秒左右,可以用await asyncio.gather(*tasks)来代替for task in tasks: await task。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import asyncio
import nest_asyncio
nest_asyncio.apply()
import timeasync def crawl_page(url):print('crawling {}'.format(url))sleep_time = int(url.split('_')[-1])#await asyncio.sleep(sleep_time)await asyncio.sleep(sleep_time)print('OK {}'.format(url))async def main(urls):tasks = [ate_task(crawl_page(url)) for url in urls ]await asyncio.gather(*tasks)%time asyncio.run(main(['url_1', 'url_2', 'url_3', 'url_4']))
协程运行时出现错误,要怎么处理?
看代码:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import asyncio
import nest_asyncio
nest_asyncio.apply()async def worker_1():await asyncio.sleep(1)return 1async def worker_2():await asyncio.sleep(2)return 2 / 0async def worker_3():await asyncio.sleep(3)print('over worker_3')return 3async def main():task_1 = ate_task(worker_1())task_2 = ate_task(worker_2())task_3 = ate_task(worker_3())await asyncio.sleep(2)task_3.cancel()res = await asyncio.gather(task_1, task_2, task_3, return_exceptions=True)print(res)%time asyncio.run(main())########## 输出 ########### [1, ZeroDivisionError('division by zero'), CancelledError()]
# Wall time: 2 s
注意return_exceptions参数,上面代码在执worker_2会抛出除0的异常,而worker_2中没有做try…catch捕捉错误,本应该会程序会停止,由于设置了return_exceptions=True,所以没有影响到其他任务的执行。而 CancelledError()表示task_3被cancel()取消掉.
协程实现消费者生产者模型
show the code:
import asyncio
import randomasync def consumer(queue, id):while True:val = ()print('{} get a val: {}'.format(id, val))await asyncio.sleep(1)async def producer(queue, id):for i in range(5):val = random.randint(1, 10)await queue.put(val)print('{} put a val: {}'.format(id, val))await asyncio.sleep(2)async def main():queue = asyncio.Queue()consumer_1 = ate_task(consumer(queue, 'consumer_1'))consumer_2 = ate_task(consumer(queue, 'consumer_2'))producer_1 = ate_task(producer(queue, 'producer_1'))producer_2 = ate_task(producer(queue, 'producer_2'))await asyncio.sleep(10)consumer_1.cancel()consumer_2.cancel()await asyncio.gather(consumer_1, consumer_2, producer_1, producer_2, return_exceptions=True)%time asyncio.run(main())########## 输出 ########### producer_1 put a val: 5
# producer_2 put a val: 3
# consumer_1 get a val: 5
# consumer_2 get a val: 3
# producer_1 put a val: 1
# producer_2 put a val: 3
# consumer_2 get a val: 1
# consumer_1 get a val: 3
# producer_1 put a val: 6
# producer_2 put a val: 10
# consumer_1 get a val: 6
# consumer_2 get a val: 10
# producer_1 put a val: 4
# producer_2 put a val: 5
# consumer_2 get a val: 4
# consumer_1 get a val: 5
# producer_1 put a val: 2
# producer_2 put a val: 8
# consumer_1 get a val: 2
# consumer_2 get a val: 8
# Wall time: 10 s
实战:豆瓣近日推荐电影爬虫
同步版本
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,
互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import requests
from bs4 import BeautifulSoupdef main():url = "/"init_page = (url).contentinit_soup = BeautifulSoup(init_page, 'lxml')all_movies = init_soup.find('div', id="showing-soon")for each_movie in all_movies.find_all('div', class_="item"):all_a_tag = each_movie.find_all('a')all_li_tag = each_movie.find_all('li')movie_name = all_a_tag[1].texturl_to_fetch = all_a_tag[1]['href']movie_date = all_li_tag[0].textresponse_item = (url_to_fetch).contentsoup_item = BeautifulSoup(response_item, 'lxml')img_tag = soup_item.find('img')print('{} {} {}'.format(movie_name, movie_date, img_tag['src']))%time main()########## 输出 ##########
九龙不败 07月02日 .jpg
善良的天使 07月02日 .jpg
别岁 07月02日 .jpg
上海的女儿 07月02日 .jpg
爱宠大机密2 07月05日 .jpg
扫毒2天地对决 07月05日 .jpg
猪猪侠·不可思议的世界 07月05日 .jpg
他她他她 07月05日 .jpg
狮子王 07月12日 .jpg
命运之夜——天之杯II :迷失之蝶 07月12日 .jpg
宝莱坞机器人2.0:重生归来 07月12日 .jpg
素人特工 07月12日 .jpg
机动战士高达NT 07月12日 .jpg
舞动吧!少年 07月12日 .jpg
嘿,蠢贼 07月16日 .jpg
银河补习班 07月18日 .jpg
小小的愿望 07月18日 .jpg
匠心 07月18日 .jpg
猪八戒·传说 07月19日 .jpg
刀背藏身 07月19日 .jpg
为家而战 07月19日 .jpg
Wall time: 22.1 s
异步版本
import asyncio
import aiohttpfrom bs4 import BeautifulSoupasync def fetch_content(url):async with aiohttp.ClientSession(headers=header, connector=aiohttp.TCPConnector(ssl=False)) as session:async (url) as response:return ()async def main():url = "/"init_page = await fetch_content(url)init_soup = BeautifulSoup(init_page, 'lxml')movie_names, urls_to_fetch, movie_dates = [], [], []all_movies = init_soup.find('div', id="showing-soon")for each_movie in all_movies.find_all('div', class_="item"):all_a_tag = each_movie.find_all('a')all_li_tag = each_movie.find_all('li')movie_names.append(all_a_tag[1].text)urls_to_fetch.append(all_a_tag[1]['href'])movie_dates.append(all_li_tag[0].text)tasks = [fetch_content(url) for url in urls_to_fetch]pages = await asyncio.gather(*tasks)for movie_name, movie_date, page in zip(movie_names, movie_dates, pages):soup_item = BeautifulSoup(page, 'lxml')img_tag = soup_item.find('img')print('{} {} {}'.format(movie_name, movie_date, img_tag['src']))%time asyncio.run(main())########## 输出 ##########九龙不败 07月02日 .jpg
善良的天使 07月02日 .jpg
别岁 07月02日 .jpg
上海的女儿 07月02日 .jpg
爱宠大机密2 07月05日 .jpg
扫毒2天地对决 07月05日 .jpg
猪猪侠·不可思议的世界 07月05日 .jpg
他她他她 07月05日 .jpg
狮子王 07月12日 .jpg
命运之夜——天之杯II :迷失之蝶 07月12日 .jpg
宝莱坞机器人2.0:重生归来 07月12日 .jpg
素人特工 07月12日 .jpg
机动战士高达NT 07月12日 .jpg
舞动吧!少年 07月12日 .jpg
嘿,蠢贼 07月16日 .jpg
银河补习班 07月18日 .jpg
小小的愿望 07月18日 .jpg
匠心 07月18日 .jpg
猪八戒·传说 07月19日 .jpg
刀背藏身 07月19日 .jpg
为家而战 07月19日 .jpg
Wall time: 5.82 s
本文发布于:2024-01-31 13:51:16,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170668027828981.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |