2024-05-16 03:28:58 发布
网友
我想告诉urllib2.urlopen(或一个定制的打开程序)使用127.0.0.1(或::1)来解析地址。不过,我不会改变我的/etc/resolv.conf。
urllib2.urlopen
127.0.0.1
::1
/etc/resolv.conf
一种可能的解决方案是使用像dnspython这样的工具来查询地址,以及httplib来构建自定义url打开程序。不过,我更希望告诉urlopen使用自定义名称服务器。有什么建议吗?
dnspython
httplib
urlopen
看起来名称解析最终由socket.create_connection处理。
socket.create_connection
-> urllib2.urlopen -> httplib.HTTPConnection -> socket.create_connection
不过,一旦设置了“Host:”头,就可以解析主机并将IP地址向下传递到打开程序。
我建议您对httplib.HTTPConnection进行子类划分,并在将其传递给socket.create_connection之前包装connect方法以修改self.host。
httplib.HTTPConnection
connect
self.host
然后子类HTTPHandler(和HTTPSHandler)将http_open方法替换为将HTTPConnection而不是将httplib自己的方法传递给do_open。
HTTPHandler
HTTPSHandler
http_open
HTTPConnection
do_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。
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
看起来名称解析最终由
socket.create_connection
处理。不过,一旦设置了“Host:”头,就可以解析主机并将IP地址向下传递到打开程序。
我建议您对
httplib.HTTPConnection
进行子类划分,并在将其传递给socket.create_connection
之前包装connect
方法以修改self.host
。然后子类
HTTPHandler
(和HTTPSHandler
)将http_open
方法替换为将HTTPConnection
而不是将httplib自己的方法传递给do_open
。像这样:
显然,如果您使用HTTPS,会有证书问题,您需要填写MyResolver。。。
您需要实现自己的dns查找客户机(或者像您所说的那样使用dnspython)。glibc中的名称查找过程非常复杂,以确保与其他非dns名称系统兼容。例如,根本无法在glibc库中指定特定的DNS服务器。
另一种(肮脏的)方法是猴子修补
socket.getaddrinfo
。例如,此代码为dns查找添加了一个(不受限制的)缓存。
相关问题 更多 >
编程相关推荐