أخبر Urllib2 لاستخدام DNS مخصص
سؤال
أود أن أقول urllib2.urlopen
(أو أ. فتاحة مخصصة) ليستخدم 127.0.0.1
(أو ::1
) لحل العناوين. لن أغير بلدي /etc/resolv.conf
, ، ومع ذلك.
حل واحد ممكن هو استخدام أداة مثل dnspython
لاستعلام عناوين و httplib
لبناء فتاحة URL مخصصة. كنت أفضل القول urlopen
لاستخدام مخطط الأسماء العرف رغم ذلك. أي اقتراحات؟
المحلول
يبدو أن حل الاسم يتم التعامل معه في نهاية المطاف بواسطة socket.create_connection
.
-> urllib2.urlopen
-> httplib.HTTPConnection
-> socket.create_connection
على الرغم من أنه بمجرد تعيين رأس "المضيف:"، يمكنك حل المضيف وتمرير عنوان IP من خلال الفتح.
أود أن أقترح عليك فرعية httplib.HTTPConnection
, ولف لف connect
طريقة لتعديل self.host
قبل اجتيازها socket.create_connection
.
ثم الفئة الفرعية HTTPHandler
(و HTTPSHandler
) ليحل محل http_open
طريقة مع واحد يمر بك HTTPConnection
بدلا من httplib الخاصة ل do_open
.
مثله:
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 ...
نصائح أخرى
طريقة أخرى (قذرة) هي الترقيع القرد socket.getaddrinfo
.
على سبيل المثال، يضيف هذا الرمز ذاكرة تخزين مؤقت (غير محدود) بحث 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
ستحتاج إلى تطبيق عميل بحث DNS الخاص بك (أو استخدام DNSPYTHON كما قلت). إن إجراء بحث الاسم في Glibc معقدة للغاية لضمان التوافق مع أنظمة أسماء DNS الأخرى. لا يوجد أي طريقة لتحديد خادم DNS معين في مكتبة Glibc على الإطلاق.