以前出于兴趣写了个爬虫专门爬取Wallpaper Abyss上的图片,写完以后发现有点慢,仔细查看发现时间大多数都花费在了http请求上了。最近异步编程也是热门,不少语言也都有这个特性,打算使用异步请求的方法改写以前的爬虫,正好也学习学习。php
网络爬虫,无非就是使用代码来模拟人的操做,发起http请求,获取网页源码,根据规律找到本身想要的东西。
在这里使用requests库来发起请求,使用BeautifulSoup来解析html,爬取这页的图片为例子:html
发送请求获取网页源代码,提取出img标签的src属性,也就是图片的连接,根据图片的连接发送请求获取图片数据,保存到本地中便可。python
# 解析某一页并下载 def parse_one_page_wall_papers(): # 获取入口 url = 'https://wall.alphacoders.com/by_sub_category.php?id=172910&name=Aria+Wallpapers' session.mount(url, adapter) response = session.get(url, headers=headers, timeout=30) soup = BeautifulSoup(response.content, 'html.parser') # 解析 thumbs = soup.find_all('div', {'class':'thumb-container'}) # 获取div(图片所在地) for index, thumb in enumerate(thumbs): save_pic(urljoin(url, thumb.a.get('href'))) def save_pic(a_url): session.mount(a_url, adapter) ori_img_res = session.get(a_url, headers=headers, timeout=20) # 保存并下载 .......
能够看到,在这里下载图片时,他都是顺序执行的。也就是只有当第一张图片请求完成后,才能进行第二张图片的请求。
本身测试了一下,下载60张图片花费了206秒,虽然方便了操做,可是速度实在太慢。编程
将时间花费在等待io上显然是不划算的,在第一个请求未到达以前,咱们应该接着发送第二个、第三个请求,就比如在与qq好友聊天时,发送消息后没必要一直等着好友的回复,而去找下一个好友聊天,等到好友消息回复后再接着聊天,显然是一个道理。segmentfault
改用aiohttp发起请求,将save_pic方法改写成异步的方法:api
async def save_pic(a_url): async with session.get(img.get('src'), headers=headers) as resp: # 保存并下载 # 以byte形式将图片数据写入 # 建立二级文件目录 # 若是文件存在 则写入存在文件 with open(folder_path, 'wb') as file: file.write(await resp.read()) file.flush() file.close() # 关闭文件 .......
注意到await关键字,await以后表明的就是堵塞操做,当遇到await时,方法就放弃执行,直到await以后的操做结束再返回执行await以后的代码。如此一来,在发起请求以后,请求未结束以前,save_pic方法便放弃执行,此时即可以再执行save_pic获取下一张图片。网络
async def parse_one_page_wall_papers(): # 获取入口 url = 'https://wall.alphacoders.com/by_sub_category.php?id=172910&name=Aria+Wallpapers' session.mount(url, adapter) response = session.get(url, headers=headers, timeout=30) soup = BeautifulSoup(response.content, 'html.parser') # 解析 thumbs = soup.find_all('div', {'class':'thumb-container'}) # 获取div(图片所在地) get_origin_url_fn = [] for index, thumb in enumerate(thumbs): get_origin_url_fn.append( save_pic(urljoin(url, thumb.a.get('href')))) await asyncio.gather(*get_origin_url_fn)
在这里使用asyncio.gather将全部的异步方法设为一个一个异步方法,也就说当全部的图片都下载完毕后,parse_one_page_wall_papers方法才会结束等待。session
在使用了异步以后,下载60张图片仅仅花费了25秒,相比于同步的206秒速度提高了8倍,不禁得让我深深感叹异步的强大。app