天天看點

【Python 庫】requests 詳解逾時和重試 Python:bs4的使用Python:bs4中 string 屬性和 text 屬性的差別及背後的原理

網絡請求不可避免會遇上請求逾時的情況,在 requests 中,如果不設定你的程式可能會永遠失去響應。

逾時又可分為連接配接逾時和讀取逾時。

連接配接逾時

連接配接逾時指的是在你的用戶端實作到遠端機器端口的連接配接時(對應的是

connect()

),Request 等待的秒數。

import time
import requests

url = \'http://www.google.com.hk\'

print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))
try:
    html = requests.get(url, timeout=5).text
    print(\'success\')
except requests.exceptions.RequestException as e:
    print(e)

print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))
           

因為 google 被牆了,是以無法連接配接,錯誤資訊顯示 connect timeout(連接配接逾時)。

2018-12-14 14:38:20
HTTPConnectionPool(host=\'www.google.com.hk\', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x00000000047F80F0>, \'Connection to www.google.com.hk timed out. (connect timeout=5)\'))
2018-12-14 14:38:25
           

就算不設定,也會有一個預設的連接配接逾時時間(我測試了下,大概是21秒)。

讀取逾時

讀取逾時指的就是用戶端等待伺服器發送請求的時間。(特定地,它指的是用戶端要等待伺服器發送位元組之間的時間。在 99.9% 的情況下這指的是伺服器發送第一個位元組之前的時間)。

簡單的說,連接配接逾時就是發起請求連接配接到連接配接建立之間的最大時長,讀取逾時就是連接配接成功開始到伺服器傳回響應之間等待的最大時長。

如果你設定了一個單一的值作為 timeout,如下所示:

r = requests.get(\'https://github.com\', timeout=5)
           

這一 timeout 值将會用作 connect 和 read 二者的 timeout。如果要分别制定,就傳入一個元組:

r = requests.get(\'https://github.com\', timeout=(3.05, 27))
           

黑闆課爬蟲闖關的第四關正好網站人為設定了一個15秒的響應等待時間,拿來做說明最好不過了。

import time
import requests

url_login = \'http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex03/\'

session = requests.Session()
session.get(url_login)

token = session.cookies[\'csrftoken\']
session.post(url_login, data={\'csrfmiddlewaretoken\': token, \'username\': \'xx\', \'password\': \'xx\'})

print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))

url_pw = \'http://www.heibanke.com/lesson/crawler_ex03/pw_list/\'
try:
    html = session.get(url_pw, timeout=(5, 10)).text
    print(\'success\')
except requests.exceptions.RequestException as e:
    print(e)

print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))
           

錯誤資訊中顯示的是 read timeout(讀取逾時)。

2018-12-14 15:20:47
HTTPConnectionPool(host=\'www.heibanke.com\', port=80): Read timed out. (read timeout=10)
2018-12-14 15:20:57
           

讀取逾時是沒有預設值的,如果不設定,程式将一直處于等待狀态。我們的爬蟲經常卡死又沒有任何的報錯資訊,原因就在這裡了。

逾時重試

一般逾時我們不會立即傳回,而會設定一個三次重連的機制。

def gethtml(url):
    i = 0
    while i < 3:
        try:
            html = requests.get(url, timeout=5).text
            return html
        except requests.exceptions.RequestException:
            i += 1
           

其實 requests 已經幫我們封裝好了。(但是代碼好像變多了...)

import time
import requests
from requests.adapters import HTTPAdapter

s = requests.Session()
s.mount(\'http://\', HTTPAdapter(max_retries=3))
s.mount(\'https://\', HTTPAdapter(max_retries=3))

print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))
try:
    r = s.get(\'http://www.google.com.hk\', timeout=5)
    return r.text
except requests.exceptions.RequestException as e:
    print(e)
print(time.strftime(\'%Y-%m-%d %H:%M:%S\'))
           

max_retries

為最大重試次數,重試3次,加上最初的一次請求,一共是4次,是以上述代碼運作耗時是20秒而不是15秒

2018-12-14 15:34:03
HTTPConnectionPool(host=\'www.google.com.hk\', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x0000000013269630>, \'Connection to www.google.com.hk timed out. (connect timeout=5)\'))
2018-12-14 15:34:23
           

相關博文推薦: