Question

Je voudrais dire urllib2.urlopen (ou un ouvre personnalisée ) pour résoudre les adresses à utiliser 127.0.0.1 (ou ::1). Je ne changerai pas /etc/resolv.conf, cependant.

Une solution possible est d'utiliser un outil comme dnspython pour interroger les adresses et httplib pour construire un ouvre-url personnalisé. Je préfère dire urlopen utiliser un serveur de noms personnalisé bien. Toutes les suggestions?

Était-ce utile?

La solution

On dirait que la résolution de noms est finalement pris en charge par socket.create_connection.

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

Bien qu'une fois le « hôte ». En-tête a été défini, vous pouvez résoudre l'hôte et de transmettre l'adresse IP par le bas à l'ouverture

Je vous suggère que vous sous-classe httplib.HTTPConnection, et envelopper la méthode connect pour modifier self.host avant de passer à socket.create_connection.

Ensuite, la sous-classe HTTPHandler (et HTTPSHandler) pour remplacer la méthode http_open avec celui qui passe votre HTTPConnection au lieu de httplib propre à do_open.

Comme ceci:

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

Évidemment, il y a des problèmes de certificat si vous utilisez le protocole HTTPS, et vous devrez remplir MyResolver ...

Autres conseils

Une autre façon (sale) est socket.getaddrinfo singe ragréage.

Par exemple, ce code ajoute un cache (illimité) pour les recherches 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

Vous devrez implémenter votre propre client de recherche dns (ou en utilisant dnspython comme vous le dites). La procédure de recherche de nom dans glibc est assez complexe pour assurer la compatibilité avec d'autres systèmes de noms non-dns. Il y a par exemple aucun moyen de spécifier un serveur DNS particulier dans la bibliothèque glibc du tout.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top