无法爬取Aspx网站动态加载HTML表格的POST请求模拟问题排查
方案可行性结论
你的核心思路完全正确。这个站点是标准ASP.NET WebForm架构,专科搜索的结果表格确实是服务端渲染后通过POST请求直接返回的,不需要执行前端JS,用requests发起请求、bs4解析HTML的方案完全可行,不需要使用浏览器自动化工具。
现有代码的核心错误
- 表单字段名编码错误:你把字段名里的
$提前转成了URL编码的%24,requests提交表单时会自动完成URL编码,提前编码会导致服务端无法识别对应字段,所有带%24的字段名、__EVENTTARGET的参数值,都要把%24替换回$。 - 重复定义表单字段:payload里
ctl00$ContentPlaceHolder1$Name重复写了两次,删除重复项即可。 - 隐藏字段硬编码:
__VIEWSTATE、__VIEWSTATEGENERATOR、__EVENTVALIDATION这三个是WebForm架构的动态校验字段,和当前访问会话绑定,每次访问页面都会生成新值,你存在formdata文件里的静态值很容易失效,必须在第一次GET访问搜索页时,从返回的HTML源码中实时解析提取。 - 筛选条件传值错误:你给
ctl00$ContentPlaceHolder1$ddlCounty传了固定值15910,这个值对应特定郡的筛选选项,如果要搜索全州范围内的麻醉科医师,这个字段应该传空字符串,否则返回结果会被限定在对应郡。 - 请求头不全:仅传占位的User-Agent很容易被服务端拦截,需要补充真实浏览器UA、
Referer字段(值为搜索页地址),表单提交的Content-Type用requests默认值即可,不需要额外修改。
修正后的参考实现
import requests from bs4 import BeautifulSoup session = requests.Session() headers = { # 替换为本地浏览器的真实UA,不要用自定义占位UA 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', 'Referer': 'https://azbomprod.azmd.gov/GLSuiteWeb/Clients/AZBOM/public/WebVerificationSearch.aspx' } search_url = "https://azbomprod.azmd.gov/GLSuiteWeb/Clients/AZBOM/public/WebVerificationSearch.aspx?q=azmd&t=20220622082816" # 首次GET访问,获取动态生成的校验字段 first_resp = session.get(search_url, headers=headers) soup = BeautifulSoup(first_resp.text, 'html.parser') # 实时提取页面中的三个必填隐藏字段 payload = { "__VIEWSTATE": soup.select_one("#__VIEWSTATE")["value"], "__VIEWSTATEGENERATOR": soup.select_one("#__VIEWSTATEGENERATOR")["value"], "__EVENTVALIDATION": soup.select_one("#__EVENTVALIDATION")["value"], "ctl00$ContentPlaceHolder1$Name": "rbName1", "ctl00$ContentPlaceHolder1$txtLastName": "", "ctl00$ContentPlaceHolder1$txtFirstName": "", "ctl00$ContentPlaceHolder1$License": "rbLicense1", "ctl00$ContentPlaceHolder1$txtLicNum": "", "ctl00$ContentPlaceHolder1$Specialty": "rbSpecialty1", # 12155为Anesthesiology对应的下拉选项值,该值正确 "ctl00$ContentPlaceHolder1$ddlSpecialty": "12155", "ctl00$ContentPlaceHolder1$ddlCounty": "", "ctl00$ContentPlaceHolder1$txtCity": "", "__EVENTTARGET": "ctl00$ContentPlaceHolder1$btnSpecial", "__EVENTARGUMENT": "" } # 提交搜索请求 search_resp = session.post(search_url, data=payload, headers=headers) # 直接解析返回结果中的医师表格即可 result_soup = BeautifulSoup(search_resp.text, 'html.parser') doctor_table = result_soup.select_one("table[class*='grid']")
补充说明:如果搜索结果存在多页,翻页时需要从当前页的HTML中重新提取三个动态校验字段,再构造对应翻页事件的POST请求,不能复用之前拿到的校验字段值。
内容的提问来源于stack exchange,提问作者SpaceNarwals
相关产品推荐
相关产品推荐

