Domanda

Vorrei dirlo urllib2.urlopen (o a apri personalizzato) usare 127.0.0.1 (O ::1) per risolvere gli indirizzi.Non cambierei il mio /etc/resolv.conf, Tuttavia.

Una possibile soluzione è utilizzare uno strumento come dnspython per interrogare indirizzi e httplib per creare un apri URL personalizzato.Preferirei raccontarlo urlopen per utilizzare un server dei nomi personalizzato però.Eventuali suggerimenti?

È stato utile?

Soluzione

Sembra che la risoluzione dei nomi alla fine sia gestita da socket.create_connection.

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

Tuttavia, una volta impostata l'intestazione "Host:", è possibile risolvere l'host e trasmettere l'indirizzo IP all'apriporta.

Suggerirei di creare una sottoclasse httplib.HTTPConnection, e avvolgi il connect metodo da modificare self.host prima di passarlo a socket.create_connection.

Quindi sottoclasse HTTPHandler (E HTTPSHandler) per sostituire il http_open metodo con uno che supera il tuo HTTPConnection invece di quello di httplib to do_open.

Come questo:

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

Ovviamente ci sono problemi con i certificati se usi HTTPS e dovrai compilare MyResolver...

Altri suggerimenti

Un altro modo (sporco) è il patching delle scimmie socket.getaddrinfo.

Ad esempio, questo codice aggiunge una cache (illimitata) per le ricerche 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

Dovrai implementare il tuo client di ricerca DNS (o utilizzare dnspython come hai detto).La procedura di ricerca dei nomi in glibc è piuttosto complessa per garantire la compatibilità con altri sistemi di nomi non DNS.Ad esempio, non esiste alcun modo per specificare un particolare server DNS nella libreria glibc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top