如何使用Scrapy应用筛选条件过滤爬取的搜索结果?
核心问题根因
这个站点基于JSF + PrimeFaces组件库开发,目前筛选条件不生效的原因有三个:
- 硬编码的
j_idtxxx类组件id是页面每次加载时随机生成的动态值,刷新页面id就会变化,提交的参数名根本匹配不上真实的表单元素,后端无法识别对应的筛选字段 - PrimeFaces的交互逻辑和普通HTML表单存在差异,仅传递输入框的
_input值无法通过框架校验规则,加上缺少JSF强制要求的视图状态隐藏参数,请求会被后端判定为非法,不会返回带筛选条件的结果 - 爬取数据时仅选择了
.ui-datatable-odd类的奇数行,即便筛选生效,也会漏掉一半的表格数据
正确实现思路
- 彻底放弃硬编码动态组件id,通过元素固定的id后缀(比如
date1_input、powerPlant_input这类固定写在组件里的后缀)从响应中匹配真实的元素id,作为FormRequest的参数键,适配每次页面的动态id变化 - 提交请求时不要剔除
FormRequest.from_response自动携带的JSF隐藏字段(比如视图状态参数),保证请求能通过后端的会话校验 - 必须把查询按钮的标识参数一并提交,告诉后端要执行查询逻辑、刷新表格区域——PrimeFaces的表单不会自动根据输入值变化触发查询,必须收到按钮点击的信号才会处理筛选
参考修正后的代码
from scrapy.http import FormRequest from ..items import EpiasscrapingItem class EpiasSpider(scrapy.Spider): name = 'epias' start_urls =[ 'https://seffaflik.epias.com.tr/transparency/uretim/gerceklesen-uretim/gercek-zamanli-uretim.xhtml' ] def parse(self, response): # 动态提取固定后缀的真实组件id,替代硬编码的动态j_idt值 date1_input_id = response.xpath('//input[contains(@id, "date1_input")]/@id').get() date2_input_id = response.xpath('//input[contains(@id, "date2_input")]/@id').get() plant_input_id = response.xpath('//input[contains(@id, "powerPlant_input")]/@id').get() # 定位查询按钮的真实id search_btn_id = response.xpath('//button[contains(@id, "search") or contains(normalize-space(.), "查询")]/@id').get() # 构造筛选参数,键全部用动态提取的真实元素id formdata = { date1_input_id: '20.03.2021', date2_input_id: '20.03.2021', plant_input_id: '2614', search_btn_id: search_btn_id # 显式触发查询按钮动作 } return FormRequest.from_response( response, formdata=formdata, callback=self.start_scraping, headers={ 'X-Requested-With': 'XMLHttpRequest' # 匹配PrimeFaces AJAX请求的特征 } ) def start_scraping(self,response): items = EpiasscrapingItem() # 修正选择器:抓取所有表格行,不再只抓奇数行 table_epias = response.css('.ui-datatable tbody tr') for epias in table_epias: # 跳过空的表头/占位行 if len(epias.css('td')) < 15: continue date = epias.css('td:nth-child(1)::text').get().strip() time = epias.css('td:nth-child(2)::text').get().strip() biogas = epias.css('td:nth-child(15)::text').get().strip() items['date'] = date items['time'] = time items['biogas'] = biogas yield items
补充排查技巧
- 如果提交后还是没生效,就在浏览器里手动操作一次完整的筛选流程,打开开发者工具的网络面板,找到筛选时发出的POST请求,对照真实请求的参数列表,把PrimeFaces要求的专属参数(比如指定刷新区域的
javax.faces.partial.render参数)补充到formdata里 - 电厂选择组件是带自动补全的下拉控件,如果传的电厂ID值和前端存储的选项值不匹配,也会导致筛选失效,可以对照网络请求里的电厂字段真实值调整参数
内容的提问来源于stack exchange,提问作者Fatma A.
相关产品推荐
相关产品推荐

