Python中如何使用Requests库设置自定义DNS解析
是这样,我为了练手写了一个 Pixiv 爬虫,主体写完以后准备加上 HTTP 代理,然后突然想起前段时间 Pixiv 已经被墙了,不过只是 DNS 污染而已,我本地改了 DNS 所以没问题。 可是当我要使用国内代理的时候,这个墙就会是问题了对吧?所以能否让 Requests 使用本地设置的 DNS 解析,然后再把请求丢给代理呢? 当然也可以用国外的代理,不过感觉要找个能用的国外代理不容易,速度也是问题。。。 或者有其他方法嘛?
Python中如何使用Requests库设置自定义DNS解析
可以考虑用 IP 连接,然后设置一下 Host。
在Python的requests库中设置自定义DNS解析,最直接的方法是结合requests和httpx库的底层能力,或者使用aiohttp。这里给你一个最实用的方案。
核心原理:修改操作系统的hosts文件映射,或者使用支持自定义DNS解析器的HTTP客户端。
方法一:使用requests + urllib3的底层控制(推荐)
requests库基于urllib3。你可以自定义一个urllib3的连接池,为其绑定一个能解析特定域名的自定义Resolver。但更常见的做法是直接劫持HTTP请求的URL,或者使用hosts文件覆盖。
下面是一个通过安装requests-toolbelt和修改HTTPAdapter来实现的示例:
import requests
from requests_toolbelt.adapters.source import SourceAddressAdapter
from urllib3 import PoolManager
import socket
class CustomDNSResolver(PoolManager):
"""自定义DNS解析的PoolManager"""
def __init__(self, host_map, *args, **kwargs):
self.host_map = host_map # 映射字典,如 {'example.com': '93.184.216.34'}
super().__init__(*args, **kwargs)
def _new_conn(self):
"""创建新连接时,如果host在映射中,则使用映射的IP"""
# 这里简化处理,实际需重写更底层的方法
# 更完整的实现需要修改urllib3的connectionpool
pass
# 更实用的方法:使用requests的hooks或直接修改URL
def dns_hook(response, *args, **kwargs):
"""一个hook示例,但无法在请求发送前修改DNS"""
pass
# 最直接的方法:使用IP地址并设置Host头
def request_with_custom_dns():
target_ip = '93.184.216.34' # example.com的真实IP
url = f'http://{target_ip}/path'
headers = {'Host': 'example.com'} # 关键:设置Host头
response = requests.get(url, headers=headers)
print(response.status_code)
print(response.text[:200])
if __name__ == '__main__':
request_with_custom_dns()
方法二:使用httpx库(支持异步,更现代)
httpx库原生支持自定义DNS解析,通过transport参数:
import httpx
import asyncio
async def custom_dns_request():
# 定义DNS覆盖映射
transport = httpx.AsyncHTTPTransport(
limits=httpx.Limits(max_connections=100),
retries=2,
# 使用自定义的DNS解析函数
# 注意:这里需要自己实现一个resolver
)
# 更简单的方法:使用httpx的client mount,覆盖特定域名
async with httpx.AsyncClient() as client:
# 方法:直接替换URL中的域名为IP,并设置Host头
url = 'http://93.184.216.34/path'
headers = {'Host': 'example.com'}
resp = await client.get(url, headers=headers)
print(resp.status_code)
# asyncio.run(custom_dns_request())
方法三:修改系统hosts(临时方案)
对于临时测试,可以直接修改hosts文件,但这不是编程解决方案:
import subprocess
import platform
def add_hosts_entry(hostname, ip):
"""临时添加hosts条目(需要管理员权限)"""
if platform.system() == 'Windows':
hosts_path = r'C:\Windows\System32\drivers\etc\hosts'
else:
hosts_path = '/etc/hosts'
entry = f'{ip}\t{hostname}\n'
with open(hosts_path, 'a') as f:
f.write(entry)
print(f'Added: {hostname} -> {ip}')
总结
最可靠的方法还是用IP发起请求并设置Host头。如果必须用requests库,可以这样封装:
import requests
class CustomDNSRequest:
def __init__(self, dns_map=None):
self.dns_map = dns_map or {}
def get(self, url, **kwargs):
# 解析URL,替换域名
from urllib.parse import urlparse
parsed = urlparse(url)
if parsed.hostname in self.dns_map:
new_ip = self.dns_map[parsed.hostname]
# 重建URL使用IP
new_netloc = new_ip if parsed.port is None else f'{new_ip}:{parsed.port}'
new_url = parsed._replace(netloc=new_netloc).geturl()
# 设置Host头
headers = kwargs.get('headers', {})
headers['Host'] = parsed.hostname
kwargs['headers'] = headers
url = new_url
return requests.get(url, **kwargs)
# 使用示例
client = CustomDNSRequest({'example.com': '93.184.216.34'})
resp = client.get('http://example.com/path')
一句话建议:用IP请求并设置Host头是最简单直接的方法。
最简单的方式你改一下 hosts 啊…
像这样?
requests.get(‘http://123.125.114.144’,headers={‘Host’:‘www.baidu.com’})
直接用国外的 VPS,写个爬虫,爬下国外的代理,然后用代理池呗。不一定非要在本机搞呀
说实话只要和 Web 相关的强烈建议先去看看 HTTP 协议的相关书籍或者 RFC。
域名在 Client 的作用是通过 DNS 解析到 Server 的 IP,但是请求需要在 Host 头中带上域名,实际请求还是发送到 IP 的。
举个例子:
GET /foo.php HTTP/1.1
Host: example.com
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: /
基于这个过程有两种方法来解决:
第一:基于系统环境解决。
修改本地 Host、指定 DNS
第二:自己构造请求。
这种方法需要可以自定义请求的 Host 头,并且需要自己处理解析这块。可以选择硬编码 IP 或者还是采用第一种方法实现。
可以先使用硬编码 IP 的方式来尝试一下,剩下的就是要确认使用的请求库能否支持自定义 Host 头了。
如果想进一步解决硬编码 IP 的问题,那么就需要一个 DNS 的库来获得正确的解析记录,再来发起请求。
剩下的问题就可能出在 HTTPS 上,因为证书校验是需要靠域名校验的,client 处理的方式细节不同通过 IP 发起请求可能会出现证书校验错误,粗暴的方法就是无视证书错误。
非常感谢!已下单《计算机网络:自顶向下方法》,准备好好学一波
改 hosts 有想到过,不过考虑到 cdn 的问题不知道能不能成功,这方面了解的太少了,明天试试。谢谢回复!
也是个法子~之前考虑的是能写好打包给同学用用,只是他们不一定有 VPS。
个人觉得对 Web 开发来说专注应用层性价比更高一些,当然有兴趣就随意了。
时间多个人推荐《 HTTP 权威指南》,时间有限可以看看《图解 HTTP 》。
好的,主要是计算机三级还没考,准备顺便学一波来着
我说的是改 HTTP Header 里面的 Host
计算机网络自顶向下在 http 方面没有 http 权威指南讲的详细,如果光写爬虫的话还是先看后者吧

