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

PHP cURL 抓取遠程頁面實戰:構造 IP、Referer、POST 數據、超時控制與錯誤處理完整模板

     編輯:PHP 綜合知識

實際業務中常需模擬瀏覽器抓取頁面、繞過簡單防盜鏈、提交表單。本文提供生產可用的 cURL 封裝模板,涵蓋偽造 IP/Referer、POST 數據、超時、重定向、編碼處理與錯誤診斷。

核心封裝函數 fetchUrl()

<?php
/**
 * 通用 cURL 抓取函數
 *
 * @param string $url          目標 URL
 * @param array  $postData     POST 數據,null 為 GET
 * @param array  $headers      額外請求頭
 * @param int    $timeout      總超時(秒)
 * @param int    $connectTimeout 連接超時(秒)
 * @param bool   $followLocation 是否跟隨重定向
 * @param string $cookieFile   Cookie 文件路徑(保持會話)
 * @param string $proxy        代理 'host:port'
 * @param string $userAgent    自定義 UA
 * @return array ['code'=>http_code, 'body'=>string, 'headers'=>array, 'error'=>string|null, 'info'=>array]
 */
function fetchUrl(string $url, array $postData = null, array $headers = [], int $timeout = 30, int $connectTimeout = 10, bool $followLocation = true, string $cookieFile = '', string $proxy = '', string $userAgent = ''): array {
    $ch = curl_init();
    $defaultHeaders = [
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
        'Cache-Control: no-cache',
        'Pragma: no-cache',
    ];
    if ($userAgent) $defaultHeaders[] = 'User-Agent: ' . $userAgent;

    // 偽造 IP(部分防火牆檢查 X-Forwarded-For / Client-IP)
    $defaultHeaders[] = 'X-Forwarded-For: ' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '127.0.0.1');
    $defaultHeaders[] = 'Client-IP: ' . (isset($_SERVER['HTTP_CLIENT_IP']) ? $_SERVER['HTTP_CLIENT_IP'] : '127.0.0.1');

    $opts = [
        CURLOPT_URL             => $url,
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_HEADER          => true,           // 包含響應頭,稍後分離
        CURLOPT_HTTPHEADER      => array_merge($defaultHeaders, $headers),
        CURLOPT_TIMEOUT         => $timeout,
        CURLOPT_CONNECTTIMEOUT  => $connectTimeout,
        CURLOPT_FOLLOWLOCATION  => $followLocation,
        CURLOPT_MAXREDIRS       => 10,
        CURLOPT_ENCODING        => 'gzip, deflate', // 自動解壓
        CURLOPT_SSL_VERIFYPEER  => true,           // 生產必開
        CURLOPT_SSL_VERIFYHOST  => 2,
        CURLOPT_USERAGENT       => $userAgent ?: 'Mozilla/5.0 (compatible; PHP-cURL/'.PHP_VERSION.')',
    ];

    if ($postData !== null) {
        $opts[CURLOPT_POST] = true;
        $opts[CURLOPT_POSTFIELDS] = is_array($postData) ? http_build_query($postData) : $postData;
    }
    if ($cookieFile) {
        $opts[CURLOPT_COOKIEJAR] = $cookieFile;
        $opts[CURLOPT_COOKIEFILE] = $cookieFile;
    }
    if ($proxy) {
        $opts[CURLOPT_PROXY] = $proxy;
    }
    // IPv4 強制(解決 IPv6 環境超時)
    if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')) {
        $opts[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
    }

    curl_setopt_array($ch, $opts);
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = $errno ? curl_error($ch) : null;
    $info = curl_getinfo($ch);
    curl_close($ch);

    // 分離頭與體
    $headerSize = $info['header_size'];
    $respHeaders = substr($response, 0, $headerSize);
    $body = substr($response, $headerSize);

    // 解析響應頭為關聯數組
    $headersArr = [];
    foreach (explode("\r\n", $respHeaders) as $line) {
        if (strpos($line, ':') !== false) {
            [$k, $v] = explode(':', $line, 2);
            $headersArr[trim($k)] = trim($v);
        }
    }

    return [
        'code'   => $info['http_code'],
        'body'   => $body,
        'headers' => $headersArr,
        'error'  => $error,
        'info'   => $info,
    ];
}

使用示例

<?php
require 'fetchUrl.php';

// 1. 簡單 GET
$res = fetchUrl('https://httpbin.org/get');
echo $res['code'] === 200 ? 'OK: ' . strlen($res['body']) : 'ERR: ' . $res['error'];

// 2. POST 表單 + 自定義 Referer
$res = fetchUrl('https://httpbin.org/post', ['username' => 'test', 'pwd' => '123'], [
    'Referer: https://example.com/login',
]);

// 3. 搶 Cookie 會話(登錄後訪問受保護頁)
$cookieFile = sys_get_temp_dir() . '/curl_cookie_' . md5('session') . '.txt';
$login = fetchUrl('https://site.com/login', ['user'=>'a','pass'=>'b'], [], 30, 10, true, $cookieFile);
if ($login['code'] === 200) {
    $profile = fetchUrl('https://site.com/profile', null, [], 30, 10, true, $cookieFile);
    // $profile['body'] 包含登錄後內容
}

// 4. 代理抓取
$res = fetchUrl('https://httpbin.org/ip', null, [], 30, 10, true, '', '127.0.0.1:7890');

// 5. 強制 IPv4(雲服務器常見 IPv6 連不上目標)
$res = fetchUrl('https://api.ipify.org?format=json'); // 內部已啟用 CURLOPT_IPRESOLVE_V4

關鍵參數說明

參數作用建議值
CURLOPT_HEADER => true獲取響應頭(狀態碼、Set-Cookie、Content-Type)true
CURLOPT_ENCODING自動處理 gzip/deflate 壓縮響應'gzip, deflate'
CURLOPT_IPRESOLVE_V4強制 IPv4,避免 IPv6 環境超時PHP 5.3+ / cURL 7.10.8+
CURLOPT_COOKIEJAR/FILE持久化 Cookie,支援跨請求會話臨時文件路徑
CURLOPT_FOLLOWLOCATION自動處理 301/302 重定向true(注意 open_basedir/safe_mode 限制)

錯誤碼快速診斷

curl_errno常見原因排查方向
6DNS 解析失敗檢查 /etc/resolv.conf、域名拼寫、內網 DNS
7無法連接主機IP/端口、防火牆、安全組、目標服務是否啟動
28操作超時調大 timeout、檢查網絡延遲、目標響應慢
35SSL 握手失敗證書過期、CA 不信任、TLS 版本不匹配、SNI 缺失
51SSL 證書驗證失敗CA 文件缺失、自簽證書需 CURLOPT_CAINFO、或開發環境暫時關閉 VERIFYPEER
60CA 證書問題更新 ca-certificates、指定 CURLOPT_CAINFO

進階:併發抓取 curl_multi 簡介

需同時抓取多個 URL 時,使用 curl_multi_* 族函數可顯著降低總耗時。參考 《解析 php 中 curl_multi 的應用》。

將 fetchUrl() 放入公共庫,統一超時、UA、IPv4、錯誤處理,能解決 90% 以上抓取場景,剩餘 10% 複雜登錄/JS 渲染請轉 Headless Chrome (Puppeteer/Playwright)。

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