使用Python请求准确捕获DNS错误

3

我正在尝试使用 python-requests 检查过期的域名。

import requests

try:
    status = requests.head('http://wowsucherror')
except requests.ConnectionError as exc:
    print(exc)

这段代码看起来太通用了。它产生以下输出:

HTTPConnectionPool(host='wowsucherror', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 11001] getaddrinfo failed',))

我想要的是只捕获这个DNS错误(如Chrome中的ERR_NAME_NOT_RESOLVED)。如果万不得已,我可以使用字符串匹配,但也许有更好、更结构化和向前兼容的方法来处理这个错误?

理想情况下应该是requests的一些DNSError扩展。

更新: Linux上的错误不同。

HTTPConnectionPool(host='wowsucherror', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known',))

requests->urllib3报告了错误https://github.com/shazow/urllib3/issues/1003

更新2: OS X也报告了不同的错误。

requests.exceptions.ConnectionError: HTTPConnectionPool(host='wowsucherror', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known',))


1
我认为你将会被困在从字符串解析errno的地方,socket错误已经在这里被捕获 https://github.com/kennethreitz/requests/blob/master/requests/packages/urllib3/connection.py#L149 但是没有任何地方设置了errno属性,因此你只能得到错误消息。如果你实际上可以访问'e',那么只需要检查e.errno就可以了。 - Padraic Cunningham
@PadraicCunningham 看起来这个错误信息不是跨平台的,我需要知道它在Linux和OS X上的表现如何。 - anatoly techtonik
确实,在我的Ubuntu系统上它会抛出一个[errno -2]错误,我尝试使用except (NewConnectionError, socket.error) as exc:语句,但是socket错误被吞掉了。也许值得发起一个问题,因为这似乎是一个合理的需求,只需要将e.errno传递即可。 - Padraic Cunningham
3个回答

7

使用以下hack完成了这个操作,但请关注https://github.com/psf/requests/issues/3630以查看更好的方法。

# for Python 2 compatibility
from __future__ import print_function
import requests

def sitecheck(url):
    status = None
    message = ''
    try:
        resp = requests.head('http://' + url)
        status = str(resp.status_code)
    if ("[Errno 11001] getaddrinfo failed" in str(exc) or     # Windows
        "[Errno -2] Name or service not known" in str(exc) or # Linux
        "[Errno 8] nodename nor servname " in str(exc)):      # OS X
        message = 'DNSLookupError'
    else:
        raise

    return url, status, message

print(sitecheck('wowsucherror'))
print(sitecheck('google.com'))

1
我有一个基于之前答案的函数,似乎不再起作用。该函数根据分辨率和请求的.ok函数而不仅仅是特定于分辨率错误来检查url的“活力”,但可以轻松适应。
def check_live(url):
    try:
        r = requests.get(url)
        live = r.ok
    except requests.ConnectionError as e:
        if 'MaxRetryError' not in str(e.args) or 'NewConnectionError' not in str(e.args):
            raise
        if "[Errno 8]" in str(e) or "[Errno 11001]" in str(e) or ["Errno -2"] in str(e):
            print('DNSLookupError')
            live = False
        else:
            raise
    except:
        raise
    return live

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接