日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

异步爬虫-aiohttp库、Twisted库简介

發布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 异步爬虫-aiohttp库、Twisted库简介 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么要用異步爬蟲?

?爬蟲本質上就是模擬客戶端與服務端的通訊過程。以瀏覽器端的爬蟲為例,我們在爬取不同網頁過程中,需要根據url構建很多HTTP請求去爬取,而如果以單個線程為參考對象,平常我們所采取的編碼習慣,通常是基于同步模式的,也就是串行的方式去執行這些請求,只有當一個url爬取結束后才會進行下一個url的爬取,由于網絡IO的延時存在,效率非常低。
?到這里可能會有人說,那么我們可以使用多進程+多線程來提高效率啊,為什么要使用異步編程,畢竟異步編程會大大增加編程難度。【進程、線程、協程簡單梳理】在這篇整理文章中有提到,多進程/多線程雖然能提高效率,但是在進程/線程切換的時候,也會消耗很多資源。而且就IO密集型任務來說,雖然使用多線程并發可以提高CUP使用率,提升爬取效率,但是卻還是沒有解決IO阻塞問題。無論是多進程還是多線程,在遇到IO阻塞時都會被操作系統強行剝奪走CPU的執行權限,爬蟲的執行效率因此就降低了下來。而異步編程則是我們在應用程序級別來檢測IO阻塞然后主動切換到其他任務執行,以此來'降低'我們爬蟲的IO,使我們的爬蟲更多的處于就緒態,這樣操作系統就會讓CPU盡可能多地臨幸我們的爬蟲,從而提高爬蟲的爬取效率。

補充:常見的IO模型有阻塞、非阻塞、IO多路復用,異步。下面舉個小栗子來簡單描述一下這四個場景。
當快樂的敲代碼時光結束時,沒有女朋友的單身狗只能約上好基友去召喚師峽谷傲游,當我秒選快樂風男,然后發送“亞索中單,不給就送后”,在隊友一片歡聲笑語中進入加載界面,奈何遇到小霸王,加載異常緩慢。。。此時!

  • 你選擇什么也不做,直直地看著輔助妹子的琴女原畫,等待加載完成。這是阻塞。
  • 你選擇切換出去到某魚看球,但是你得時不時的切換回LOL,看看是否加載完成,就這樣來來回回,累得要死,還錯過很多精彩畫面。這是非阻塞。
  • 你掏出自己的愛瘋XL,打開某魚APP看球,這樣就不用來回切換,只是時不時地看一下電腦顯示器,看是否加載完成了。這是IO多路復用。
  • 連泡面都舍不得一次用完一包醬包的你,哪有愛瘋XL,但是身為碼農的尊嚴讓你寫個個小程序,在檢測到游戲在加載的時候,自動切換到瀏覽器,打開某魚的球星直播間。而當游戲加載完成后,自動切換回LOL游戲界面。無縫切換絲滑感受。這個叫異步。
  • 下面開始進入正題

    asyncio

    在介紹aiohttp、tornado、twisted之前,先了解下python3.4版本引入的標準庫asyncio。它可以幫助我們檢測IO(只能是網絡IO),實現應用程序級別的切換。它的編程模型是一個消息循環。我們可以從asyncio模塊中直接獲取一個EventLoop的引用,然后把需要執行的協程扔到EventLoop中執行,就實現了異步IO。

    基本使用

    ?

    import asyncio import random import datetimeurls=['www.baidu.com','www.qq.com','www.douyu.com']@asyncio.coroutine def crawl(url):print("正在抓取:{}-{}".format(url,datetime.datetime.now().time()))io_time = random.random()*3 #隨機模擬網絡IO時間yield from asyncio.sleep(io_time) #模擬網絡IOprint('{}-抓取完成,用時{}s'.format(url,io_time))loop = asyncio.get_event_loop() #獲取EventLoop loop.run_until_complete(asyncio.wait(map(crawl,urls))) #執行coroutine loop.close()

    運行結果:

    ?

    正在抓取:www.baidu.com-12:45:26.517226 正在抓取:www.douyu.com-12:45:26.517226 正在抓取:www.qq.com-12:45:26.517226 www.douyu.com-抓取完成,用時0.1250027573049739s www.baidu.com-抓取完成,用時0.450045918339271s www.qq.com-抓取完成,用時0.6967129499714361s [Finished in 0.9s]

    運行的時候可以發現三個請求幾乎是同時發出的,而返回順序則是根據網絡IO完成時間順序返回的。

    由于asyncio主要應用于TCP/UDP socket通訊,不能直接發送http請求,因此,我們需要自己定義http報頭。
    補充:

    • 客戶端發送一個HTTP請求到服務器的請求消息包括以下格式:請求行、消息報頭和請求正文三個部分。
      例如:GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n
    • 用asyncio提供的@asyncio.coroutine可以把一個generator標記為coroutine類型,然后在coroutine內部用yield from調用另一個coroutine實現異步操作。為了簡化并更好地標識異步IO,從Python 3.5開始引入了新的語法async和await,可以讓coroutine的代碼更簡潔易讀。

    概念補充

    • event_loop:事件循環,相當于一個無限循環,我們可以把一些函數注冊到這個事件循環上,當滿足條件發生的時候,就會調用對應的處理方法。
    • coroutine:中文翻譯叫協程,在 Python 中常指代為協程對象類型,我們可以將協程對象注冊到時間循環中,它會被事件循環調用。我們可以使用 async 關鍵字來定義一個方法,這個方法在調用時不會立即被執行,而是返回一個協程對象。
    • task:任務,它是對協程對象的進一步封裝,包含了任務的各個狀態。
    • future:代表將來執行或沒有執行的任務的結果,實際上和 task 沒有本質區別。

    有了以上知識基礎,就可以擼代碼啦

    ?

    import asyncio import uuiduser_agent='Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'def parse_page(host,res):print('%s 解析結果 %s' %(host,len(res)))with open('%s.html' %(uuid.uuid1()),'wb') as f:f.write(res)async def get_page(host,port=80,url='/',callback=parse_page,ssl=False,encode_set='utf-8'):print('下載 http://%s:%s%s' %(host,port,url))if ssl:port=443#發起tcp連接, IO阻塞操作recv,send=await asyncio.open_connection(host=host,port=port,ssl=ssl) #封裝http協議的報頭,因為asyncio模塊只能封裝并發送tcp包,因此這一步需要我們自己封裝http協議的包request_headers="""GET {} HTTP/1.0\r\nHost: {}\r\nUser-agent: %s\r\n\r\n""".format(url,host,user_agent) request_headers=request_headers.encode(encode_set)#發送構造好的http請求(request),IO阻塞send.write(request_headers)await send.drain()#接收響應頭 IO阻塞操作while True:line=await recv.readline()if line == b'\r\n':breakprint('%s Response headers:%s' %(host,line))#接收響應體 IO阻塞操作text=await recv.read()#執行回調函數callback(host,text)#關閉套接字send.close() #沒有recv.close()方法,因為是四次揮手斷鏈接,雙向鏈接的兩端,一端發完數據后執行send.close()另外一端就被動地斷開if __name__ == '__main__':tasks=[get_page('www.gov.cn',url='/',ssl=False),get_page('www.douyu.com',url='/',ssl=True),]loop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))loop.close()

    用上async/await關鍵字,是不是既簡潔,也更便于理解了

    自己動手封裝HTTP(S)報頭確實很麻煩,所以接下來就要請出這一小節的正主aiohttp了,它里面已經幫我們封裝好了。
    補充:asyncio可以實現單線程并發IO操作。如果僅用在客戶端,發揮的威力不大。如果把asyncio用在服務器端,例如Web服務器,由于HTTP連接就是IO操作,因此可以用單線程+coroutine實現多用戶的高并發支持。asyncio實現了TCP、UDP、SSL等協議,aiohttp則是基于asyncio實現的HTTP框架。它分為兩部分,一部分是Client(我們將要使用的部分,因為我們爬蟲是模擬客戶端操作嘛),一部分是 Server,詳細的內容可以參考官方文檔。

    下面我們用aiohttp來改寫上面的代碼:

    ?

    import asyncio import uuid import aiohttpuser_agent='Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'def parse_page(url,res):print('{} 解析結果 {}'.format(url,len(res)))with open('{}.html'.format(uuid.uuid1()),'wb') as f:f.write(res)async def get_page(url,callback=parse_page):session = aiohttp.ClientSession()response = await session.get(url)if response.reason == 'OK':result = await response.read()session.close()callback(url,result)if __name__ == '__main__':tasks=[get_page('http://www.gov.cn'),get_page('https://www.douyu.com'),]loop=asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))loop.close()

    是不是更加簡潔了呢?


    Twisted

    twisted是一個網絡框架,哪怕剛剛接觸python爬蟲的萌新都知道的Scrapy爬蟲框架,就是基于twisted寫的。它其中一個功能就是發送異步請求,檢測IO并自動切換。
    基于twisted修改上面的代碼如下:

    ?

    from twisted.web.client import getPage,defer from twisted.internet import reactor import uuiddef tasks_done(arg):reactor.stop() #停止reactor#定義回調函數 def parse_page(res):print('解析結果 {}'.format(len(res)))with open('{}.html'.format(uuid.uuid1()),'wb') as f:f.write(res)defer_list=[]#初始化一個列表來存放getPage返回的defer對象urls=['http://www.gov.cn','https://www.douyu.com', ]for url in urls:obj = getPage(url.encode('utf-8'),) #getPage會返回一個defer對象obj.addCallback(parse_page) #給defer對象添加回調函數defer_list.append(obj) #將defer對象添加到列表中defer.DeferredList(defer_list).addBoth(tasks_done) #任務列表結束后停止reactor.stopreactor.run #啟動監聽

    這只是一個簡單的應用,后面會看情況可能會寫一篇Twisted的整理文章。



    作者:放風箏的富蘭克林
    鏈接:https://www.jianshu.com/p/aa93b7ae2a56
    來源:簡書
    著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

    總結

    以上是生活随笔為你收集整理的异步爬虫-aiohttp库、Twisted库简介的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。