omi*_*nug 8 python python-requests
如何强制requests库使用特定的Internet协议版本来获取get请求?或者这可以通过Python中的另一种方法更好地实现?我可以,但我不想用curl...
澄清目的的例子:
import requests
r = requests.get('https://my-dyn-dns-service.domain/?hostname=my.domain',
auth = ('myUserName', 'my-password'))
Run Code Online (Sandbox Code Playgroud)
Ker*_*ley 25
您可以使用此 hack 来强制requests使用 IPv4:
requests.packages.urllib3.util.connection.HAS_IPV6 = False
Run Code Online (Sandbox Code Playgroud)
(这是 Nulano 作为评论提交的,我认为它应该是一个正确的答案)。
小智 7
我发现了一种强制urrlib3使用ipv4或ipv6的简约解决方案。urrlib3使用此方法为Http和Https创建新连接。您可以在其中指定要使用的任何AF_FAMILY。
import socket
import requests.packages.urllib3.util.connection as urllib3_cn
def allowed_gai_family():
"""
https://github.com/shazow/urllib3/blob/master/urllib3/util/connection.py
"""
family = socket.AF_INET
if urllib3_cn.HAS_IPV6:
family = socket.AF_INET6 # force ipv6 only if it is available
return family
urllib3_cn.allowed_gai_family = allowed_gai_family
Run Code Online (Sandbox Code Playgroud)
我已经为requests+ urllib3+编写了一个运行时补丁socket,允许根据每个请求选择性地传递所需的地址族。
与其他解决方案不同,不涉及猴子修补,而是requests用修补的文件替换导入,并且它提供了一个request兼容的接口,其中所有公开的类都被子类化和修补,并且所有 \xe2\x80\x9csimple API\xe2\x80\x9d 函数都被重新实现。唯一明显的区别应该是存在一个额外的family参数,您可以使用它来将名称解析过程中使用的地址族限制为socket.AF_INET或socket.AF_INET6。然后,使用一系列有点复杂(但大多只是 LoC 密集型)的策略方法覆盖来将该值一直传递到底层,以便urllib3在函数调用的替代实现中使用该值socket.create_connection。
TL;DR用法如下:
\n\nimport socket\n\nfrom . import requests_wrapper as requests # Use this load the patch\n\n\n# This will work (if IPv6 connectivity is available) \xe2\x80\xa6\nrequests.get("http://ip6only.me/", family=socket.AF_INET6)\n# \xe2\x80\xa6 but this won\'t\nrequests.get("http://ip6only.me/", family=socket.AF_INET)\n\n# This one will fail as well\nrequests.get("http://127.0.0.1/", family=socket.AF_INET6)\n\n# This one will work if you have IPv4 available\nrequests.get("http://ip6.me/", family=socket.AF_INET)\n\n# This one will work on both IPv4 and IPv6 (the default)\nrequests.get("http://ip6.me/", family=socket.AF_UNSPEC)\nRun Code Online (Sandbox Code Playgroud)\n\n补丁库的完整链接(~350 LoC): https: //gitlab.com/snippets/1900824
\n小智 5
这是一个hack,但是您可以monkey-patch getaddrinfo来仅过滤IPv4地址:
# Monkey patch to force IPv4, since FB seems to hang on IPv6
import socket
old_getaddrinfo = socket.getaddrinfo
def new_getaddrinfo(*args, **kwargs):
responses = old_getaddrinfo(*args, **kwargs)
return [response
for response in responses
if response[0] == socket.AF_INET]
socket.getaddrinfo = new_getaddrinfo
Run Code Online (Sandbox Code Playgroud)
这完全未经测试,可能需要一些调整,但是结合使用 Python \xe2\x80\x9crequests\xe2\x80\x9d 与现有套接字连接以及如何强制 python httplib 库仅使用 A requests 的答案,看起来像你应该能够创建一个仅 IPv6 的套接字,然后让请求将其用于其连接池,如下所示:
\n\ntry:\n from http.client import HTTPConnection\nexcept ImportError:\n from httplib import HTTPConnection\n\nclass MyHTTPConnection(HTTPConnection):\n def connect(self):\n print("This actually called called")\n self.sock = socket.socket(socket.AF_INET6)\n self.sock.connect((self.host, self.port,0,0))\n if self._tunnel_host:\n self._tunnel()\n\nrequests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection\nRun Code Online (Sandbox Code Playgroud)\n