<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們可以通過開啟流並寫入和讀取 HTTP 請求和響應來使用 asyncio 查詢網站的 HTTP 狀態。
然後我們可以使用 asyncio 並行查詢多個網站的狀態,甚至動態報告結果。
asyncio 模組提供了對開啟通訊端連線和通過流讀寫資料的支援。我們可以使用此功能來檢查網頁的狀態。
這可能涉及四個步驟,它們是:
可以使用 asyncio.open_connection() 函數在 asyncio 中開啟連線。在眾多引數中,該函數採用字串主機名和整數埠號。
這是一個必須等待的協程,它返回一個 StreamReader 和一個 StreamWriter,用於使用通訊端進行讀寫。
這可用於在埠 80 上開啟 HTTP 連線。
... # open a socket connection reader, writer = await asyncio.open_connection('www.google.com', 80)
我們還可以使用 ssl=True 引數開啟 SSL 連線。這可用於在埠 443 上開啟 HTTPS 連線。
... # open a socket connection reader, writer = await asyncio.open_connection('www.google.com', 443)
開啟後,我們可以向 StreamWriter 寫入查詢以發出 HTTP 請求。例如,HTTP 版本 1.1 請求是純文字格式的。我們可以請求檔案路徑“/”,它可能如下所示:
GET / HTTP/1.1 Host: www.google.com
重要的是,每行末尾必須有一個回車和一個換行符(rn),末尾有一個空行。
作為 Python 字串,這可能如下所示:
'GET / HTTP/1.1rn' 'Host: www.google.comrn' 'rn'
在寫入 StreamWriter 之前,此字串必須編碼為位元組。這可以通過對字串本身使用 encode() 方法來實現。預設的“utf-8”編碼可能就足夠了。
... # encode string as bytes byte_data = string.encode()
然後可以通過 StreamWriter 的 write() 方法將位元組寫入通訊端。
... # write query to socket writer.write(byte_data)
寫入請求後,最好等待位元組資料傳送完畢並等待通訊端準備就緒。這可以通過 drain() 方法來實現。這是一個必須等待的協程。
... # wait for the socket to be ready. await writer.drain()
發出 HTTP 請求後,我們可以讀取響應。這可以通過通訊端的 StreamReader 來實現。可以使用讀取一大塊位元組的 read() 方法或讀取一行位元組的 readline() 方法來讀取響應。
我們可能更喜歡 readline() 方法,因為我們使用的是基於文字的 HTTP 協定,它一次傳送一行 HTML 資料。readline() 方法是協程,必須等待。
... # read one line of response line_bytes = await reader.readline()
HTTP 1.1 響應由兩部分組成,一個由空行分隔的檔頭,然後是一個空行終止的主體。header 包含有關請求是否成功以及將傳送什麼型別的檔案的資訊,body 包含檔案的內容,例如 HTML 網頁。
HTTP 檔頭的第一行包含伺服器上所請求頁面的 HTTP 狀態。每行都必須從位元組解碼為字串。
這可以通過對位元組資料使用 decode() 方法來實現。同樣,預設編碼為“utf_8”。
... # decode bytes into a string line_data = line_bytes.decode()
我們可以通過關閉 StreamWriter 來關閉通訊端連線。這可以通過呼叫 close() 方法來實現。
... # close the connection writer.close()
這不會阻塞並且可能不會立即關閉通訊端。現在我們知道如何使用 asyncio 發出 HTTP 請求和讀取響應,讓我們看一些檢查網頁狀態的範例。
我們可以開發一個範例來使用 asyncio 檢查多個網站的 HTTP 狀態。
在此範例中,我們將首先開發一個協程來檢查給定 URL 的狀態。然後我們將為排名前 10 的網站中的每一個呼叫一次這個協程。
首先,我們可以定義一個協程,它將接受一個 URL 字串並返回 HTTP 狀態。
# get the HTTP/S status of a webpage async def get_status(url): # ...
必須將 URL 解析為其組成部分。我們在發出 HTTP 請求時需要主機名和檔案路徑。我們還需要知道 URL 方案(HTTP 或 HTTPS)以確定是否需要 SSL。
這可以使用 urllib.parse.urlsplit() 函數來實現,該函數接受一個 URL 字串並返回所有 URL 元素的命名元組。
... # split the url into components url_parsed = urlsplit(url)
然後我們可以開啟基於 URL 方案的 HTTP 連線並使用 URL 主機名。
... # open the connection if url_parsed.scheme == 'https': reader, writer = await asyncio.open_connection(url_parsed.hostname, 443, ssl=True) else: reader, writer = await asyncio.open_connection(url_parsed.hostname, 80)
接下來,我們可以使用主機名和檔案路徑建立 HTTP GET 請求,並使用 StreamWriter 將編碼位元組寫入通訊端。
... # send GET request query = f'GET {url_parsed.path} HTTP/1.1rnHost: {url_parsed.hostname}rnrn' # write query to socket writer.write(query.encode()) # wait for the bytes to be written to the socket await writer.drain()
接下來,我們可以讀取 HTTP 響應。我們只需要包含 HTTP 狀態的響應的第一行。
... # read the single line response response = await reader.readline()
然後可以關閉連線。
... # close the connection writer.close()
最後,我們可以解碼從伺服器讀取的位元組、遠端尾隨空白,並返回 HTTP 狀態。
... # decode and strip white space status = response.decode().strip() # return the response return status
將它們結合在一起,下面列出了完整的 get_status() 協程。它沒有任何錯誤處理,例如無法存取主機或響應緩慢的情況。這些新增將為讀者提供一個很好的擴充套件。
# get the HTTP/S status of a webpage async def get_status(url): # split the url into components url_parsed = urlsplit(url) # open the connection if url_parsed.scheme == 'https': reader, writer = await asyncio.open_connection(url_parsed.hostname, 443, ssl=True) else: reader, writer = await asyncio.open_connection(url_parsed.hostname, 80) # send GET request query = f'GET {url_parsed.path} HTTP/1.1rnHost: {url_parsed.hostname}rnrn' # write query to socket writer.write(query.encode()) # wait for the bytes to be written to the socket await writer.drain() # read the single line response response = await reader.readline() # close the connection writer.close() # decode and strip white space status = response.decode().strip() # return the response return status
接下來,我們可以為我們要檢查的多個網頁或網站呼叫 get_status() 協程。在這種情況下,我們將定義一個世界排名前 10 的網頁列表。
... # list of top 10 websites to check sites = ['https://www.google.com/', 'https://www.youtube.com/', 'https://www.facebook.com/', 'https://twitter.com/', 'https://www.instagram.com/', 'https://www.baidu.com/', 'https://www.wikipedia.org/', 'https://yandex.ru/', 'https://yahoo.com/', 'https://www.whatsapp.com/' ]
然後我們可以使用我們的 get_status() 協程依次查詢每個。在這種情況下,我們將在一個迴圈中按順序這樣做,並依次報告每個狀態。
... # check the status of all websites for url in sites: # get the status for the url status = await get_status(url) # report the url and its status print(f'{url:30}:t{status}')
在使用 asyncio 時,我們可以做得比順序更好,但這提供了一個很好的起點,我們可以在以後進行改進。將它們結合在一起,main() 協程查詢前 10 個網站的狀態。
# main coroutine async def main(): # list of top 10 websites to check sites = ['https://www.google.com/', 'https://www.youtube.com/', 'https://www.facebook.com/', 'https://twitter.com/', 'https://www.instagram.com/', 'https://www.baidu.com/', 'https://www.wikipedia.org/', 'https://yandex.ru/', 'https://yahoo.com/', 'https://www.whatsapp.com/' ] # check the status of all websites for url in sites: # get the status for the url status = await get_status(url) # report the url and its status print(f'{url:30}:t{status}')
最後,我們可以建立 main() 協程並將其用作 asyncio 程式的入口點。
... # run the asyncio program asyncio.run(main())
將它們結合在一起,下面列出了完整的範例。
# SuperFastPython.com # check the status of many webpages import asyncio from urllib.parse import urlsplit # get the HTTP/S status of a webpage async def get_status(url): # split the url into components url_parsed = urlsplit(url) # open the connection if url_parsed.scheme == 'https': reader, writer = await asyncio.open_connection(url_parsed.hostname, 443, ssl=True) else: reader, writer = await asyncio.open_connection(url_parsed.hostname, 80) # send GET request query = f'GET {url_parsed.path} HTTP/1.1rnHost: {url_parsed.hostname}rnrn' # write query to socket writer.write(query.encode()) # wait for the bytes to be written to the socket await writer.drain() # read the single line response response = await reader.readline() # close the connection writer.close() # decode and strip white space status = response.decode().strip() # return the response return status # main coroutine async def main(): # list of top 10 websites to check sites = ['https://www.google.com/', 'https://www.youtube.com/', 'https://www.facebook.com/', 'https://twitter.com/', 'https://www.instagram.com/', 'https://www.baidu.com/', 'https://www.wikipedia.org/', 'https://yandex.ru/', 'https://yahoo.com/', 'https://www.whatsapp.com/' ] # check the status of all websites for url in sites: # get the status for the url status = await get_status(url) # report the url and its status print(f'{url:30}:t{status}') # run the asyncio program asyncio.run(main())
執行範例首先建立 main() 協程並將其用作程式的入口點。main() 協程執行,定義前 10 個網站的列表。然後順序遍歷網站列表。 main()協程掛起呼叫get_status()協程查詢一個網站的狀態。
get_status() 協程執行、解析 URL 並開啟連線。它構造一個 HTTP GET 查詢並將其寫入主機。讀取、解碼並返回響應。main() 協程恢復並報告 URL 的 HTTP 狀態。
對列表中的每個 URL 重複此操作。該程式大約需要 5.6 秒才能完成,或者平均每個 URL 大約需要半秒。這突出了我們如何使用 asyncio 來查詢網頁的 HTTP 狀態。
儘管如此,它並沒有充分利用 asyncio 來並行執行任務。
https://www.google.com/ : HTTP/1.1 200 OK
https://www.youtube.com/ : HTTP/1.1 200 OK
https://www.facebook.com/ : HTTP/1.1 302 Found
https://twitter.com/ : HTTP/1.1 200 OK
https://www.instagram.com/ : HTTP/1.1 200 OK
https://www.baidu.com/ : HTTP/1.1 200 OK
https://www.wikipedia.org/ : HTTP/1.1 200 OK
https://yandex.ru/ : HTTP/1.1 302 Moved temporarily
https://yahoo.com/ : HTTP/1.1 301 Moved Permanently
https://www.whatsapp.com/ : HTTP/1.1 302 Found
asyncio 的一個好處是我們可以同時執行許多協程。我們可以使用 asyncio.gather() 函數在 asyncio 中並行查詢網站的狀態。
此函數採用一個或多個協程,暫停執行提供的協程,並將每個協程的結果作為可迭代物件返回。然後我們可以遍歷 URL 列表和可迭代的協程返回值並報告結果。
這可能是比上述方法更簡單的方法。首先,我們可以建立一個協程列表。
... # create all coroutine requests coros = [get_status(url) for url in sites]
接下來,我們可以執行協程並使用 asyncio.gather() 獲取可迭代的結果。
請注意,我們不能直接提供協程列表,而是必須將列表解壓縮為單獨的表示式,這些表示式作為位置引數提供給函數。
... # execute all coroutines and wait results = await asyncio.gather(*coros)
這將同時執行所有協程並檢索它們的結果。然後我們可以遍歷 URL 列表和返回狀態並依次報告每個。
... # process all results for url, status in zip(sites, results): # report status print(f'{url:30}:t{status}')
將它們結合在一起,下面列出了完整的範例。
# SuperFastPython.com # check the status of many webpages import asyncio from urllib.parse import urlsplit # get the HTTP/S status of a webpage async def get_status(url): # split the url into components url_parsed = urlsplit(url) # open the connection if url_parsed.scheme == 'https': reader, writer = await asyncio.open_connection(url_parsed.hostname, 443, ssl=True) else: reader, writer = await asyncio.open_connection(url_parsed.hostname, 80) # send GET request query = f'GET {url_parsed.path} HTTP/1.1rnHost: {url_parsed.hostname}rnrn' # write query to socket writer.write(query.encode()) # wait for the bytes to be written to the socket await writer.drain() # read the single line response response = await reader.readline() # close the connection writer.close() # decode and strip white space status = response.decode().strip() # return the response return status # main coroutine async def main(): # list of top 10 websites to check sites = ['https://www.google.com/', 'https://www.youtube.com/', 'https://www.facebook.com/', 'https://twitter.com/', 'https://www.instagram.com/', 'https://www.baidu.com/', 'https://www.wikipedia.org/', 'https://yandex.ru/', 'https://yahoo.com/', 'https://www.whatsapp.com/' ] # create all coroutine requests coros = [get_status(url) for url in sites] # execute all coroutines and wait results = await asyncio.gather(*coros) # process all results for url, status in zip(sites, results): # report status print(f'{url:30}:t{status}') # run the asyncio program asyncio.run(main())
執行該範例會像以前一樣執行 main() 協程。在這種情況下,協程列表是在列表理解中建立的。
然後呼叫 asyncio.gather() 函數,傳遞協程並掛起 main() 協程,直到它們全部完成。協程執行,同時查詢每個網站並返回它們的狀態。
main() 協程恢復並接收可迭代的狀態值。然後使用 zip() 內建函數遍歷此可迭代物件和 URL 列表,並報告狀態。
這突出了一種更簡單的方法來同時執行協程並在所有任務完成後報告結果。它也比上面的順序版本更快,在我的系統上完成大約 1.4 秒。
https://www.google.com/ : HTTP/1.1 200 OK
https://www.youtube.com/ : HTTP/1.1 200 OK
https://www.facebook.com/ : HTTP/1.1 302 Found
https://twitter.com/ : HTTP/1.1 200 OK
https://www.instagram.com/ : HTTP/1.1 200 OK
https://www.baidu.com/ : HTTP/1.1 200 OK
https://www.wikipedia.org/ : HTTP/1.1 200 OK
https://yandex.ru/ : HTTP/1.1 302 Moved temporarily
https://yahoo.com/ : HTTP/1.1 301 Moved Permanently
https://www.whatsapp.com/ : HTTP/1.1 302 Found
以上就是Python使用Asyncio實現檢查網站狀態的詳細內容,更多關於Python Asyncio檢查網站狀態的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45