爬蟲:異步(並行)數據爬取

原文地址

分類目錄——爬蟲

在進行網頁爬取時,網頁的響應速度慢於計算機的處理速度,在串行模式下訪問多個網頁,在通過網絡獲取一個網頁的過程中,在這個過程之前,計算機只能閒置等待。而異步的方式就是讓計算機可以在這個閒置時間先去做後面的工作,等這個網頁響應完成再對它進行處理。

這裏說的這種異步的方式是一種分時獲得時間片的機制,有些像多線程,不同於多進程,私以爲比較適合爬蟲這種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
    

    可以看到在真正應用到網絡環境中之後效果提速效果就不再像上面那樣明顯了,但是效率的提升還是很可觀的。

  • 全部代碼

  • 參考文獻

    加速爬蟲: 異步加載 Asyncio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章