我想告诉urllib2.urlopen(或自定义开瓶器)使用127.0.0.1(或::1)来解析地址。我不会改变我的/etc/resolv.conf不过来。

一种可能的解决方案是使用一个工具,如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)与一个通过您的http_open代替httplib的自身到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 ...

其他提示

另一个(脏)的方法是猴子修补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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top