Pergunta

Eu gostaria de dizer urllib2.urlopen (ou um costume abridor ) para usar 127.0.0.1 (ou ::1) para endereços resolver. Eu não mudaria meu /etc/resolv.conf, no entanto.

Uma possível solução é usar uma ferramenta como dnspython para endereços de consulta e httplib para construir um abridor url personalizada. Eu prefiro dizer urlopen usar um servidor de nomes costume embora. Alguma sugestão?

Foi útil?

Solução

Looks como resolução de nomes é finalmente tratada por socket.create_connection.

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

Embora uma vez que o "anfitrião". Cabeçalho tiver sido definida, você pode resolver o anfitrião e passar o endereço IP através de até o abridor

Eu sugiro que você subclasse httplib.HTTPConnection, e enrole o método connect para modificar self.host antes de passá-lo para socket.create_connection.

Então HTTPHandler subclasse (e HTTPSHandler) para substituir o método http_open com um que passa seu HTTPConnection vez de httplib própria para do_open.

Como esta:

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

Obviamente, existem problemas de certificado se você usar o HTTPS, e você precisa preencher MyResolver ...

Outras dicas

Outro (sujo) maneira é socket.getaddrinfo-remendar macaco.

Por exemplo, este código adiciona um cache (ilimitado) para Pesquisas de 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

Você precisará implementar cliente suas próprias Pesquisa de DNS (ou usando dnspython como você disse). O procedimento de pesquisa de nome na glibc é muito complexa para garantir a compatibilidade com outros sistemas de nomes não-DNS. Há, por exemplo, nenhuma maneira de especificar um servidor DNS em particular na biblioteca glibc em tudo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top