Jamabandi网站爬取POST请求失效问题及代码排查
故障排查与解决方案
核心故障原因
- 会话未保持:未使用
requests.Session()统一管理Cookie,ASP.NET的ViewState、SessionID等依赖会话一致性,分散的请求会导致服务器识别无效。 - 隐藏字段提取不全:进入Mutation页面后,除了常规的
__VIEWSTATE、__VIEWSTATEGENERATOR、__EVENTVALIDATION,还需额外提取__EVENTTARGET、__EVENTARGUMENT等触发事件的参数,否则POST请求会被服务器拒绝。 - POST参数缺失:选择变更编号时,需指定触发控件的ID(比如对应的下拉框或按钮ID),仅传隐藏字段无法触发正确的服务器逻辑。
解决方案
- 全程使用Session维护会话:所有GET/POST请求通过同一个
requests.Session()对象发送,自动保持Cookie。 - 每次请求后重新提取隐藏字段:每个页面跳转后,都解析当前页面的表单隐藏字段,确保参数为最新值。
- 补充事件触发参数:在POST请求中加入
__EVENTTARGET(指定触发的控件ID)和__EVENTARGUMENT(通常为空),模拟用户点击操作。 - 处理页面编码:指定响应编码为
utf-8,避免解析BeautifulSoup时出现乱码导致字段提取失败。
完整爬取代码
import requests from bs4 import BeautifulSoup # 初始化会话,统一管理Cookie session = requests.Session() session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' }) base_url = "https://jamabandi.punjab.gov.in" def extract_hidden_fields(soup): """提取页面所有表单隐藏字段""" hidden_fields = {} for input_tag in soup.find_all('input', type='hidden'): name = input_tag.get('name') value = input_tag.get('value') if name and value: hidden_fields[name] = value return hidden_fields try: # 1. 访问首页,提取初始隐藏字段 response = session.get(base_url) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 2. POST选择地区(示例取第一个可选地区,需根据实际页面调整value) district_option = soup.find('select', id='ddlDistrict').find_all('option')[1] post_data = hidden_fields.copy() post_data.update({ 'ddlDistrict': district_option['value'], '__EVENTTARGET': 'ddlDistrict', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 3. POST选择乡(示例取第一个可选乡) tehsil_option = soup.find('select', id='ddlTehsil').find_all('option')[1] post_data = hidden_fields.copy() post_data.update({ 'ddlTehsil': tehsil_option['value'], '__EVENTTARGET': 'ddlTehsil', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 4. POST选择村(示例取第一个可选村) village_option = soup.find('select', id='ddlVillage').find_all('option')[1] post_data = hidden_fields.copy() post_data.update({ 'ddlVillage': village_option['value'], '__EVENTTARGET': 'ddlVillage', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 5. POST选择年份(示例取第一个可选年份) year_option = soup.find('select', id='ddlYear').find_all('option')[1] post_data = hidden_fields.copy() post_data.update({ 'ddlYear': year_option['value'], '__EVENTTARGET': 'ddlYear', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 6. 进入Mutation页面(假设触发按钮ID为btnMutation,需根据实际页面确认) post_data = hidden_fields.copy() post_data.update({ '__EVENTTARGET': 'btnMutation', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') hidden_fields = extract_hidden_fields(soup) # 7. 选择变更编号(示例取第一个可选编号) mutation_option = soup.find('select', id='ddlMutation').find_all('option')[1] post_data = hidden_fields.copy() post_data.update({ 'ddlMutation': mutation_option['value'], '__EVENTTARGET': 'ddlMutation', '__EVENTARGUMENT': '' }) response = session.post(base_url, data=post_data) response.encoding = 'utf-8' # 验证爬取结果 soup = BeautifulSoup(response.text, 'html.parser') print("当前页面标题:", soup.title.string) except Exception as e: print(f"爬取出错: {str(e)}") # 注意事项: # 1. 需根据实际页面的控件ID调整参数(比如下拉框、按钮的ID) # 2. 若页面出现验证码,需额外添加验证码识别逻辑 # 3. 控制请求频率,避免触发网站反爬机制
内容的提问来源于stack exchange,提问作者jatin rajani
相关产品推荐
相关产品推荐

