【问题标题】:Use urllib in python to fetch IPv6 URL with FQDN在 python 中使用 urllib 获取带有 FQDN 的 IPv6 URL
【发布时间】:2017-08-11 14:38:43
【问题描述】:

我想用 urllib 获取 IPv6 页面。 使用方括号 IPv6 表示法,但当我给它 FQDN 时,我不知道如何(轻松)说服 python 执行 IPv6 请求 就像下面的ip是:https://www.dslreports.com/whatismyip

from sys import version_info

PY3K = version_info >= (3, 0)

if PY3K:
    import urllib.request as urllib
else:
    import urllib2 as urllib

url = None
opener = urllib.build_opener()
opener.addheaders = [('User-agent',
     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36")]
url = opener.open("http://[2607:fad0:3706:1::1000]/whatismyip", timeout=3)
content = url.read()

【问题讨论】:

  • 澄清一下,当 IPv4 和 IPv6 地址都可用时,您希望始终使用 IPv6 地址吗?
  • 是的,因为代码应该依次但不按顺序检查 IPv4,然后检查 IPv6。

标签: python urllib ipv6


【解决方案1】:

我终于解决了我的问题。不是以最优雅的方式,但它对我有用。

看完后:

Force requests to use IPv4 / IPv6Python urllib2 force IPv4

我决定进行 DNS 查找,然后发送一个带有 FQDN 的 Host 标头来获取内容。 (虚拟主机需要主机头)

这是丑陋的sn-p:

# Ugly hack to get either IPv4 or IPv6 response from server
parsed_uri = urlparse(server)
fqdn = "{uri.netloc}".format(uri=parsed_uri)
scheme = "{uri.scheme}".format(uri=parsed_uri)
path = "{uri.path}".format(uri=parsed_uri)

try:
    ipVersion = ip_kind(fqdn[1:-1])
    ip = fqdn
except ValueError:
    addrs = socket.getaddrinfo(fqdn, 80)
    if haveIPv6:
        ipv6_addrs = [addr[4][0] for addr in addrs if addr[0] == socket.AF_INET6]
        ip = "[" + ipv6_addrs[0] + "]"
    else:
        ipv4_addrs = [addr[4][0] for addr in addrs if addr[0] == socket.AF_INET]
        ip = ipv4_addrs[0]

server = "{}://{}{}".format(scheme, ip, path)

url = urllib.Request(server, None, {'User-agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5'})
# Next line adds the host header
url.host = fqdn
content = urllib.urlopen(url).read()

这远非理想,它可能会更干净,但它对我有用。

在这里实现:https://github.com/SteveClement/ipgetter/tree/IPv6 这只是通过一个服务器列表返回您的边界网关 IP,现在也在 IPv6 中。

【讨论】:

    【解决方案2】:

    [更新:关于 Python 2 / Python 3 的这一行不再有效,因为问题已更新]

    首先,您似乎使用的是 Python 2。这很重要,因为 urllib 模块已被拆分为多个部分并在 Python 3 中重命名。

    其次,您的代码 sn-p 似乎不正确:build_opener 不是 urllib 可用的函数。它在 urllib2 中可用。

    所以,我假设您的代码实际上是以下代码:

    import urllib2
    opener = urllib2.build_opener()
    opener.addheaders = [('User-agent',
     "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36")]
    url = opener.open("http://www.dslreports.com/whatismyip", timeout=3)
    

    如果您的 DNS 解析器正确处理 IPv6 资源记录,并且如果您的操作系统是使用双堆栈 IPv4/IPv6 或单 IPv6 堆栈构建的,并且如果您有一个正确的 IPv6 网络路径到 dslreports.com,则此 Python程序将使用 IPv6 连接到 www.dslreports.com。因此,无需说服 python 发出 IPv6 请求。

    【讨论】:

    • 好吧,我猜我不是很清楚。正如您在我对 sn-p 的更新中看到的那样,代码与 python2 和 3 兼容。在 python 的精神中,显式比隐式更好。我不希望它依赖用户正确配置 IPv6 的能力。您应该掌握是使用 v4 还是 v6。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    • 2011-10-06
    • 1970-01-01
    • 2017-12-29
    相关资源
    最近更新 更多