JAVA HTML PARSER

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 Scrapehttps://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

不要把真实代理密码提交到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(),并保持同一代理会话和限速策略。