1. 问题起点
在采集类任务中,访问失败 是一个常见的“拦路虎”。尤其是面对带有延迟加载、地域限制和请求校验的网站时,异常可能来自多种环节:
- 连接问题:代理地址失效、网络延迟过高
- 请求问题:关键请求头缺失、会话信息过期
- 内容问题:页面结构变化、数据在脚本中动态生成
- 访问限制:地址封锁、身份验证、验证码拦截
如果定位不及时,不仅会影响任务进度,还可能造成数据缺口。
2. 情境回顾
一次酒店信息采集任务中,需要基于 城市、酒店名、景点 这些关键词,在 www.agoda.cn 检索相关酒店并获取价格、评分等内容。
任务启动后没多久,日志中出现了这样的记录:
[ERROR] 访问受限:HTTP 403
[ERROR] 数据解析错误:未找到 hotelName 字段
可见既有访问被阻拦的情况,也有解析失败的情况。
3. 排查过程
为了尽快弄清原因,我做了分步验证:
(1)本机直连
浏览器直接访问相同搜索链接,可以正常显示 → 排除服务器不可用的可能性。
(2)更换代理节点
使用爬虫代理,替换不同出口 IP 测试,发现有的能正常获取,有的直接返回 403 → 存在 IP 封锁情况。
(3)对比请求信息
利用浏览器调试工具抓取真实请求头,与程序中发送的对比,发现少了 User-Agent 和 Accept-Language → 请求不完整可能触发了限制。
(4)检查数据加载方式
查看 HTML 源码时发现酒店信息是通过异步接口返回的 JSON,而非直接在 HTML 中 → 用静态解析自然会找不到数据。
4. 调整方案
结合上面的排查结果,做了以下调整:
- 代理池轮换:接入支持用户名密码验证的代理,并在遇到异常时自动切换 IP。
- 补全请求头:加入浏览器常用的
User-Agent、Accept-Language、Referer等信息。 - 直连数据接口:绕过 HTML 页面,直接请求 Agoda 的酒店搜索 API(抓包获取)。
- 访问节奏控制:在多次请求之间增加随机延时,避免短时间内大量访问。
5. 样例代码(Python + 爬虫代理)
import requests
import random
import time
from urllib.parse import quote
# ======== 亿牛云代理配置 www.16yun.cn========
proxy_host = "proxy.16yun.cn" # 域名
proxy_port = "3100" # 端口
proxy_user = "16YUN" # 用户名
proxy_pass = "16IP" # 密码
proxies = {
"http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
"https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
}
# ======== 请求头设置 ========
headers = {
"User-Agent": random.choice([
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/127.0.0.1 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
]),
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Referer": "https://www.agoda.cn/",
}
# ======== 搜索关键词 ========
keyword = "上海"
encoded_keyword = quote(keyword)
# Agoda 酒店搜索 API(抓包获取,可修改参数)
url = f"https://www.agoda.cn/api/zh-cn/Main/GetSearchResultList?city={encoded_keyword}&page=1&pageSize=10"
try:
resp = requests.get(url, headers=headers, proxies=proxies, timeout=15)
if resp.status_code == 200:
data = resp.json()
hotels = data.get("hotelList", [])
for h in hotels:
print(f"酒店: {h.get('hotelName')}, 价格: {h.get('price')}, 评分: {h.get('rating')}")
else:
print(f"访问异常,状态码: {resp.status_code}")
except requests.exceptions.ProxyError:
print("代理不可用,请检查配置。")
except requests.exceptions.Timeout:
print("请求超时,请检查网络延迟。")
except Exception as e:
print(f"异常:{e}")
time.sleep(random.uniform(2, 5)) # 随机延时
6. 方法总结
快速锁定采集异常的有效方式,是分层排查:
- 连接层 → 验证代理可用性、延迟、DNS解析。
- 请求层 → 对比请求头、会话信息是否缺失。
- 数据层 → 检查页面或接口返回的结构是否变化。
- 限制层 → 判断访问频率、IP封禁或验证机制。
这种由浅入深的排查路径,可以在很短时间内缩小问题范围,提高修复效率。