首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在python的请求库中以类似于curl的-解析标志的方式指定URL解析?

问如何在python的请求库中以类似于curl的-解析标志的方式指定URL解析?
EN

Stack Overflow用户
提问于 2017-06-05 17:16:13
回答 4查看 10.4K关注 0票数 14

我正在编写一些python客户端代码,由于一些环境限制,我希望指定一个URL,并控制它的解析方式。我可以通过使用--解析标志来完成这个任务。有什么方法可以对Python的请求库进行类似的操作吗?

理想情况下,这在Python2.7中是可行的,但我也可以让3.x解决方案工作。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-06-05 21:34:05

在做了一些调查之后,我(毫不奇怪)发现请求通过请求Python来解析主机名(这是要求您的操作系统这样做)。首先,我找到了一些示例代码来劫持DNS解析(告诉urllib2使用自定义DNS),然后我进一步了解了Python如何解析套接字文档中的主机名。然后就是把所有的东西连接在一起:

代码语言:javascript
复制
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实现让我觉得很麻烦,如果您在实际应用程序中使用了这个版本,我强烈推荐一个更好的版本。
  • 这段代码已经在Python 3上进行了测试,但我看不出它为什么不能像Python 2那样工作。
票数 8
EN

Stack Overflow用户

发布于 2020-03-19 05:21:56

一段时间以来,我一直试图想出一个解决办法,终于偶然发现了这篇文章。@ not 654提供的解决方案不适用于我(使用https和python 3.8),但是几天的睡眠使我得到了这个解决方案,不管版本如何(没有对太多版本进行测试,但天真地希望是这样的)。

它也适用于ipv6 --尽管我也没有对它进行测试。

解决方案的关键是对所有调用使用默认的getaddrinfo() (对其输出没有假设)--只需用ip地址替换主机名就可以了!因此,我大张旗鼓地阐述了它的工作效果;-)

代码语言:javascript
复制
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!):

代码语言:javascript
复制
override_dns('www.example.com', '192.168.1.100')

我相信这是一个比我之前使用的ForcedIPHTTPSAdapter更好的解决方案。

票数 7
EN

Stack Overflow用户

发布于 2021-03-05 16:25:37

延迟回答,但有一个名为强制转接器的模块,它正是这样做的:

安装:

代码语言:javascript
复制
pip3 install forcediphttpsadapter

用法:

代码语言:javascript
复制
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)
...

资料来源:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44374215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档