如何使用 requests 库从 http 请求中获取 IP 地址?
Posted
技术标签:
【中文标题】如何使用 requests 库从 http 请求中获取 IP 地址?【英文标题】:How do I get the IP address from a http request using the requests library? 【发布时间】:2014-04-24 21:47:56 【问题描述】:我正在使用 python 中的请求库发出 HTTP 请求,但我需要来自响应 HTTP 请求的服务器的 IP 地址,并且我试图避免进行两次调用(并且可能与响应请求的人)。
这可能吗?是否有任何 python HTTP 库允许我这样做?
PS:我还需要发出 HTTPS 请求并使用经过身份验证的代理。
更新 1:
例子:
import requests
proxies =
"http": "http://user:password@10.10.1.10:3128",
"https": "http://user:password@10.10.1.10:1080",
response = requests.get("http://example.org", proxies=proxies)
response.ip # This doesn't exist, this is just an what I would like to do
然后,我想知道响应中的方法或属性连接到哪些 IP 地址请求。在其他库中,我可以通过找到 sock 对象并使用 getpeername()
函数来做到这一点。
【问题讨论】:
“响应的服务器”是模棱两可的,因为在您和实际生成响应的机器之间可能存在各种代理、负载平衡器等。并且一个给定的域名在 DNS 中可能有多个 IP 地址。 【参考方案1】:事实证明,它相当复杂。
这是使用 requests
版本 1.2.3 时的猴子补丁:
将_make_request
方法包装在HTTPConnectionPool
上,以将来自socket.getpeername()
的响应存储在HTTPResponse
实例上。
对于 python 2.7.3 上的我来说,此实例在 response.raw._original_response
上可用。
from requests.packages.urllib3.connectionpool import HTTPConnectionPool
def _make_request(self,conn,method,url,**kwargs):
response = self._old_make_request(conn,method,url,**kwargs)
sock = getattr(conn,'sock',False)
if sock:
setattr(response,'peer',sock.getpeername())
else:
setattr(response,'peer',None)
return response
HTTPConnectionPool._old_make_request = HTTPConnectionPool._make_request
HTTPConnectionPool._make_request = _make_request
import requests
r = requests.get('http://www.google.com')
print r.raw._original_response.peer
产量:
('2a00:1450:4009:809::1017', 80, 0, 0)
啊,如果涉及代理或响应被分块,则不会调用 HTTPConnectionPool._make_request
。
所以这里有一个新版本修补httplib.getresponse
:
import httplib
def getresponse(self,*args,**kwargs):
response = self._old_getresponse(*args,**kwargs)
if self.sock:
response.peer = self.sock.getpeername()
else:
response.peer = None
return response
httplib.HTTPConnection._old_getresponse = httplib.HTTPConnection.getresponse
httplib.HTTPConnection.getresponse = getresponse
import requests
def check_peer(resp):
orig_resp = resp.raw._original_response
if hasattr(orig_resp,'peer'):
return getattr(orig_resp,'peer')
跑步:
>>> r1 = requests.get('http://www.google.com')
>>> check_peer(r1)
('2a00:1450:4009:808::101f', 80, 0, 0)
>>> r2 = requests.get('https://www.google.com')
>>> check_peer(r2)
('2a00:1450:4009:808::101f', 443, 0, 0)
>>> r3 = requests.get('http://wheezyweb.readthedocs.org/en/latest/tutorial.html#what-you-ll-build')
>>> check_peer(r3)
('162.209.99.68', 80)
还检查了设置代理的运行;返回代理地址。
更新 2016/01/19
est 提供an alternative that doesn't need the monkey-patch:
rsp = requests.get('http://google.com', stream=True)
# grab the IP while you can, before you consume the body!!!!!!!!
print rsp.raw._fp.fp._sock.getpeername()
# consume the body, which calls the read(), after that fileno is no longer available.
print rsp.content
更新 2016/05/19
来自 cmets,复制到此处以获取可见性,Richard Kenneth Niescior 提供以下已确认可用于请求 2.10.0 和 Python 3。
rsp=requests.get(..., stream=True)
rsp.raw._connection.sock.getpeername()
更新 2019/02/22
带有请求版本 2.19.1 的 Python3。
resp=requests.get(..., stream=True)
resp.raw._connection.sock.socket.getsockname()
更新 2020/01/31
带有请求 2.22.0 的 Python3.8
resp = requests.get('https://www.google.com', stream=True)
resp.raw._connection.sock.getsockname()
【讨论】:
它不漂亮,但它有效。谢谢!这帮助很大! 很好的解决方案:谢谢。我遇到了 HTTPS 连接问题:“WrappedSocket”对象没有 getpeername() 方法。我最终在 self.sock.socket 上找到了该方法,因此两步尝试/除了 self.sock.getpeername() 然后 self.sock.socket.getpeername() 为我完成了这项工作:处理我的网络监视器服务. 我刚需要这个,我发现rsp=requests.get(..., stream=True);rsp.raw._connection.sock.getpeername()
有效。我有requests 2.10.0
并且正在使用 Python 3
现在似乎是resp.raw._connection.sock.socket.getsockname()
,请求版本为“2.19.1”。请注意,在我的例子中,resp.raw._connection.sock
的类型是 urllib3.contrib.pyopenssl.WrappedSocket
。
@MattH getsockname()
是本地名称,getpeername()
是远程名称,您在回复中将两者与更新混在一起。【参考方案2】:
试试:
import requests
proxies =
"http": "http://user:password@10.10.1.10:3128",
"https": "http://user:password@10.10.1.10:1080",
response = requests.get('http://jsonip.com', proxies=proxies)
ip = response.json()['ip']
print('Your public IP is:', ip)
【讨论】:
这很好,但是当尝试获取本地和/或远程 ip 时,当使用请求的 99.9% 的人会这样做时,它是如何工作的?当您测试基本代码时,这适用于测试环境。但在生产中,你永远不会这样做。以上是关于如何使用 requests 库从 http 请求中获取 IP 地址?的主要内容,如果未能解决你的问题,请参考以下文章
servlet如何利用request来获取http请求中的主体信息?
servlet如何利用request来获取http请求中的主体信息?
如何在 Django 1.6 中使用 HTTP POST 请求接收 json 数据?