如何用Python+BeautifulSoup爬取采用PrimeFaces的表单?
我之前也折腾过PrimeFaces这类JS封装的表单提交,确实比普通静态表单麻烦不少,给你一步步拆解解决方法:
第一步:定位PrimeFaces的请求参数
PrimeFaces的表单提交是通过AJAX异步发送的,没法直接从页面HTML里拿到完整的查询参数,得靠浏览器开发者工具抓真实请求:
- 打开目标页面后按F12进入开发者工具,切换到Network标签
- 勾选顶部的Preserve log(防止页面跳转后请求记录丢失)
- 手动在页面上提交一次测试查询(比如输入姓名和邮编点搜索)
- 在Network列表里找POST类型的请求(通常请求URL就是当前页面的
findVoterReg.xhtml,或者带ajax标识) - 找到请求后切换到Payload标签(旧版Chrome叫Form Data),这里就是PrimeFaces需要的所有参数,重点关注这些:
javax.faces.ViewState:这个是PrimeFaces的视图状态令牌,每次请求都会变,必须从页面提取- 表单字段对应的参数:比如
findVoterForm:firstName、findVoterForm:lastName这类,和你输入的内容对应 - 框架自带的参数:比如
javax.faces.partial.ajax(值一般为true)、javax.faces.source(触发请求的按钮ID)
第二步:用Python实现提交
1. 先获取初始页面,提取必要的会话和ViewState
一定要用requests.Session()保持会话,PrimeFaces依赖会话cookie跟踪状态:
import requests from bs4 import BeautifulSoup target_url = "https://www.sos.state.co.us/voter/pages/pub/olvr/findVoterReg.xhtml" session = requests.Session() # 获取初始页面,拿到ViewState和会话cookie initial_response = session.get(target_url) soup = BeautifulSoup(initial_response.text, "html.parser") view_state = soup.find("input", {"name": "javax.faces.ViewState"})["value"]
2. 构造POST请求的参数
完全照搬你在Network里看到的Payload结构,参数名必须和抓包结果完全一致:
payload = { "javax.faces.partial.ajax": "true", "javax.faces.source": "findVoterForm:searchBtn", # 替换成你抓包到的按钮ID "javax.faces.partial.execute": "@all", "javax.faces.partial.render": "findVoterForm:searchResultsPanel", # 替换成结果面板的ID "findVoterForm": "findVoterForm", "findVoterForm:firstName": "John", # 你的测试姓名 "findVoterForm:lastName": "Doe", "findVoterForm:zipCode": "80202", # 你的测试邮编 "javax.faces.ViewState": view_state }
3. 设置请求头
PrimeFaces对请求头有要求,必须带上这些关键项:
headers = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Faces-Request": "partial/ajax", "Referer": target_url, "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" }
4. 发送请求并解析结果
返回的是XML格式的AJAX响应,需要用BeautifulSoup的XML解析器处理:
response = session.post(target_url, data=payload, headers=headers) result_soup = BeautifulSoup(response.text, "xml") # 提取结果面板里的内容 result_panel = result_soup.find("update", {"id": "findVoterForm:searchResultsPanel"}) print(result_panel.text.strip()) # 可以进一步解析里面的HTML结构
额外注意事项
- 如果需要多次提交,每次请求后都要从响应里重新提取新的
javax.faces.ViewState,因为这个令牌会更新 - 要是遇到请求被拒绝,检查抓包的参数有没有遗漏,比如有些站点会带
javax.faces.partial.event这类隐藏参数 - 尽量用真实浏览器的
User-Agent,避免被站点的反爬机制拦截
内容的提问来源于stack exchange,提问作者rixter
相关产品推荐
相关产品推荐

