告诉urllib2使用自定义DNS

时间:2010-02-10 11:46:05

标签: python dns urllib2 dnspython urlopen

我想告诉urllib2.urlopen(或自定义开启者)使用127.0.0.1(或::1)来解析地址。但是,我不会更改我的/etc/resolv.conf

一种可能的解决方案是使用dnspython之类的工具来查询地址,使用httplib来构建自定义网址开启工具。我更喜欢告诉urlopen使用自定义名称服务器。有什么建议吗?

3 个答案:

答案 0 :(得分:21)

看起来名称解析最终由socket.create_connection处理。

-> urllib2.urlopen
-> httplib.HTTPConnection
-> socket.create_connection

虽然设置了“Host:”标头后,您可以解析主机并将IP地址传递给开启者。

我建议您继承httplib.HTTPConnection,并在将connect传递给self.host之前将socket.create_connection方法包装起来修改HTTPHandler

然后将HTTPSHandler(和http_open)子类化为将HTTPConnection方法替换为将do_open而不是httplib自己的方法替换为import urllib2 import httplib import socket def MyResolver(host): if host == 'news.bbc.co.uk': return '66.102.9.104' # Google IP else: return host class MyHTTPConnection(httplib.HTTPConnection): def connect(self): self.sock = socket.create_connection((MyResolver(self.host),self.port),self.timeout) class MyHTTPSConnection(httplib.HTTPSConnection): def connect(self): sock = socket.create_connection((MyResolver(self.host), self.port), self.timeout) self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) class MyHTTPHandler(urllib2.HTTPHandler): def http_open(self,req): return self.do_open(MyHTTPConnection,req) class MyHTTPSHandler(urllib2.HTTPSHandler): def https_open(self,req): return self.do_open(MyHTTPSConnection,req) opener = urllib2.build_opener(MyHTTPHandler,MyHTTPSHandler) urllib2.install_opener(opener) f = urllib2.urlopen('http://news.bbc.co.uk') data = f.read() from lxml import etree doc = etree.HTML(data) >>> print doc.xpath('//title/text()') ['Google'] 的方法。

像这样:

{{1}}

如果您使用HTTPS,显然存在证书问题,您需要填写MyResolver ...

答案 1 :(得分:17)

另一种(肮脏)方式是修补猴子socket.getaddrinfo

例如,此代码为dns查找添加(无限制)缓存。

import socket
prv_getaddrinfo = socket.getaddrinfo
dns_cache = {}  # or a weakref.WeakValueDictionary()
def new_getaddrinfo(*args):
    try:
        return dns_cache[args]
    except KeyError:
        res = prv_getaddrinfo(*args)
        dns_cache[args] = res
        return res
socket.getaddrinfo = new_getaddrinfo

答案 2 :(得分:0)

您需要实现自己的DNS查找客户端(或者如您所说,使用dnspython)。 glibc中的名称查找过程非常复杂,以确保与其他非DNS名称系统的兼容性。例如,根本没有办法在glibc库中指定特定的DNS服务器。