如何从印度铁路rbs站点抓取含隐藏数据的完整列车中间站信息
解决方案
方案1:使用支持JS渲染的爬取工具(最省心,改动最小)
纯Jsoup只能解析静态HTML,无法执行页面JavaScript,也没法模拟按钮点击触发动态请求,你可以换成轻量的无界面JS渲染工具HtmlUnit,或者自动化测试工具Selenium,完全复用你现有的表格解析逻辑:
- 引入HtmlUnit依赖,配置开启JavaScript执行、禁用CSS渲染减少性能消耗
- 模拟提交起点终点参数到目标页面,获取渲染后的页面对象
- 定位到页面上所有加载隐藏站点的按钮元素,循环执行模拟点击操作,每次点击后等待1-2秒确保JS请求完成、DOM更新
- 所有隐藏内容加载完成后,直接提取tbody元素,用你现有的行遍历逻辑解析全部站点数据即可
方案2:抓全请求参数直接调用接口(性能更高,无需渲染)
你直接调用接口失败的核心原因是缺了会话关联和正确的参数规则,按以下步骤调整即可:
- 第一次用Jsoup发POST请求到
ShortPath.jsp时,不要直接拿Document,先获取Response对象,把返回的所有Cookie(核心是JSESSIONID)全部保存下来,同时解析返回的页面统计加载隐藏内容的按钮总数,确定需要调用StationXmlServlet的次数 - 调用
StationXmlServlet的规则:- 必须携带第一次请求拿到的全部Cookie,否则服务器会判定请求非法
- 参数为表单键值对格式,不要用逗号拼接,
index参数从1开始依次递增,和按钮顺序一一对应,其余参数保持你抓包到的固定值即可
- 每次接口返回的JSON直接解析,提取站点信息和你之前从初始表格拿到的内容合并即可
代码调整示例(方案2核心逻辑)
private void shortestPath(String source, String destination) { try { // 第一步:先拿Cookie和初始页面 Connection.Response initRes = Jsoup.connect(url) .data("srcCode", source.toUpperCase()) .data("destCode", destination.toUpperCase()) .data("guageType", "S") .data("transhipmentFlag", "false") .data("distance", "goods") .method(Connection.Method.POST) .execute(); Map<String, String> cookies = initRes.cookies(); Document doc = initRes.parse(); // 你的原有初始表格解析逻辑保留 Element table = doc.select("tbody").get(0); Elements rows = table.select("tr"); stationCodeList = new String[rows.size() - 3]; jsonPath = new JSONObject(); for (int row = 3; row < rows.size(); row++) { JSONObject jsonObject = new JSONObject(); Elements cols = rows.get(row).select("td"); String code = cols.get(1).text(); String name = cols.get(2).text(); String cum_dist = cols.get(3).text(); String inter_dist = cols.get(4).text(); String gauge = cols.get(5).text(); String carry_cap = cols.get(6).text(); jsonObject.put("Code", code); jsonObject.put("Name", name); jsonObject.put("Cumulative Distance", cum_dist); jsonObject.put("inter Distance", inter_dist); jsonObject.put("Gauge Type", gauge); jsonObject.put("Carrying Capacity", carry_cap); jsonPath.put(code, jsonObject); stationCodeList[row - 3] = code; } // 第二步:统计按钮数,循环调用接口拿隐藏数据 // 先定位加载隐藏内容的按钮元素,拿到总数量,选择器可根据页面实际结构调整 Elements loadBtns = doc.select(".load-inter-btn"); for (int i = 1; i <= loadBtns.size(); i++) { // 发请求拿隐藏数据 String servletRes = Jsoup.connect("https://rbs.indianrail.gov.in/ShortPath/StationXmlServlet") .cookies(cookies) .data("route", "inter") .data("index", String.valueOf(i)) .data("distance", "goods") .data("PageName", "ShortPath") .method(Connection.Method.POST) .ignoreContentType(true) .execute() .body(); // 解析返回的JSON,把站点数据合并到jsonPath和stationCodeList即可 JSONObject hideData = new JSONObject(servletRes); // ... 补充JSON解析逻辑合并数据即可 } } catch (Exception e) { e.printStackTrace(); } this.destination =new Station(stationCodeList[stationCodeList.length-1]); }
内容的提问来源于stack exchange,提问作者IronFist
相关产品推荐
相关产品推荐

