初始异步爬虫

以前出于兴趣写了个爬虫专门爬取Wallpaper Abyss上的图片,写完以后发现有点慢,仔细查看发现时间大多数都花费在了http请求上了。最近异步编程也是热门,不少语言也都有这个特性,打算使用异步请求的方法改写以前的爬虫,正好也学习学习。php

同步的请求

网络爬虫,无非就是使用代码来模拟人的操做,发起http请求,获取网页源码,根据规律找到本身想要的东西。
在这里使用requests库来发起请求,使用BeautifulSoup来解析html,爬取这页的图片为例子:
image.pnghtml

发送请求获取网页源代码,提取出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

参考连接:
协程与任务api
理解 JavaScript 的 async/await异步

相关文章
相关标签/搜索