← 返回博客
数据抓取2026年9月19日

网页抓取自定义请求头:2026实操指南

易代理数据方案团队·公开网络数据采集研究·6 分钟阅读
advantages-of-custom-headers-in-web-scraping

TL;DR: 自定义请求头通过内容协商、语言与地区一致性、会话维持和条件缓存,提高响应格式正确率、解析成功率并减少重复流量。最佳做法是按域名与资源类型维护最小模板,让请求头、Cookie、代理地区和客户端能力保持一致;排障时固定其他变量,依次检查最终 URL、状态码、Content-Type、重定向链和响应正文,而不是盲目复制浏览器字段。

实现自定义请求头

自定义请求头解决什么问题

自定义请求头是抓取程序随 HTTP 请求发送的元数据,主要用于四类任务:

  • 内容协商:用 Accept 声明可解析的 HTML、JSON 或其他媒体类型;
  • 本地化:用 Accept-Language 配合代理地区、地区 Cookie 和 URL 获取一致的语言或币种;
  • 会话与授权:通过 Cookie、Authorization 维持已获许可的访问状态;
  • 增量更新:通过 If-None-Match 或 If-Modified-Since 避免重复下载未变化资源。

请求头只表达客户端声明。修改 User-Agent 不会执行 JavaScript,也不会生成有效 Cookie 或获得账户权限;发送 Accept: application/json 也不能把只提供 HTML 的页面转换为 JSON。

自定义请求头如何提高抓取质量

减少格式错误和无效解析

公开接口同时支持 HTML 与 JSON 时,明确发送 Accept: application/json 可以减少内容协商歧义。程序仍需验证响应:如果状态码是 200,但 Content-Type 为 text/html,正文可能是登录页、错误页或限流提示,不能直接交给 JSON 解析器。

建议分别统计两项指标:

  1. HTTP 成功率:返回预期状态码的请求比例;
  2. 解析成功率:成功提取必需字段的响应比例。

例如,1,000 次请求中有 980 次返回 200,但只有 910 次包含商品编号、价格和币种,则 HTTP 成功率为 98%,有效解析率只有 91%。后一个数字更能反映抓取管道是否可用。

提高地区数据的一致性

价格、库存和税费页面通常同时受出口 IP、语言、Cookie 与 URL 路径影响。采集法国站点时,可以把法国代理、Accept-Language: fr-FR,fr;q=0.9、欧元 Cookie 和法语 URL 绑定为一个会话;如果代理位于法国,而 Cookie 仍保存美国地区设置,结果可能混合美元价格和法语文案。

应在每条结果中保存以下上下文:

  • 代理国家或地区;
  • 请求语言;
  • 最终 URL;
  • 页面显示的币种;
  • 含税或未税标记;
  • 会话编号和采集时间。

这些字段能区分真实价格变化与地区配置漂移。

降低重复传输成本

服务器返回 ETag 后,后续请求可发送 If-None-Match;资源未变化时,服务器通常返回 304 Not Modified,不再传输完整正文。没有 ETag 时,可以使用 Last-Modified 与 If-Modified-Since,但时间精度和服务器实现可能导致误判,因此仍应定期执行完整校验。

以 10,000 个平均 500 KB 的页面为例,完整下载约需 5 GB 流量。如果 70% 的页面未变化并返回 304,理论上可减少约 3.5 GB 正文传输;实际节省量还要扣除请求头、响应头和定期全量校验产生的流量。

建立最小且稳定的请求头模板

按“域名 + 资源类型”拆分模板,不要让 HTML 页面、JSON 接口和文件下载共用一套字段。

请求头适用场景推荐做法常见错误
User-Agent大多数 HTTP 请求使用稳定、可解释的客户端标识每次请求随机更换
AcceptHTML 或 API 内容协商只声明解析器支持的媒体类型声明 JSON 后不验证响应
Accept-Language本地化页面与代理地区、Cookie 和 URL 一致同一会话频繁切换语言
Accept-Encoding压缩传输只声明客户端可解码的格式不支持 Brotli 却声明 br
Authorization获得许可的 API从密钥管理系统动态注入写入仓库或完整日志
Cookie登录或地区会话在同一粘性会话内复用同一 Cookie 数秒内跨国跳转
Referer站点确实依赖导航来源按真实导航链设置为所有请求伪造同一来源
If-None-Match基于 ETag 的增量抓取与 URL 和资源版本绑定保存把其他 URL 的值混用

不要复制浏览器中的全部请求头。浏览器请求可能包含短期令牌、设备提示、实验字段以及仅对当前导航有效的 Referer;复制后既可能泄露凭据,也可能形成相互矛盾的客户端声明。

三类模板示例

HTML_HEADERS = {
    "User-Agent": "ResearchCollector/1.0 (+https://example.org/contact)",
    "Accept": "text/html,application/xhtml+xml",
    "Accept-Language": "zh-CN,zh;q=0.9",
}

JSON_HEADERS = {
    "User-Agent": "ResearchCollector/1.0 (+https://example.org/contact)",
    "Accept": "application/json",
}

FILE_HEADERS = {
    "User-Agent": "ResearchCollector/1.0 (+https://example.org/contact)",
    "Accept": "application/pdf,application/octet-stream;q=0.8",
}

没有请求正文的 GET 通常不需要 Content-Type。只有发送 JSON 正文的 POST、PUT 或 PATCH 请求,才应设置 Content-Type: application/json。

用响应证据验证配置

每次请求至少记录以下字段:

  1. 请求 URL、最终 URL和完整重定向链;
  2. 状态码、Content-Type 与 Content-Encoding;
  3. 响应字节数和耗时;
  4. 解析是否成功及缺失字段;
  5. 请求头模板版本;
  6. 代理地区、会话编号和重试次数。

诊断异常响应时,可以保存正文前 1 KB,快速识别登录页、验证码页、网关错误或限流提示。保存前必须清除令牌、邮箱、电话号码和查询参数中的敏感值。

import requests

session = requests.Session()
session.headers.update({
    "User-Agent": "ResearchCollector/1.0 (+https://example.org/contact)",
    "Accept": "text/html,application/xhtml+xml",
    "Accept-Language": "zh-CN,zh;q=0.9",
})

url = "https://example.org/public-page"
first = session.get(
    url,
    timeout=(5, 20),
    allow_redirects=True,
)

validator_headers = {}
if first.headers.get("ETag"):
    validator_headers["If-None-Match"] = first.headers["ETag"]
elif first.headers.get("Last-Modified"):
    validator_headers["If-Modified-Since"] = first.headers["Last-Modified"]

second = session.get(
    url,
    headers=validator_headers,
    timeout=(5, 20),
    allow_redirects=True,
)

if second.status_code == 304:
    print("资源未变化,继续使用本地副本")
elif second.status_code == 200:
    content_type = second.headers.get("Content-Type", "")
    print(second.url, content_type, len(second.content))
else:
    print(second.status_code, second.url)

服务器可以忽略条件请求,因此程序必须同时处理 200 和 304。ETag 与缓存验证的语义分别由 RFC 9110 和 RFC 9111 定义。

一次可复现的排障案例

某公开商品接口包含 120 个 URL。第一版采集器直接复制浏览器请求,其中混入过期 Cookie、导航专用字段和不再有效的会话标识;11 个请求被重定向到 HTML 会话页,但程序仍按 JSON 解析,最终产生 11 次异常。

排查过程分为四步:

  1. 固定 URL、代理出口和并发数;
  2. 记录最终 URL、重定向链与 Content-Type;
  3. 删除过期 Cookie 和无关浏览器字段;
  4. 仅保留稳定的 User-Agent、Accept: application/json 和必要授权。

调整后,120 个响应均返回预期媒体类型。第二轮复用首轮保存的 ETag,其中 83 个未变化资源返回 304;这组结果只代表该接口,但明确展示了最小模板如何同时改善可诊断性和增量传输效率。

请求头、代理与会话的边界

请求头控制应用层声明,代理决定网络出口,两者不能互相替代。无状态公开页面可以按请求轮换 IP;购物车、分页游标、地区 Cookie 或登录会话通常需要粘性出口,具体轮换粒度可参考网页抓取中的 IP 轮换实践指南。

同一登录 Cookie 不应在数秒内跨多个国家使用。更稳妥的做法是以“账户 + 国家 + Cookie 容器 + 代理会话”为绑定单元,并在会话结束后统一销毁,而不是只轮换 User-Agent。

EProxies 提供超过 7200 万个住宅 IP,覆盖 195+ 个国家和地区,支持 HTTP(S) 与 SOCKS5。平台运行时间指标为 98.2%,并由 99.9% 运行时间 SLA 支持;按量住宅代理 $0.25/GB 起,300 GB 阶梯档约 $0.73/GB,ISP SOCKS5 代理 $0.95/IP 起,无限流量方案 $79/月起。采购前应确认目标国家库存、并发上限、会话时长、计费口径和 SLA 适用范围。

按采集任务选择配置

新闻增量采集

保存文章列表页和正文页各自的 ETag 或 Last-Modified。收到 304 时沿用本地副本;收到 200 时更新正文、验证器、发布时间和采集时间,避免把缓存时间误当成文章发布时间。转载、聚合与内容权利问题可参考网页抓取如何重塑新闻分发。

公开 JSON 接口

先确认接口文档明确支持 JSON,再发送 Accept: application/json。批量任务还应记录分页游标、速率限制响应头和每页记录数;如果接口返回 200 但必需字段为空,应先检查权限、接口版本和查询参数,而不是继续增加请求头。批量接口编排可参考 API 驱动的行业报告网页抓取指南。

动态页面

初始 HTML 不含目标数据时,继续堆叠请求头通常无效。应先在浏览器网络面板中确认数据来自 XHR、Fetch、GraphQL、内嵌状态还是脚本执行;只有页面必须运行 JavaScript 才使用浏览器自动化,具体识别路径可参考使用人工智能抓取动态网站。

自定义请求头故障排查流程

先把问题归入四层:代理连接、HTTP 协议、会话授权或内容解析。每轮实验只改变一个变量,否则无法判断异常来自请求头、Cookie、代理出口还是目标站点更新。

现象首要检查项可执行动作不应采取的做法
400字段语法、重复字段、URL 编码、正文格式导出实际发送的请求并逐字段删除一次添加整套浏览器字段
401凭据是否缺失、过期或作用域错误刷新合法凭据并核对 API 权限更换 User-Agent 代替认证
403账户权限、条款、来源链和响应正文停止重试并确认访问许可随机请求头持续尝试
407代理凭据、白名单和代理 URL单独测试代理认证修改目标站点的 Accept
429Retry-After、并发数和单域名频率降低并发并执行退避无等待立即重试
HTML 代替 JSON最终 URL、登录状态、媒体类型保存正文片段并检查重定向直接交给 JSON 解析器
解压失败Content-Encoding 与解码器删除不支持的压缩声明声明客户端不支持的 br
200 但字段为空JavaScript、地区 Cookie、接口版本对照页面网络请求和字段模式把 HTTP 成功当成数据成功

推荐按以下顺序执行:

  1. 用单个 URL、单线程和固定代理复现;
  2. 输出程序最终实际发送的请求头,而不是配置文件中的预期值;
  3. 检查最终 URL、重定向次数和响应媒体类型;
  4. 暂时移除 Cookie、Referer 和非必需字段;
  5. 从最小模板开始,每次只恢复一个字段;
  6. 用 20 至 50 个稳定 URL 做回归测试,比较 HTTP 成功率、解析成功率和响应大小;
  7. 为新模板分配版本号,异常时立即回滚。

遇到 429 时优先遵循 Retry-After。没有该字段时,可使用带随机抖动的指数退避,例如约 1、2、4、8 秒,并限制最大重试次数;持续限流时应降低单域名并发,而不是只更换请求头。

安全与合规控制

API 密钥、Cookie 和授权令牌应从环境变量或密钥管理系统读取。日志只保留令牌哈希、末尾字符或内部凭据编号;共享抓包文件前,还要清除查询参数、请求正文和响应正文中的个人数据。

请求头模板可以纳入版本控制,但敏感值必须排除。每次变更应记录目标域名、字段差异、测试样本数、HTTP 成功率、解析成功率、流量变化和回滚版本。

公开可访问不等于允许无限制采集。上线前应检查站点条款、个人数据规则、数据库权利、访问频率和技术限制,并结合各国网页抓取合法性地图评估适用司法辖区。

常见问题

自定义请求头有哪些最佳实践?

按域名和资源类型使用最小、稳定且可解释的模板,只发送任务需要的字段。让请求头与 Cookie、代理地区、会话状态和本地解析能力一致,并同时监控状态码、Content-Type、重定向链与解析成功率。敏感字段应由密钥系统注入,不能写入代码或完整日志。

自定义请求头问题如何排查?

先用单个 URL、固定代理和固定 Cookie 复现,再检查程序实际发送的请求头、最终 URL、状态码、重定向链、Content-Type 和正文前 1 KB。移除 Cookie、Referer 与非必需字段,从最小模板开始每次只增加一个字段;对 429 遵循 Retry-After,对 401、403 则先核对凭据、权限和站点条款。最后用 20 至 50 个稳定 URL 回归测试,比较解析成功率而不只是 200 比例。

自定义请求头如何改善网页抓取?

它们可以请求正确的媒体类型和语言、维持合法会话,并通过 ETag 或修改时间减少重复下载。例如,将法国住宅代理、法语请求头和欧元 Cookie 绑定到同一会话,可降低语言、币种和地区库存相互冲突的概率。其效果应通过解析成功率、响应字节数、304 比例和地区字段一致性来衡量。

自定义请求头能保证抓取成功吗?

不能。请求头无法替代合法认证、JavaScript 执行、Cookie 管理、访问频率控制或稳定网络。即使返回 200,仍要检查媒体类型和必需字段是否存在。

是否应该复制浏览器中的全部请求头?

不应该。浏览器请求可能包含短期令牌、设备提示、实验字段和当前导航专用字段,复制后可能泄露凭据或造成字段冲突。先建立最小模板,再根据接口文档和响应证据逐项增加字段。

Accept 和 Content-Type 有什么区别?

Accept 声明客户端希望接收的响应媒体类型,Content-Type 描述当前消息正文的媒体类型。没有请求正文的 GET 通常不需要设置 Content-Type;发送 JSON 正文时才使用 Content-Type: application/json。

遇到 403 是否应该继续增加请求头?

不应该。先检查响应正文、账户权限、站点条款、真实导航链路和请求频率,并在确认访问许可前停止自动重试。随机追加字段不会获得授权,反而会掩盖真正的拒绝原因。

自定义请求头能替代住宅代理吗?

不能。请求头表达客户端偏好,住宅代理提供特定地区的网络出口。多地区采集需要共同管理代理、语言、Cookie 和会话;代理本身不会赋予账户权限,请求头也不能改变出口 IP。

本文由 EProxies 团队撰写,经内部质量标准核查与人工审核后发布。