Pregunta

Me gustaría decirle urllib2.urlopen (o un costumbre abridor ) para utilizar 127.0.0.1 (o ::1) para resolver las direcciones. No cambiaría mi /etc/resolv.conf, sin embargo.

Una posible solución es utilizar una herramienta como dnspython para consultar direcciones y httplib para construir un abridor de URL personalizada. Yo prefiero decir urlopen utilizar un servidor de nombres de encargo sin embargo. ¿Alguna sugerencia?

¿Fue útil?

Solución

Parece que la resolución de nombres es en última instancia a cargo de socket.create_connection.

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

Aunque una vez que el "Anfitrión:". Cabecera se ha establecido, puede resolver el anfitrión y transmitir la dirección IP a través hasta el abridor

Me gustaría sugerir que httplib.HTTPConnection subclase, y envolver el método connect modificar self.host antes de pasarla a socket.create_connection.

A continuación, HTTPHandler subclase (y HTTPSHandler) para reemplazar el método http_open con uno que pasa a su HTTPConnection en lugar de la propia a do_open httplib.

De esta manera:

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']

Es obvio que hay problemas de certificado si utiliza las HTTPS, y usted necesitará llenar MyResolver ...

Otros consejos

Otra forma (sucio) es socket.getaddrinfo mono-parches.

Por ejemplo, este código añade una memoria caché (ilimitado) para las búsquedas 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

Usted tendrá que implementar su propio cliente de búsqueda de DNS (o usando dnspython como usted ha dicho). El procedimiento de búsqueda de nombre en glibc es bastante complejo para asegurar la compatibilidad con otros sistemas de nombres no DNS. Hay, por ejemplo, no hay manera de especificar un servidor DNS en particular en la biblioteca glibc en absoluto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top