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。