Jsoup爬取汇率网站前10次运行正常后续返回NULL值如何解决
问题根因
- 代码无容错机制:IO异常仅打印日志,未终止后续流程。连接失败时
doc保持null值,调用doc.select直接触发空指针,是返回NULL的直接原因。 - 反爬规则触发:目标站点对高频爬虫请求存在拦截策略,前10次请求频率低被放行,后续请求被识别为爬虫直接拒绝连接/返回错误响应,导致Jsoup获取数据失败。
- 请求配置缺陷:当前仅配置了超时时间,未模拟浏览器请求头特征,默认的Jsoup请求标识极易被服务器识别拦截。
解决方案
无需修改Netbeans连接属性,只需在代码中新增适配逻辑即可:
1. 补全异常容错+重试机制
连接失败时自动重试2-3次,所有重试均失败则终止后续解析逻辑,避免空指针。
2. 优化请求配置,模拟浏览器访问
添加User-Agent、Referer等请求头,伪装成正常浏览器请求,降低被拦截概率。
3. 添加请求间隔限制
两次请求之间设置1-3秒的随机延时,避免高频请求触发反爬规则。
4. 修正解析逻辑
原有选择器和遍历逻辑存在错误,无法正确遍历所有汇率行,需调整元素选择规则。
修改后的完整代码
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; public class Den3 { public static void main(String[] args) { String url = "https://uzmanpara.milliyet.com.tr/doviz-kurlari/"; Document doc = null; int retryCount = 3; // 最大重试次数 Random random = new Random(); // 带重试的请求逻辑 while (retryCount > 0 && doc == null) { try { // 模拟浏览器请求头 doc = Jsoup.connect(url) .timeout(10000) // 超时时间拉长到10秒 .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") .referrer("https://www.google.com") .header("Accept-Language", "tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7") .get(); } catch (IOException ex) { Logger.getLogger(Den3.class.getName()).log(Level.WARNING, "请求失败,剩余重试次数:" + (retryCount-1), ex); retryCount--; // 重试前加随机延时 try { Thread.sleep((long) (2000 + random.nextInt(2000))); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } // 请求完全失败直接退出 if (doc == null) { System.err.println("多次请求均失败,请检查网络或稍后再试"); return; } String[] currencyStr = new String[11]; String[] buyStr = new String[11]; String[] sellStr = new String[11]; // 修正选择器,直接选表格下的所有行 Elements rows = doc.select(".borsaMain table.table-markets tbody tr"); int i = 0; for (Element row : rows) { if (i >= 11) break; // 避免数组越界 Elements tds = row.select("td"); if (tds.size() < 4) continue; // 跳过无效行 currencyStr[i] = tds.get(1).text(); buyStr[i] = tds.get(2).text(); sellStr[i] = tds.get(3).text(); System.out.println(String.format("%s [buy=%s, sell=%s]", currencyStr[i], buyStr[i], sellStr[i])); i++; } for(i = 0; i < 11; i++){ System.out.println("currency: " + currencyStr[i]); System.out.println("buy: " + buyStr[i]); System.out.println("sell: " + sellStr[i]); } // 单次请求结束后加延时,若为循环爬取可保留 try { Thread.sleep((long) (1000 + random.nextInt(2000))); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
内容的提问来源于stack exchange,提问作者Simurg
相关产品推荐
相关产品推荐

