Frage

Ich möchte urllib2.urlopen sagen (oder ein benutzerdefinierte Opener ) verwenden 127.0.0.1 (oder ::1) zu lösen Adressen. Ich würde nicht meinen /etc/resolv.conf jedoch ändern.

Eine mögliche Lösung ist ein Tool wie dnspython zu Abfrage-Adressen zu verwenden und httplib eine benutzerdefinierte URL Opener zu bauen. Ich würde es vorziehen urlopen sagte wenn einen benutzerdefinierten Name-Server zu verwenden. Irgendwelche Vorschläge?

War es hilfreich?

Lösung

Sieht aus wie Namensauflösung letztlich von socket.create_connection behandelt wird.

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

Auch wenn einmal der „Host“. Header gesetzt wurde, können Sie den Host beheben und geben die IP-Adresse durch bis auf den Öffner

Ich würde vorschlagen, dass Sie Unterklasse httplib.HTTPConnection und wickeln Sie die connect Methode self.host zu ändern, bevor es zu socket.create_connection vorbei.

Dann Unterklasse HTTPHandler (und HTTPSHandler) die http_open Methode mit einer ersetzen, die Ihren HTTPConnection gehen statt httplib eigenen zu do_open.

Wie folgt aus:

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

Natürlich gibt es Zertifikat Fragen, wenn Sie die HTTPS verwenden, und Sie werden MyResolver füllen müssen aus ...

Andere Tipps

Ein weiterer (dirty) Weg ist affen Patchen socket.getaddrinfo.

Zum Beispiel dieses Code fügt eine (unbegrenzt) Cache für DNS-Lookups.

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

Sie müssen Ihre eigenen DNS-Lookup-Client (oder mit dnspython wie Sie gesagt haben) implementieren. Die Namenssuche Verfahren in glibc sind ziemlich komplex Kompatibilität mit anderen Nicht-DNS-Namen-Systemen zu gewährleisten. Es gibt zum Beispiel keine Möglichkeit, einen bestimmten DNS-Server in der glibc-Bibliothek überhaupt angeben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top