Urllib2에 사용자 정의 DNS를 사용하도록 지시하십시오
문제
말하고 싶습니다 urllib2.urlopen
(또는 a 사용자 정의 오프너) 사용 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 이름 시스템과의 호환성을 보장하기 위해 매우 복잡합니다. 예를 들어 GLIBC 라이브러리에 특정 DNS 서버를 지정할 방법이 없습니다.