[英]Use python Urllib, urllib2, or requests to click continue & login
[英]Force python mechanize/urllib2 to only use A requests?
這是一個相關的問題,但我無法弄清楚如何應用mechanize / urllib2的答案: 如何強制python httplib庫只使用A請求
基本上,給出這個簡單的代碼:
#!/usr/bin/python
import urllib2
print urllib2.urlopen('http://python.org/').read(100)
這導致wireshark說以下內容:
0.000000 10.102.0.79 -> 8.8.8.8 DNS Standard query A python.org
0.000023 10.102.0.79 -> 8.8.8.8 DNS Standard query AAAA python.org
0.005369 8.8.8.8 -> 10.102.0.79 DNS Standard query response A 82.94.164.162
5.004494 10.102.0.79 -> 8.8.8.8 DNS Standard query A python.org
5.010540 8.8.8.8 -> 10.102.0.79 DNS Standard query response A 82.94.164.162
5.010599 10.102.0.79 -> 8.8.8.8 DNS Standard query AAAA python.org
5.015832 8.8.8.8 -> 10.102.0.79 DNS Standard query response AAAA 2001:888:2000:d::a2
這是一個5秒的延遲 !
我的系統中沒有啟用IPv6(用USE=-ipv6
編譯的gentoo)所以我不認為python有任何理由甚至嘗試IPv6查找。
上面提到的問題建議明確地將套接字類型設置為AF_INET
,這聽起來很棒。 我不知道如何強制urllib或機械化使用我創建的任何套接字。
編輯 :我知道AAAA查詢是問題,因為其他應用程序也有延遲,一旦我禁用ipv6重新編譯,問題就消失了......除了仍在執行AAAA請求的python中。
遇到同樣的問題,根據JJ提供的信息,這是一個丑陋的黑客(使用風險自負......)。
這基本上強制socket.getaddrinfo(..)
的family
參數為socket.AF_INET
而不是使用socket.AF_UNSPEC
(零,這似乎是在socket.create_connection
使用的),不僅適用於來自urllib2
調用,而且應該這樣做對於所有對socket.getaddrinfo(..)
調用:
#--------------------
# do this once at program startup
#--------------------
import socket
origGetAddrInfo = socket.getaddrinfo
def getAddrInfoWrapper(host, port, family=0, socktype=0, proto=0, flags=0):
return origGetAddrInfo(host, port, socket.AF_INET, socktype, proto, flags)
# replace the original socket.getaddrinfo by our version
socket.getaddrinfo = getAddrInfoWrapper
#--------------------
import urllib2
print urllib2.urlopen("http://python.org/").read(100)
至少在這個簡單的情況下,這對我有用。
沒有答案,但有一些數據點。 DNS解析似乎來自HTTPConnection.connect()
httplib.py
HTTPConnection.connect()
我的python 2.5.4 stdlib上的第670行)
代碼流大致是:
for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
self.sock = socket.socket(af, socktype, proto)
try:
self.sock.connect(sa)
except socket.error, msg:
continue
break
關於發生了什么的一些評論:
socket.getaddrinfo()
的第三個參數限制套接字系列 - 即IPv4與IPv6。 傳遞零返回所有家庭。 零被硬編碼到stdlib中。
將主機名傳遞給getaddrinfo()
將導致名稱解析 - 在啟用了IPv6的OS X框中,A和AAAA記錄都會消失,兩個答案都會立即返回並返回。
連接循環的其余部分嘗試每個返回的地址,直到一個成功
例如:
>>> socket.getaddrinfo("python.org", 80, 0, socket.SOCK_STREAM)
[
(30, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0)),
( 2, 1, 6, '', ('82.94.164.162', 80))
]
>>> help(socket.getaddrinfo)
getaddrinfo(...)
getaddrinfo(host, port [, family, socktype, proto, flags])
-> list of (family, socktype, proto, canonname, sockaddr)
一些猜測:
由於getaddrinfo()
的套接字系列硬編碼為零,因此您將無法通過urllib中的某些受支持的API接口覆蓋A與AAAA記錄。 除非機械化由於某些其他原因而自行解析名稱,否則機械化也不能。 從連接循環的構造,這是By Design。
python的套接字模塊是一個圍繞POSIX套接字API的瘦包裝器; 我希望他們能夠解決系統上所有可用和配置的系列。 仔細檢查Gentoo的IPv6配置。
當被問及python.org的AAAA時,DNS服務器8.8.8.8(谷歌DNS)立即回復。 因此,我們在您發布的跟蹤中沒有看到此回復的事實可能表明該數據包沒有返回(這發生在UDP中)。 如果這種損失是隨機的,那是正常的。 如果它是系統的,則表示您的網絡設置存在問題,可能是防火牆損壞,導致第一個AAAA回復無法恢復。
5秒延遲來自您的存根解析器。 在這種情況下,如果它是隨機的,那可能是運氣不好,但與IPv6無關,A記錄的回復也可能失敗。
在最后一個IPv4地址分發前兩年,禁用IPv6似乎是一個非常奇怪的舉動!
% dig @8.8.8.8 AAAA python.org
; <<>> DiG 9.5.1-P3 <<>> @8.8.8.8 AAAA python.org
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50323
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;python.org. IN AAAA
;; ANSWER SECTION:
python.org. 69917 IN AAAA 2001:888:2000:d::a2
;; Query time: 36 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Jan 9 21:51:14 2010
;; MSG SIZE rcvd: 67
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.