我正在编写一些python客户端代码,由于一些环境限制,我希望指定一个URL,并控制它的解析方式。我可以通过使用--解析标志来完成这个任务。有什么方法可以对Python的请求库进行类似的操作吗?
理想情况下,这在Python2.7中是可行的,但我也可以让3.x解决方案工作。
发布于 2017-06-05 21:34:05
在做了一些调查之后,我(毫不奇怪)发现请求通过请求Python来解析主机名(这是要求您的操作系统这样做)。首先,我找到了一些示例代码来劫持DNS解析(告诉urllib2使用自定义DNS),然后我进一步了解了Python如何解析套接字文档中的主机名。然后就是把所有的东西连接在一起:
import socket
import requests
def is_ipv4(s):
# Feel free to improve this: https://stackoverflow.com/questions/11827961/checking-for-ip-addresses
return ':' not in s
dns_cache = {}
def add_custom_dns(domain, port, ip):
key = (domain, port)
# Strange parameters explained at:
# https://docs.python.org/2/library/socket.html#socket.getaddrinfo
# Values were taken from the output of `socket.getaddrinfo(...)`
if is_ipv4(ip):
value = (socket.AddressFamily.AF_INET, 0, 0, '', (ip, port))
else: # ipv6
value = (socket.AddressFamily.AF_INET6, 0, 0, '', (ip, port, 0, 0))
dns_cache[key] = [value]
# Inspired by: https://stackoverflow.com/a/15065711/868533
prv_getaddrinfo = socket.getaddrinfo
def new_getaddrinfo(*args):
# Uncomment to see what calls to `getaddrinfo` look like.
# print(args)
try:
return dns_cache[args[:2]] # hostname and port
except KeyError:
return prv_getaddrinfo(*args)
socket.getaddrinfo = new_getaddrinfo
# Redirect example.com to the IP of test.domain.com (completely unrelated).
add_custom_dns('example.com', 80, '66.96.162.92')
res = requests.get('http://example.com')
print(res.text) # Prints out the HTML of test.domain.com.我在写这篇文章时遇到了一些注意事项:
https来说效果很差。代码运行良好(只需使用https://和443,而不是http://和80)。但是,SSL证书绑定到域名,请求将尝试验证证书上的名称到您试图连接的原始域。getaddrinfo为IPv4和IPv6地址返回稍微不同的信息。我的is_ipv4实现让我觉得很麻烦,如果您在实际应用程序中使用了这个版本,我强烈推荐一个更好的版本。发布于 2020-03-19 05:21:56
一段时间以来,我一直试图想出一个解决办法,终于偶然发现了这篇文章。@ not 654提供的解决方案不适用于我(使用https和python 3.8),但是几天的睡眠使我得到了这个解决方案,不管版本如何(没有对太多版本进行测试,但天真地希望是这样的)。
它也适用于ipv6 --尽管我也没有对它进行测试。
解决方案的关键是对所有调用使用默认的getaddrinfo() (对其输出没有假设)--只需用ip地址替换主机名就可以了!因此,我大张旗鼓地阐述了它的工作效果;-)
import socket
dns_cache = {}
# Capture a dict of hostname and their IPs to override with
def override_dns(domain, ip):
dns_cache[domain] = ip
prv_getaddrinfo = socket.getaddrinfo
# Override default socket.getaddrinfo() and pass ip instead of host
# if override is detected
def new_getaddrinfo(*args):
if args[0] in dns_cache:
print("Forcing FQDN: {} to IP: {}".format(args[0], dns_cache[args[0]]))
return prv_getaddrinfo(dns_cache[args[0]], *args[1:])
else:
return prv_getaddrinfo(*args)
socket.getaddrinfo = new_getaddrinfo要使用上述逻辑,只需在发出请求之前像这样调用函数(您可以使用IP地址或另一个FQDN!):
override_dns('www.example.com', '192.168.1.100')我相信这是一个比我之前使用的ForcedIPHTTPSAdapter更好的解决方案。
发布于 2021-03-05 16:25:37
延迟回答,但有一个名为强制转接器的模块,它正是这样做的:
安装:
pip3 install forcediphttpsadapter用法:
import requests
from forcediphttpsadapter.adapters import ForcedIPHTTPSAdapter
url = 'https://domain.tld/path'
session = requests.Session()
session.mount(url, ForcedIPHTTPSAdapter(dest_ip='x.x.x.x')) # type the desired ip
r = session.get(url, verify=False)
print(r.text)
...资料来源:
https://stackoverflow.com/questions/44374215
复制相似问题