初始異步爬蟲

以前出於興趣寫了個爬蟲專門爬取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異步

相關文章
相關標籤/搜索