在進行網頁爬取時,網頁的響應速度慢於計算機的處理速度,在串行模式下訪問多個網頁,在通過網絡獲取一個網頁的過程中,在這個過程之前,計算機只能閒置等待。而異步的方式就是讓計算機可以在這個閒置時間先去做後面的工作,等這個網頁響應完成再對它進行處理。
這裏說的這種異步的方式是一種分時獲得時間片的機制,有些像多線程,不同於多進程,私以爲比較適合爬蟲這種IO密集型操作。
-
異步編程包——asyncio
這裏直接通過代碼來說明它的語法
async def job(t): # async 形式的功能 print('Start job ', t) await asyncio.sleep(t) # 等待 "t" 秒, 期間切換其他任務 print('Job ', t, ' takes ', t, ' s') async def main(loop): # async 形式的功能 tasks = [ loop.create_task(job(t)) for t in range(1, 3) ] # 創建任務, 但是不執行 await asyncio.wait(tasks) # 執行並等待所有任務完成 t1 = time.time() loop = asyncio.get_event_loop() # 建立 loop loop.run_until_complete(main(loop)) # 執行 loop loop.close() # 關閉 loop print("Async total time : ", time.time() - t1) # Start job 1 # Start job 2 # Job 1 takes 1 s # Job 2 takes 2 s # Async total time : 2.0259742736816406
再做個非異步串行的對比操作
def job(t): print('Start job ', t) time.sleep(t) # wait for "t" seconds print('Job ', t, ' takes ', t, ' s') def main(): [job(t) for t in range(1, 3)] t1 = time.time() main() print("NO async total time : ", time.time() - t1) # Start job 1 # Job 1 takes 1 s # Start job 2 # Job 2 takes 2 s # NO async total time : 3.001530647277832
(注意rang(1,3)的結果是隻有1,2兩個值)
可以看到異步方式的執行總時間是多個任務的最大時間,而非異步方式的執行總時間是多個任務的執行時間之和。當然這是在這種簡單實例下的結果,在複雜問題或者非IO密集型的處理過程中,效果不會這麼理想。
-
將異步操作應用到爬蟲——aiohttp
對於aiohttp,可以簡單的理解爲異步形式的requests,(只是邏輯上的理解,語法並不同)
還是通過代碼來說明語法
URL = 'https://blog.csdn.net/BBJG_001' async def job(session, url): response = await session.get(url) # 等待並切換 return str(response.url) async def main(loop): async with aiohttp.ClientSession() as session: # 官網推薦建立 Session 的形式 tasks = [loop.create_task(job(session, URL)) for _ in range(2)] finished, unfinished = await asyncio.wait(tasks) all_results = [r.result() for r in finished] # 獲取所有結果 # print(all_results) t1 = time.time() loop = asyncio.get_event_loop() loop.run_until_complete(main(loop)) loop.close() print("Async total time:", time.time() - t1) # Async total time: 0.44501423835754395
同樣也進行非異步方式的對比
URL = 'https://blog.csdn.net/BBJG_001' def normal(): for i in range(2): r = requests.get(URL) url = r.url # print(url) t1 = time.time() normal() print("Normal total time:", time.time()-t1) # Normal total time: 0.7451720237731934
可以看到在真正應用到網絡環境中之後效果提速效果就不再像上面那樣明顯了,但是效率的提升還是很可觀的。
-
參考文獻