
本文详解通过设置关键请求头(user-agent 和 accept-language)并采用流式下载方式,解决 requests 无法正常下载 adgm 等严格反爬网站 pdf 的常见问题,确保文件完整性与可读性。
在使用 requests 库下载 PDF 文件时,看似简单的 GET 请求常因目标网站的反爬机制而失败——下载的文件虽有大小,却无法被 Adobe Reader 或系统预览器打开,提示“已损坏”或“无法打开此文档”。根本原因往往不是网络或代码逻辑错误,而是服务器端对 HTTP 请求头进行了校验:仅提供 User-Agent 不足以通过验证,还需显式声明 Accept-Language,且 URL 参数应与请求头分离处理,避免拼接污染。
以下是一个经过实测、可稳定下载 ADGM 官网 PDF 的专业方案:
import requests
PDF_NAME = "alpha-development-middle-east-ltd-penalty-notice-redacted.pdf"
BASE_URL = "https://www.adgm.com/documents/operating-in-adgm/ongoing-obligation/enforcement/"
# 分离 URL 路径与查询参数,提升可维护性与兼容性
url = BASE_URL + PDF_NAME
params = {
"la": "en",
"hash": "5EA2DA7D1492D105375580EEF2FB088F"
}
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
"Accept-Language": "en-GB,en;q=0.9,en-US;q=0.8,pt;q=0.7"
}
# 启用 stream=True 并分块写入,避免内存溢出 & 提升大文件鲁棒性
chunk_size = 32 * 1024 # 32KB 每次读取
with requests.get(url, headers=headers, params=params, stream=True) as response:
response.raise_for_status() # 自动抛出 4xx/5xx 错误,便于调试
with open(PDF_NAME, "wb") as f:
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk: # 过滤空块
f.write(chunk)✅ 关键要点说明:
- Accept-Language 是必需项:ADGM 等政府/监管类网站常依赖该字段判断客户端合法性,缺失将导致返回 HTML 登录页或空响应(表面成功但内容为错误页面,导致 PDF 损坏)。
- 使用 params 参数而非手动拼接 URL:避免特殊字符编码错误(如 & =),同时让 requests 自动处理 URL 编码。
- 务必启用 stream=True + iter_content():防止大文件占用过多内存;直接写 response.content 可能因响应体被截断或含隐藏重定向内容而损坏文件。
- 调用 response.raise_for_status():及时捕获 HTTP 错误(如 403 Forbidden、404 Not Found),避免静默失败。
⚠️ 额外建议:
立即学习“Python免费学习笔记(深入)”;
- 若仍失败,可尝试抓包(如 Chrome DevTools → Network → 查看真实请求的 Headers),复刻完整请求头(包括 Referer、Sec-Fetch-* 等);
- 对于高频下载场景,添加 time.sleep(1) 避免触发频率限制;
- 生产环境建议增加超时控制:timeout=(3, 30)(3 秒连接,30 秒读取)。
遵循以上方法,即可稳定、可靠地下载受严格访问控制的 PDF 文档,兼顾健壮性与可维护性。








