Jsoup技术问题:如何规避随机出现的403 HTML错误?
Jsoup爬取遭遇403反爬问题求助
问题现象
- 每5分钟运行一次脚本:20分钟(4次循环)后开始出现
org.jsoup.HttpStatusException: HTTP error fetching URL. Status=403,错误频率逐渐升高,最终每次运行都返回403。此时同一PC浏览器访问该网站也会显示“403 Forbidden”及“Request forbidden by administrative rules”,但手机访问正常。 - 每10分钟运行一次脚本:会出现3-4次成功、2-3次403的循环情况。
已做尝试
已设置userAgent和referrer,目标为获取form3表单文本,完整脚本如下:
try { String url = "http://..."; // Some params String[] mesId = {"[id=planning11604]","[id=planning11612]","[id=planning12915]"}; java.util.Random r = new java.util.Random(); int Guichet = r.nextInt(3); // My Jsoup connection Connection.Response resp = Jsoup.connect(url) .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36") .referrer("http://www.google.com") .method(Connection.Method.GET) .timeout(20000) .execute(); Document responseDocument1 = resp.parse(); // "checked" a checkbox in a form and then submit the form. FormElement form1 = (FormElement) responseDocument1.select("form#FormBookingCreate").first(); Element maCheckbox1 = form1.select("[name=condition]").first(); maCheckbox1.attr("checked", "checked"); Document responseDocument2 = form1.submit().cookies(resp.cookies()).post(); // "checked" a radio button in a form and then submit the form. FormElement form2 = (FormElement) responseDocument2.select("form#FormBookingCreate").first(); Element Radio1 = form2.select(mesId[Guichet]).first(); Radio1.attr("checked", "checked"); Document responseDocument3 = form2.submit().cookies(resp.cookies()).post(); FormElement form3 = (FormElement) responseDocument3.select("form#FormBookingCreate").first(); System.out.println("3ème page : "+form3.text()); Guichet = Guichet+1; } catch (IOException e) { System.out.println(e.toString()); }
解决方案建议
1. 优化请求频率与随机延迟
- 放弃固定间隔,改用随机延迟,比如每次请求后等待8-15分钟,避免机械性请求规律被识别。
- 控制单日总请求次数,减少服务器负载压力。
2. 完善请求头信息
- 除
userAgent和referrer外,添加真实浏览器常用的请求头:.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") .header("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3") .header("Accept-Encoding", "gzip, deflate") .header("Connection", "keep-alive") .header("Upgrade-Insecure-Requests", "1") - 定期更换
userAgent,模拟不同设备/浏览器请求:String[] userAgents = { "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" }; int uaIndex = new Random().nextInt(userAgents.length); .userAgent(userAgents[uaIndex])
3. 正确维护Cookie会话
- 当前代码仅传递首次请求的Cookie,后续请求需更新Cookie池:
// 首次请求获取初始Cookie Map<String, String> cookies = resp.cookies(); // 提交form1后更新Cookie Connection.Response form1Resp = form1.submit().cookies(cookies).execute(); cookies.putAll(form1Resp.cookies()); Document responseDocument2 = form1Resp.parse(); // 提交form2后再次更新Cookie Connection.Response form2Resp = form2.submit().cookies(cookies).execute(); cookies.putAll(form2Resp.cookies()); Document responseDocument3 = form2Resp.parse();
4. 使用代理IP
- IP被封禁时,切换代理IP是直接解决方案。可配置免费代理(注意稳定性)或付费代理:
// 基础代理配置 .proxy("代理IP", 端口号) // 带认证的代理 .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("代理IP", 端口号))) .proxyUsername("用户名") .proxyPassword("密码")
5. 模拟真实用户行为
- 在表单操作间加入1-3秒随机延迟,模拟用户操作间隔:
Thread.sleep(new Random().nextInt(2000) + 1000); // 1-3秒随机延迟 - 保持当前随机选择单选按钮的逻辑,避免固定操作路径。
6. 403后的重试策略
- 遇到403时,先等待30分钟以上,再更换UA或代理后重试,避免加重封禁。
内容的提问来源于stack exchange,提问作者DerfelCadarn
相关产品推荐
相关产品推荐

