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