Python 如何使用请求库从 http 请求中获取 IP 地址?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22492484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:03:14  来源:igfitidea点击:

How do I get the IP address from a http request using the requests library?

pythonpython-requestspycurlhttplibhttplib2

提问by gawry

I am making HTTP requests using the requests library in python, but I need the ip address from the server that responded the http request and I'm trying to avoid to make two calls (and possibly having a different ip address from the one that responded the request.

我正在使用 python 中的请求库发出 HTTP 请求,但我需要来自响应 http 请求的服务器的 IP 地址,并且我试图避免进行两次调用(并且可能与响应的 IP 地址不同请求。

Is that possible? Does any python http library allows me to do that?

那可能吗?是否有任何 python http 库允许我这样做?

ps: I also need to make HTTPS requests and to use an authenticated proxy.

ps:我还需要发出 HTTPS 请求并使用经过身份验证的代理。

Update 1:

更新 1:

Example:

例子:

import requests

proxies = {
  "http": "http://user:[email protected]:3128",
  "https": "http://user:[email protected]: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

then, I would like to know to which IP address requests connected from a method or property in the response. In other libraries I was able to do that by finding the sock object and using the getpeername() method.

然后,我想知道响应中的方法或属性连接到哪些 IP 地址请求。在其他库中,我可以通过找到 sock 对象并使用 getpeername() 方法来做到这一点。

采纳答案by MattH

It turns out that it's rather involved.

事实证明,它相当复杂。

Here's a monkey-patch while using requestsversion 1.2.3:

这是使用requests1.2.3 版时的猴子补丁:

Wrapping the _make_requestmethod on HTTPConnectionPoolto store the response from socket.getpeername()on the HTTPResponseinstance.

缠绕_make_request方法上HTTPConnectionPool存储从响应socket.getpeername()HTTPResponse实例。

For me on python 2.7.3, this instance was available on response.raw._original_response.

对于我在 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

Yields:

产量:

('2a00:1450:4009:809::1017', 80, 0, 0)


Ah, if there's a proxy involved or the response is chunked, the HTTPConnectionPool._make_requestisn't called.

啊,如果涉及代理或响应分块,HTTPConnectionPool._make_request则不会调用。

So here's a new version patching httplib.getresponseinstead:

所以这里有一个新版本的补丁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')

Running:

跑步:

>>> 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)

Also checked running with proxies set; proxy address is returned.

还检查了在设置代理的情况下运行;返回代理地址。



Update2016/01/19

更新2016/01/19

estoffers an alternative that doesn't need the monkey-patch:

est提供了一种不需要猴子补丁的替代方案

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  


Update2016/05/19

更新2016/05/19

From the comments, copying here for visibility, Richard Kenneth Niescioroffers the following that is confirmed working with requests 2.10.0 and Python 3.

从评论中复制到此处以获得可见性,Richard Kenneth Niescior提供了以下已确认可用于请求 2.10.0 和 Python 3 的内容。

rsp=requests.get(..., stream=True)
rsp.raw._connection.sock.getpeername()


Update2019/02/22

更新2019/02/22

Python3 with requests version 2.19.1.

带有请求版本 2.19.1 的 Python3。

resp=requests.get(..., stream=True)
resp.raw._connection.sock.socket.getsockname()


Update2020/01/31

更新2020/01/31

Python3.8 with requests 2.22.0

带有请求 2.22.0 的 Python3.8

resp = requests.get('https://www.google.com', stream=True)
resp.raw._connection.sock.getsockname()