在requests里,可以通過(guò)timeout參數(shù) 設(shè)置請(qǐng)求超時(shí)時(shí)間,超時(shí)則拋出異常
requests.get(url=url,timeout=(10,30))
timeout=(10,30)表示connect timeout 10秒,read timeout 30秒。
有時(shí)候,即使這樣設(shè)置依然會(huì)出現(xiàn)超時(shí)永久卡住的情況,仔細(xì)搜索資料,發(fā)現(xiàn)timeout只是針對(duì)connect和read超時(shí),而如果在connect之前就卡住,則會(huì)一直卡住,比如從dns服務(wù)器獲取域名解析ip,這一步卡住的話,程序就一直卡住了,沒(méi)人管的話卡一個(gè)月都行。
我有一個(gè)爬蟲(chóng)就是這樣,放在國(guó)內(nèi)完全沒(méi)問(wèn)題,放在國(guó)外服務(wù)器就經(jīng)常requests卡住。全部都加了timeout參數(shù),改善很多,但是還是會(huì)偶爾卡住,后來(lái)發(fā)現(xiàn)是獲取dns這一步卡住了。
(驗(yàn)證:urllib 直接使用 socket.getaddrinfo 獲取 DNS,寫(xiě)一個(gè)循環(huán)重復(fù) 1000 次,然后你發(fā)現(xiàn)自己的程序卡死了那么你應(yīng)該遇到了和我一樣的狀況。)
requests的文檔有這樣描述:
timeout is not a time limit on the entire response download; rather, an exception is raised if the server has not issued a response for timeout seconds (more precisely, if no bytes have been received on the underlying socket for timeout seconds). If no timeout is specified explicitly, requests do not time out.
解決辦法
在程序main函數(shù)開(kāi)頭用setdefaulttimeout 設(shè)置默認(rèn)請(qǐng)求超時(shí)時(shí)間。
socket.setdefaulttimeout(timeout)
Set the default timeout in seconds (float) for new socket objects. A value of None indicates that new socket objects have no timeout. When the socket module is first imported, the default is None.
import socket
socket.setdefaulttimeout(30)
設(shè)置HTTP或socket超時(shí),來(lái)防止請(qǐng)求時(shí)間過(guò)長(zhǎng),導(dǎo)致程序卡置不前。
上面代碼把全局默認(rèn)dns解析、connect、read 的timeout都設(shè)為了30秒。
requests的timeout參數(shù)會(huì)覆蓋默認(rèn)的connect、read時(shí)間,不影響其他請(qǐng)求。