“请求”python库上的DNS超时

DNS timeout on 'requests' python library

对于我的项目,我必须检查网站的状态(在共享主机上)。

我使用Python请求库。

1
2
3
4
5
def getStatusCode(url):
    try:
        return requests.head(url,timeout=0.3).status_code
    except:
        return -1

此代码在MacOS 10.10下使用Python3.4非常有效,其中包含http://www.google.com等网址。 如果我拔掉我的ISP电缆,我立即得到了例外。

在带有Python3.4的Ubuntu Server 14.04下,如果我拔掉我的ISP电缆,我永远不会收到超时错误。 Raspbian上的同样问题。

经过一些测试,如果我用IP http://216.58.212.100替换url,Ubuntu Server会引发异常,但由于我在共享的Web托管上,所以我无法使用IP。

经过一些研究后,我发现请求库中的超时和DNS查找之间存在差异,这种情况不是由操作系统执行,而是由操作系统执行。

所以我的问题是解决这个问题最美妙的方法是什么? 我是否需要在Python中添加额外的超时异常,如:函数调用超时

谢谢


根据查理的鼓励,我在这里发布我的两个解决方案

对于第一个,我在请求标头中添加了主机,因此我可以将IP地址作为url和avoir DNS查找。

1
2
3
4
5
6
7
8
def getStatusCode(url):
    headers = {'host': 'www.example.com'}
    try:
        return requests.head(url,timeout=0.3,headers=headers).status_code
    except:
        return -1

print(getStatusCode('http://1.2.3.4'))

第二种解决方案基于信号的使用,但具有一秒的分辨率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class timeout:
    def __init__(self, seconds=1, error_message='Timeout'):
        self.seconds = seconds
        self.error_message = error_message
    def handle_timeout(self, signum, frame):
        raise TimeoutError(self.error_message)
    def __enter__(self):
        signal.signal(signal.SIGALRM, self.handle_timeout)
        signal.alarm(self.seconds)
    def __exit__(self, type, value, traceback):
        signal.alarm(0)

def getStatusCode(url):
    try:
        return requests.head(url,timeout=0.3).status_code
    except:
        return -1

with timeout(seconds=1):
    print(getStatusCode('http://www.example.com'))

(此解决方案来自Thomas Ahle,网址为https://stackoverflow.com/a/22348885/3896729)


现在我已经更好地理解了你的问题 - 我认为有一个更好的方法是使用你的操作系统ping应用程序,这在Python中应该不难做到 - 例如。您还应该平均1000个请求并查看平均值,标准偏差,异常值等。原因是如果一个请求需要500毫秒而您想要1毫秒的分辨率,则需要产生至少500个请求来获取任何内容接近你想要的分辨率。

使用Pythons urllib(2)的问题在于它的执行效果几乎不如系统级调用,因此您很难产生足够的线程来获得所需的时序分辨率。

最后,我会再次检查您的结果商业产品,以确保您的结果相似。例如(没有隶属关系):
http://www.thinkbroadband.com/ping。