Java Jsoup代理爬虫
Jsoup 1.17.1+支持请求级代理认证。案例创建可复用Connection会话,采集Books to Scrape三页商品并输出UTF-8 CSV。
语言Java 17+框架Jsoup 1.21+测试目标Books to Scrape输出books-jsoup.csv
01
END-TO-END RESULT
代理认证、CSS选择器与CSV输出
测试目标Books to Scrape
https://books.toscrape.com/
运行时Java 17+Jsoup 1.21+
输出文件结构化数据books-jsoup.csv
代码直接连接隧道代理固定网关 proxy.123proxy.cn:36923。主机与端口无需替换,出口路由由当前产品配置决定;你只需设置控制台生成的完整代理用户名和密码。
02
CREDENTIALS
只把代理账密放进环境变量
PROXY_USER必须是控制台中的代理用户名,不是网站登录手机号。地区和SESSION场景应复制控制台生成的完整路由用户名。
export PROXY_USER="替换为控制台代理用户名"
export PROXY_PASS="替换为控制台代理密码"
# 隧道代理固定网关:proxy.123proxy.cn:36923$env:PROXY_USER="替换为控制台代理用户名"
$env:PROXY_PASS="替换为控制台代理密码"
# 隧道代理固定网关:proxy.123proxy.cn:36923
不要把真实代理密码提交到Git仓库、镜像、日志或前端代码中。
03
COMPLETE PROGRAM
BooksWithProxy.java
以下代码包含完整入口和输出逻辑。安装注释、运行命令与依赖声明保留在文件顶部,复制为对应文件后即可执行。
// pom.xml dependency:
// <dependency>
// <groupId>org.jsoup</groupId>
// <artifactId>jsoup</artifactId>
// <version>1.21.2</version>
// </dependency>
import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public final class BooksWithProxy {
static {
// Allow Basic proxy authentication for HTTPS CONNECT tunnels.
System.setProperty(
"jdk.http.auth.tunneling.disabledSchemes",
""
);
}
private static final String PROXY_HOST = "proxy.123proxy.cn";
private static final int PROXY_PORT = 36923;
private static String csv(String value) {
return "\"" + value.replace("\"", "\"\"") + "\"";
}
public static void main(String[] args) throws Exception {
String proxyUser = System.getenv("PROXY_USER");
String proxyPass = System.getenv("PROXY_PASS");
if (proxyUser == null || proxyPass == null) {
throw new IllegalStateException(
"set PROXY_USER and PROXY_PASS first"
);
}
Connection session = Jsoup.newSession()
.proxy(PROXY_HOST, PROXY_PORT)
.auth(context -> {
if (!context.isProxy()) {
return null;
}
return context.credentials(proxyUser, proxyPass);
})
.userAgent("123Proxy-Developer-Example/1.0")
.timeout(30_000);
try (BufferedWriter output = Files.newBufferedWriter(
Path.of("books-jsoup.csv"),
StandardCharsets.UTF_8
)) {
output.write("title,price,availability,url\n");
String pageUrl =
"https://books.toscrape.com/catalogue/page-1.html";
for (int pageNumber = 1; pageNumber <= 3; pageNumber++) {
Document document = session
.newRequest(pageUrl)
.get();
for (Element book : document.select("article.product_pod")) {
Element link = book.selectFirst("h3 a");
String title = link.attr("title");
String price = book.selectFirst("p.price_color").text();
String availability = book
.selectFirst("p.availability")
.text();
String detailUrl = link.absUrl("href");
output.write(
csv(title) + "," +
csv(price) + "," +
csv(availability) + "," +
csv(detailUrl) + "\n"
);
}
Element next = document.selectFirst("li.next > a");
if (next == null) {
break;
}
pageUrl = next.absUrl("href");
Thread.sleep(500);
}
}
System.out.println("saved records to books-jsoup.csv");
}
}
04
ENGINEERING CHECKS
案例没有省略的关键逻辑
01HTTPS CONNECT前解除JDK对Basic代理认证的默认禁用
02auth回调只在context.isProxy时返回凭证
03Connection会话复用代理、User-Agent和超时
04CSS选择器提取字段并对CSV双引号执行转义
05
SWITCH PROXY PRODUCT
替换网关,不改采集逻辑
代理产品网关域名端口适合任务
隧道代理
proxy.123proxy.cn36923混合池 / 纯住宅池隧道住宅代理
residential.123proxy.cn33000国家地区与SESSION不限量动态住宅
unlimit.residential.123proxy.cn10253不限流量住宅任务两类静态代理
控制台分配的固定代理IP返回端口直连IP,无网关域名隧道住宅代理的国家与SESSION写在完整代理用户名中
网关固定为 residential.123proxy.cn:33000。例如使用美国SESSION时,直接把控制台生成的完整用户名作为 PROXY_USER,代码无需解析或重组。
06
PRIMARY REFERENCES
框架文档与测试目标
07
TROUBLESHOOTING
常见问题
为什么还要设置jdk.http.auth.tunneling.disabledSchemes?
JDK默认可能禁止HTTPS CONNECT隧道使用Basic代理认证。该属性必须在第一次认证前设置为空,否则代理账密正确也可能返回407。
为什么要求Jsoup 1.17.1以上?
Jsoup从1.17.1加入请求级认证能力,可为代理认证安全返回用户名和密码。
能否使用Java全局Authenticator?
可以,但全局Authenticator容易影响同一JVM中的其他HTTP请求。案例优先使用Jsoup连接级auth回调。
如何采集详情页?
从detailUrl继续调用session.newRequest(url).get(),并保持同一代理会话和限速策略。