2010-02-10 19 views
13

उपयोग करने के लिए मैं urllib2.urlopen बताना चाहूँगा (या एक कस्टम सलामी बल्लेबाज) पतों को हल करने 127.0.0.1 (या ::1) का उपयोग करें। हालांकि, मैं अपना /etc/resolv.conf नहीं बदलूंगा।बताएँ urllib2 कस्टम DNS

एक संभावित समाधान है कि dnspython जैसे टूल का उपयोग करें और httplib कस्टम यूआरएल ओपनर बनाने के लिए। हालांकि कस्टम नेमसर्वर का उपयोग करने के लिए मैं urlopen बताना पसंद करूंगा। कोई सुझाव?

उत्तर

20

ऐसा लगता है कि नाम संकल्प अंततः socket.create_connection द्वारा संभाला जाता है।

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

हालांकि एक बार "मेजबान:" शीर्षक निर्धारित किया गया है, तो आप मेजबान को हल करने और सलामी बल्लेबाज के लिए नीचे के माध्यम से आईपी पते पर पारित कर सकते हैं।

मैं सुझाव देंगे कि आप उपवर्ग httplib.HTTPConnection, और connect विधि लपेट यह socket.create_connection को पार करने से पहले self.host संशोधित करने के लिए।

फिर एक है कि अपने HTTPConnection बजाय httplib के स्वयं के do_open गुजरता साथ http_open विधि को बदलने के लिए HTTPHandler (और HTTPSHandler) उपवर्ग।

इस तरह

:

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

जाहिर है प्रमाणपत्र मुद्दों यदि आप HTTPS का उपयोग करें, और आप MyResolver बाहर भरने की आवश्यकता होगी रहे हैं ...

+0

मुझे नहीं लगता कि मुझे अब के लिए HTTPS की आवश्यकता होगी, इसलिए यह पूरी तरह से पर्याप्त होगा! आपका बहुत बहुत धन्यवाद! –

+0

'HTTPConnection._create_connection' को ओवरराइड करना भी संभव है, जो http://bugs.python.org/issue7776 के कारण पायथन 2.7.7 और 3.5 के बाद उपलब्ध है। –

0

आप अपनी खुद की DNS लुकअप को लागू करने की आवश्यकता होगी क्लाइंट (या जैसा आपने कहा था dnspython का उपयोग कर)। ग्लिब में नाम लुकअप प्रक्रिया अन्य गैर-डीएनएस नाम प्रणालियों के साथ संगतता सुनिश्चित करने के लिए बहुत जटिल है। उदाहरण के लिए glibc लाइब्रेरी में एक विशेष DNS सर्वर निर्दिष्ट करने का कोई तरीका नहीं है।

16

एक और (गंदे) तरीका बंदर-पैचिंग socket.getaddrinfo है।

उदाहरण के लिए यह कोड डीएनएस लुकअप के लिए एक (असीमित) कैश जोड़ता है।

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 
+2

इस हैक का एक फायदा भी पाइथन में लगभग सभी डीएनएस लुकअप को रोकता है, न केवल 'urlopen' –

+0

के माध्यम से, यदि मेजबान छोटी संख्या में स्कॉप्ड होते हैं तो यह एक बेहतर समाधान है। मेरे पास 10 एक्स की गति है। :) –