告诉urllib2使用自定义DN

2024-05-16 03:28:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我想告诉urllib2.urlopen(或一个定制的打开程序)使用127.0.0.1(或::1)来解析地址。不过,我不会改变我的/etc/resolv.conf

一种可能的解决方案是使用像dnspython这样的工具来查询地址,以及httplib来构建自定义url打开程序。不过,我更希望告诉urlopen使用自定义名称服务器。有什么建议吗?


Tags: 工具程序服务器名称url地址confetc
3条回答

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

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

不过,一旦设置了“Host:”头,就可以解析主机并将IP地址向下传递到打开程序。

我建议您对httplib.HTTPConnection进行子类划分,并在将其传递给socket.create_connection之前包装connect方法以修改self.host

然后子类HTTPHandler(和HTTPSHandler)将http_open方法替换为将HTTPConnection而不是将httplib自己的方法传递给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

例如,此代码为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

相关问题 更多 >