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

发布于 2021-01-29 19:36:49

我正在使用python中的请求库发出HTTP请求,但我需要来自响应http请求的服务器的IP地址,因此,我试图避免进行两次调用(可能与响应的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地址请求连接到了。在其他库中,我可以通过找到袜子对象并使用getpeername()方法来做到这一点。

关注者
0
被浏览
173
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    事实证明,它涉及其中。

    这是使用requests1.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提供了不需要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

    从评论中复制到此处以提高可见性,Richard KennethNiescior提供了以下已确认可用于请求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()
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看