如何不使用Selenium仅用requests爬取WHO流感监测历史数据?
解决方案
核心问题原因
你之前的代码存在两个核心错误导致请求未被后端识别为有效查询提交:
- 提取隐藏参数时错误使用
id属性作为参数键:ASP.NET表单提交时参数以输入框的name属性为键,你用id会导致后端无法识别校验参数,直接返回原始表单页 - 缺少提交按钮的触发参数:后端需要通过该参数判断用户点击了「Display report」按钮,而非普通页面访问
具体实现步骤
1. 配置请求头
先构造合理的请求头,避免被站点拦截:
import requests from bs4 import BeautifulSoup HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Referer": "https://apps.who.int/flumart/Default?ReportNo=12", "Content-Type": "application/x-www-form-urlencoded" } TARGET_URL = "https://apps.who.int/flumart/Default?ReportNo=12"
2. 正确构造POST参数
GET请求获取初始页面后,提取所有隐藏输入框的name和value,同时加入查询参数和提交按钮参数:
with requests.Session() as s: s.headers.update(HEADERS) # 第一步:获取初始页面的隐藏参数 resp = s.get(TARGET_URL, timeout=30) soup = BeautifulSoup(resp.text, "lxml") # 构造基础请求参数 post_data = { "lstSearchBy": "Mexico", "ctl_list_YearFrom": "2017", "ctl_list_WeekFrom": "1", "ctl_list_YearTo": "2021", "ctl_list_WeekTo": "53", # 核心:加入提交按钮参数,告知后端用户点击了查询按钮 "ctl00$ContentPlaceHolder1$btnDisplayReport": "Display Report" } # 提取所有隐藏域参数,用name作为键 hidden_inputs = soup.find_all("input", type="hidden") for inp in hidden_inputs: if inp.get("name") and inp.get("value"): post_data[inp["name"]] = inp["value"] # 第二步:提交查询请求,设置较长超时时间适配站点慢响应 resp = s.post(TARGET_URL, data=post_data, timeout=60) # 此时resp.text中已经包含查询后的表格数据,可以用BeautifulSoup解析 result_soup = BeautifulSoup(resp.text, "lxml") # 提取结果表格,选择class为gvFlumart的表格即可 data_table = result_soup.find("table", {"class": "gvFlumart"})
注意事项
- 如果提交后仍返回表单页,可通过浏览器F12开发者工具的网络面板,手动点击查询按钮后查看POST请求的Form Data,确认提交按钮的参数名和值,替换代码中对应的部分即可
- 批量爬取多个国家数据时,每次请求间隔建议设置10秒以上,避免触发站点限流
- 部分国家无对应时间段数据时,返回的表格会为空,可加判断逻辑跳过无效数据
内容的提问来源于stack exchange,提问作者Geoff
相关产品推荐
相关产品推荐

