如何設置Python和urllib2的源IP /接口?Python和urllib2的源接口
回答
不幸的是,使用中的標準庫模塊(urllib2,httplib,socket)的堆棧設計有點糟糕 - 在操作的關鍵點,HTTPConnection.connect
(在httplib中)代表socket.create_connection
,這反過來給出你在創建套接字實例sock
和sock.connect
調用之間沒有任何「掛鉤」,因爲你需要在sock.connect
之前插入sock.bind
,這就是你需要設置源IP的條件(我在爲這樣的設計抽象而廣泛傳播福音一種密封的,過度封裝的方式 - 我將在本週四在OSCON上以「禪和抽象維護的藝術」爲題談論這個問題 - 但在這裏你的問題是如何處理一堆抽象,這樣,嘆了口氣)。
當您遇到這樣的問題時,您只有兩個不太好的解決方案:複製,粘貼和編輯錯誤設計的代碼,您需要在其中放置一個原始設計人員無法滿足的「掛鉤」 ;或者,「猴子補丁」那個代碼。兩者都不是好的,但都可以工作,所以至少讓我們感謝我們有這樣的選擇(通過使用開源和動態語言)。在這種情況下,我想我會去猴修補(這是不好的,但複製和粘貼編碼更差) - 一個代碼片段如:
import socket
true_socket = socket.socket
def bound_socket(*a, **k):
sock = true_socket(*a, **k)
sock.bind((sourceIP, 0))
return sock
socket.socket = bound_socket
根據您的實際需要(做您需要將所有套接字綁定到相同的源IP上,或者......?)您可以在正常使用urllib2
之前運行此操作,或者(當然,更復雜的方式)只需要爲需要的那些出站套接字運行它以某種方式進行綁定(然後每次恢復socket.socket = true_socket
以避免未來的套接字尚未創建)。第二種選擇會增加自己的複雜性以適當地協調,所以我在等待你澄清在你解釋所有事情之前你是否需要這樣的複雜情況。
AKX的好答案是「複製/粘貼/編輯」替代方案中的一個變種,因此我不需要在這方面進行太多的擴展 - 但請注意,它並不完全在其connect
方法中重現socket.create_connection
,請參閱源here(位於頁面的最後),並決定如果您決定轉到該路由,您可能希望在複製/粘貼/編輯的版本中體現create_connection
函數的其他功能。
這似乎工作。
import urllib2, httplib, socket
class BindableHTTPConnection(httplib.HTTPConnection):
def connect(self):
"""Connect to the host and port specified in __init__."""
self.sock = socket.socket()
self.sock.bind((self.source_ip, 0))
if isinstance(self.timeout, float):
self.sock.settimeout(self.timeout)
self.sock.connect((self.host,self.port))
def BindableHTTPConnectionFactory(source_ip):
def _get(host, port=None, strict=None, timeout=0):
bhc=BindableHTTPConnection(host, port=port, strict=strict, timeout=timeout)
bhc.source_ip=source_ip
return bhc
return _get
class BindableHTTPHandler(urllib2.HTTPHandler):
def http_open(self, req):
return self.do_open(BindableHTTPConnectionFactory('127.0.0.1'), req)
opener = urllib2.build_opener(BindableHTTPHandler)
opener.open("http://google.com/").read() # Will fail, 127.0.0.1 can't reach google.com.
不過,您需要弄清楚某種方式來參數化「127.0.0.1」。
這個完美的作品!非常感謝。 – 2010-10-05 23:33:30
@DaveRawks:你在哪個系統中獲得成功?我無法綁定Windows 7中的網絡接口。 – 2013-01-27 12:25:26
代碼適用於Linux和OSX上的我。我從來沒有在Windows上編寫過套接字代碼,但我懷疑在用戶空間中缺少原始套接字可能會導致問題。 – 2013-02-04 22:39:35
我以爲我會跟進一個稍微好一點的猴子補丁版本。如果您需要能夠在某些套接字上設置不同的端口選項,或者使用類似套接字的SSL之類的代碼,則以下代碼的效果會更好一些。
_ip_address = None
def bind_outgoing_sockets_to_ip(ip_address):
"""This binds all python sockets to the passed in ip address"""
global _ip_address
_ip_address = ip_address
import socket
from socket import socket as s
class bound_socket(s):
def connect(self, *args, **kwargs):
if self.family == socket.AF_INET:
if self.getsockname()[0] == "0.0.0.0" and _ip_address:
self.bind((_ip_address, 0))
s.connect(self, *args, **kwargs)
socket.socket = bound_socket
你必須只能綁定在連接插座,如果你需要運行像在需要綁定到不同的IP地址相同的過程Web服務器。
推理,我應該猴子補丁在可用的最高級別,這裏是亞歷克斯的答案替代哪些補httplib
,而不是socket
,趁着httplib.HTTPSConnection.__init__()
的source_address
關鍵字參數(這不是由urllib2
,AFAICT暴露)的。經過測試並正在使用Python 2.7.2。
import httplib
HTTPSConnection_real = httplib.HTTPSConnection
class HTTPSConnection_monkey(HTTPSConnection_real):
def __init__(*a, **kw):
HTTPSConnection_real.__init__(*a, source_address=(SOURCE_IP, 0), **kw)
httplib.HTTPSConnection = HTTPSConnection_monkey
這裏有一個進一步的細化,使得使用的HTTPConnection's source_address argument(在Python 2.7中引入):
import functools
import httplib
import urllib2
class BoundHTTPHandler(urllib2.HTTPHandler):
def __init__(self, source_address=None, debuglevel=0):
urllib2.HTTPHandler.__init__(self, debuglevel)
self.http_class = functools.partial(httplib.HTTPConnection,
source_address=source_address)
def http_open(self, req):
return self.do_open(self.http_class, req)
這給了我們一個自定義urllib2.HTTPHandler實現,是source_address知道。我們可以用下面的代碼添加到一個新的urllib2.OpenerDirector並安裝爲默認打開程序(用於未來urlopen()電話):
handler = BoundHTTPHandler(source_address=("192.168.1.10", 0))
opener = urllib2.build_opener(handler)
urllib2.install_opener(opener)
對於Python 2.7 httplib.HTTPConnection有source_address添加進去,讓您提供要綁定的IP端口對。
請參閱:http://docs.python.org/2/library/httplib.html#httplib.HTTPConnection
- 1. python urllib2和unicode
- 2. Python,Urllib2和Openers
- 3. 使用python 2.7和urllib2連接到API
- 4. 蟒蛇捲曲的urllib2源接口地址
- 5. Python的 - 的urllib2和urllib的
- 6. Urllib2.urlopen窗口中的Python中文
- 7. 使用Python和的urllib2如何閱讀源代碼
- 8. 與Python的urllib2
- 9. 使用Python的urllib2連接網址
- 10. python和arduino的接口
- 11. 的Python的urllib2 + Beautifulsoup
- 12. 的Python的urllib2庫
- 13. 的Python的urllib2與
- 14. urllib2 python等效python
- 15. Python的URLLib/URLLib2 POST
- 16. Python urllib2錯誤
- 17. Urllib2 Python錯誤
- 18. python csv linux urllib2
- 19. 使用urllib2 python
- 20. Python mod json + urllib2
- 21. urllib2.HTTPError Python
- 22. Python urllib2 force IPv4
- 23. Python - Heroku urllib2.HTTPError
- 24. Python urllib2錯誤
- 25. python urllib2 return JSON
- 26. Python - 線程和urlopen(urllib2)和解析
- 27. 刪除HTTP「連接」標題,Python urllib2
- 28. 用urllib2和python讀取正確的HTML
- 29. Feedparser(和urllib2的)問題:連接超時
- 30. 使用urllib2和Tor在python中拒絕連接
使用「請求」庫或pycurl是合理的。如果您將它用於非平凡的任務,您總會偶然發現urllib2的糟糕設計。 – HighCat 2012-09-09 11:49:07