首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 爬蟲實戰入門:基於 HttpURLConnection 的 GET/POST 請求與 Header 構建技巧

     編輯:Java 綜合教學

前言:爬蟲的本質是「模擬瀏覽器」

Java 原生 `HttpURLConnection` 無需第三方依賴即可完成 HTTP 通信。本文以知乎模擬登錄為例,演示如何通過瀏覽器開發者工具分析請求、提取關鍵 Header、構建通用請求工具類、處理 GET/POST、Cookie 管理,並封裝可復用的異步回調框架。

一、請求分析:從瀏覽器開發者工具到代碼

1.1 關鍵步驟

  1. 打開目標頁面 (如 `https://www.zhihu.com`)。
  2. F12 開啟 Network 面板,勾選「Preserve log」。
  3. 刷新/登錄/操作,捕獲目標請求 (通常是文檔類型 `document`)。
  4. 查看 Request Headers:Method、URL、Cookie、User-Agent、Referer、Accept 等。
  5. 查看 Response:HTML/JSON、狀態碼、Set-Cookie。

1.2 知乎首頁請求精簡

經測試,訪問知乎首頁僅需 `Cookie` 包含有效登錄憑證即可,其他 Header (User-Agent、Accept 等) 非必需但建議補全防反爬。

二、通用 HTTP 工具類設計 (異步回調風格)

2.1 核心接口 `HttpUtils`

public class HttpUtils {
    private HttpURLConnection conn;
    private OnVisitingListener listener;

    public interface OnVisitingListener {
        void onSuccess(HttpURLConnection conn);
        void onSetDetails(HttpURLConnection conn, HttpUtils httpUtils); // 設置 Header/Body
        void onFail(IOException e);
    }

    public HttpUtils setOnVisitingListener(OnVisitingListener l) { this.listener = l; return this; }

    public void startConnection(String url, String method) {
        try {
            URL u = new URL(url);
            conn = (HttpURLConnection) u.openConnection();
            conn.setRequestMethod(method);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            listener.onSetDetails(conn, this); // 回調設置細節
            conn.connect();
            if (conn.getResponseCode() == 200) listener.onSuccess(conn);
            else throw new IOException("HTTP " + conn.getResponseCode());
        } catch (IOException e) { listener.onFail(e); }
    }

    // 批量設置 Header
    public void setRequestProperties(Map headers) {
        for (Map.Entry e : headers.entrySet())
            conn.setRequestProperty(e.getKey(), e.getValue());
    }
    // 設置 Request Body (POST)
    public void setRequestBody(String body) throws IOException {
        try (PrintWriter w = new PrintWriter(conn.getOutputStream())) {
            w.write(body); w.flush();
        }
    }
    public static HttpUtils newInstance() { return new HttpUtils(); }
}

2.2 流工具類 `StreamUtils` (文件/流/字符串互轉)

public class StreamUtils {
    // 讀取流為字符串
    public static String readFromStream(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buf = new byte[1024]; int len;
        while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
        return out.toString(StandardCharsets.UTF_8);
    }
    // 按行讀取文件/流,回調處理
    public interface OnGetStringListener { void onGetString(String line); void onGeted(); }
    public static void getString(Object src, OnGetStringListener l) throws IOException {
        BufferedReader br = createBufferedReader(src, null);
        String line;
        while ((line = br.readLine()) != null) l.onGetString(line);
        l.onGeted(); br.close();
    }
    // 創建 BufferedReader (支持 File/String/InputStream/Reader)
    static BufferedReader createBufferedReader(Object src, String charset) throws IOException { /* ... */ }
}

三、實戰:GET 請求抓取知乎首頁

public class ZhihuCrawler {
    public static void main(String[] args) {
        HttpUtils.newInstance().setOnVisitingListener(new HttpUtils.OnVisitingListener() {
            @Override public void onSuccess(HttpURLConnection conn) {
                try { System.out.println(StreamUtils.readFromStream(conn.getInputStream())); }
                catch (IOException e) { e.printStackTrace(); }
            }
            @Override public void onSetDetails(HttpURLConnection conn, HttpUtils httpUtils) {
                Map headers = new HashMap<>();
                // 從文件讀取預先保存的 Header (含 Cookie)
                StreamUtils.getString("requestheader.txt", new StreamUtils.OnGetStringListener() {
                    @Override public void onGetString(String line) {
                        String[] kv = line.split(":", 2);
                        if (kv.length == 2) headers.put(kv[0].trim(), kv[1].trim());
                    }
                    @Override public void onGeted() { httpUtils.setRequestProperties(headers); }
                });
            }
            @Override public void onFail(IOException e) { e.printStackTrace(); }
        }).startConnection("https://www.zhihu.com/", "GET");
    }
}

requestheader.txt 示例:

Cookie: _xsrf=...; z_c0=...; d_c0=...; q_c1=...
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Referer: https://www.zhihu.com/
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

四、POST 請求:模擬登錄/表單提交

4.1 區別點

  • Method = `"POST"`
  • 需設置 `Content-Type: application/x-www-form-urlencoded` 或 `application/json`
  • 調用 `setRequestBody(body)` 寫入輸出流 (必須在 `connect()` 前)

4.2 代碼片段

httpUtils.setOnVisitingListener(new HttpUtils.OnVisitingListener() {
    @Override public void onSetDetails(HttpURLConnection conn, HttpUtils httpUtils) {
        Map headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");
        headers.put("Cookie", "..."); // 如有預登錄 Cookie
        httpUtils.setRequestProperties(headers);
        // 構建表單體: phone_num=xxx&password=yyy&captcha=...
        httpUtils.setRequestBody("phone_num=13800000000&password=123456");
    }
    // onSuccess/onFail 同 GET
}).startConnection("https://www.zhihu.com/login/phone_num", "POST");

五、進階話題:反爬蟲與工程化建議

挑戰應對策略
User-Agent 檢測設置真實瀏覽器 UA,定期輪換
Cookie 失效/掃碼登錄維護 Cookie 池,研究登錄流程 (二維碼/短信/滑塊),或使用 Selenium/Playwright 自動化瀏覽器獲取 Cookie
IP 限流/封禁代理 IP 池 (付費/免費),請求間隔隨機化 (1-5s)
JS 渲染/動態加載HttpURLConnection 無法執行 JS,需 Headless Chrome (Puppeteer/Java 綁定) 或分析 AJAX 接口直接調用
驗證碼/行為分析打碼平台、模擬人類軌跡、降低頻率
HTTPS 證書驗證生產環境勿關閉驗證;自簽證書需導入信任庫

六、工程化遷移建議

  • 入門/輕量/無依賴:`HttpURLConnection` + 手工封裝 (本文方案)。
  • 生產/高併發/功能豐富:遷移至 **Apache HttpClient 5** / **OkHttp 4** / **Spring WebClient (Reactor)**,支持連接池、異步非阻塞、自動重試、攔截器、TLS 精細控制。
  • 分布式爬蟲框架:WebMagic、Crawler4j、Scrapy (Python) 配合 Redis/RabbitMQ 去重調度。

總結

Java 爬蟲核心在於:請求分析 → Header/Body 精準構建 → 異步非阻塞 IO → 反爬對抗 → 數據清洗入庫。本文提供的 `HttpUtils` + `StreamUtils` 雙工具類,採用回調模式解耦邏輯,適合快速驗證與輕量項目。生產環境請拥抱成熟 HTTP 客戶端庫,專注於業務解析與反爬策略迭代。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved