PHP cURL代理爬虫
PHP cURL负责代理连接和错误处理,DOMDocument与DOMXPath解析Quotes to Scrape。案例连续采集3页并输出UTF-8 JSON。
语言PHP 8.1+框架cURL + DOMXPath测试目标Quotes to Scrape输出quotes-php.json
01
END-TO-END RESULT
cURL代理请求、XPath解析与JSON输出
测试目标Quotes to Scrape
https://quotes.toscrape.com/
运行时PHP 8.1+cURL + DOMXPath
输出文件结构化数据quotes-php.json
代码直接连接隧道代理固定网关 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
scrape.php
以下代码包含完整入口和输出逻辑。安装注释、运行命令与依赖声明保留在文件顶部,复制为对应文件后即可执行。
<?php
// requirements: PHP 8+ with curl and dom extensions
$proxyHost = 'proxy.123proxy.cn';
$proxyPort = 36923;
$proxyUser = getenv('PROXY_USER');
$proxyPass = getenv('PROXY_PASS');
if (!$proxyUser || !$proxyPass) {
throw new RuntimeException('set PROXY_USER and PROXY_PASS first');
}
function fetchHtml(
string $url,
string $proxyHost,
int $proxyPort,
string $proxyUser,
string $proxyPass
): string {
$curl = curl_init($url);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_PROXY => $proxyHost,
CURLOPT_PROXYPORT => $proxyPort,
CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
CURLOPT_PROXYUSERPWD => $proxyUser . ':' . $proxyPass,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_FAILONERROR => true,
CURLOPT_USERAGENT => '123Proxy-Developer-Example/1.0',
]);
$body = curl_exec($curl);
if ($body === false) {
$error = curl_error($curl);
curl_close($curl);
throw new RuntimeException($error);
}
curl_close($curl);
return $body;
}
$records = [];
$url = 'https://quotes.toscrape.com/';
for ($pageNumber = 1; $pageNumber <= 3; $pageNumber++) {
$html = fetchHtml(
$url,
$proxyHost,
$proxyPort,
$proxyUser,
$proxyPass
);
$document = new DOMDocument();
@$document->loadHTML($html, LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new DOMXPath($document);
foreach ($xpath->query('//div[contains(@class, "quote")]') as $quote) {
$text = $xpath->query(
'.//span[contains(@class, "text")]',
$quote
)->item(0)?->textContent;
$author = $xpath->query(
'.//small[contains(@class, "author")]',
$quote
)->item(0)?->textContent;
$tags = [];
foreach ($xpath->query(
'.//a[contains(@class, "tag")]',
$quote
) as $tag) {
$tags[] = trim($tag->textContent);
}
$records[] = [
'text' => trim((string) $text),
'author' => trim((string) $author),
'tags' => $tags,
'source_url' => $url,
];
}
$next = $xpath->query('//li[contains(@class, "next")]/a')
->item(0);
if (!$next) {
break;
}
$url = 'https://quotes.toscrape.com' .
$next->getAttribute('href');
usleep(500000);
}
file_put_contents(
'quotes-php.json',
json_encode($records, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
);
echo 'saved ' . count($records) . " records to quotes-php.json\n";
04
ENGINEERING CHECKS
案例没有省略的关键逻辑
01代理主机、端口与CURLOPT_PROXYUSERPWD分别设置
02连接超时和总超时分开配置
03HTTP 4xx/5xx通过CURLOPT_FAILONERROR进入错误处理
04XPath相对当前quote节点提取字段
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
常见问题
为什么不把账密直接拼到代理URL?
CURLOPT_PROXYUSERPWD专门处理代理凭证,避免特殊字符破坏URL结构。
PHP缺少DOMDocument怎么办?
需要启用dom扩展;缺少cURL时也必须先启用curl扩展。
如何改为SOCKS5?
将CURLOPT_PROXYTYPE改为CURLPROXY_SOCKS5_HOSTNAME,并使用控制台生成的SOCKS接入信息。