我想告诉urllib2.urlopen
(或自定义开罐器)使用127.0.0.1
(或::1
)来解析地址。然而,我不会改变我的/etc/resolv.conf
。告诉urllib2使用自定义DNS
一个可能的解决方案是使用像dnspython
这样的工具查询地址,并使用httplib
来构建一个自定义url开启者。我宁愿告诉urlopen
使用自定义域名服务器。有什么建议么?
我想告诉urllib2.urlopen
(或自定义开罐器)使用127.0.0.1
(或::1
)来解析地址。然而,我不会改变我的/etc/resolv.conf
。告诉urllib2使用自定义DNS
一个可能的解决方案是使用像dnspython
这样的工具查询地址,并使用httplib
来构建一个自定义url开启者。我宁愿告诉urlopen
使用自定义域名服务器。有什么建议么?
看起来像名称解析最终由socket.create_connection
处理。
-> urllib2.urlopen
-> httplib.HTTPConnection
-> socket.create_connection
一度的“主持人:”头已定,就可以解析主机,并通过倒在揭幕战上的IP地址通过。
我建议你将子类别httplib.HTTPConnection
,并包装connect
方法修改self.host
然后将其传递到socket.create_connection
。
然后继承HTTPHandler
(和HTTPSHandler
)与一个通过你的HTTPConnection
代替httplib的自己来do_open
更换http_open
方法。
像这样:
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']
显然,有证书的问题,如果你使用HTTPS,你会需要填写MyResolver ...
您需要实现自己的DNS查找客户端(或者像你说的那样使用dnspython)。 glibc中的名称查找过程非常复杂,以确保与其他非DNS名称系统的兼容性。例如,根本没有办法在glibc库中指定特定的DNS服务器。
另一种(脏)的方式是猴子修补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
这个黑客的一个优点是,它也拦截了python中几乎所有的dns查找,不仅通过'urlopen' – 2013-11-21 08:32:33
这是一个更好的解决方案,如果主机的范围很小。我有10倍的速度。 :) – 2014-06-30 14:16:22
我不认为我现在需要HTTPS,所以这完全就够了!非常感谢你! – 2010-02-10 19:03:26
也可以重写'HTTPConnection._create_connection',由于http://bugs.python.org/issue7776,自Python 2.7.7和3.5开始可用。 – 2016-04-13 08:26:26