下面我将从简单到复杂,分步讲解整个流程和实现方法。

核心思想
采集带验证码的网页,本质上是在模拟一个真实用户进行登录或操作,你需要:
- 第一次访问目标页面:获取初始的Cookie信息(如果网站依赖Session)。
- 获取验证码图片:从HTML源码中找到验证码图片的URL,并请求这个图片。
- 处理验证码:这是最关键的一步,有几种主流方法。
- 提交表单:将你获取的Cookie、用户名、密码和验证码一起提交到服务器。
- 采集数据:如果登录成功,你就可以带着有效的Session Cookie去访问需要登录才能看到的页面,并抓取数据。
准备工作:PHP环境
你需要一个能发起HTTP请求和获取HTML的库,PHP自带的 file_get_contents() 和 curl 扩展都可以,但强烈推荐使用 cURL,因为它更强大,能更好地模拟浏览器行为(如设置Header、Cookie、处理重定向等)。
确保你的PHP环境开启了 curl 扩展。
详细步骤与代码示例
我们以一个模拟的登录页面为例,假设其HTML结构如下:

login_page.html (模拟)
<html>
<head><title>登录</title></head>
<body>
<form action="login.php" method="post">
<p>用户名: <input type="text" name="username"></p>
<p>密码: <input type="password" name="password"></p>
<!-- 验证码图片 -->
<p>验证码: <img src="captcha.php" id="captcha_img"></p>
<p><input type="text" name="captcha_code"></p>
<p><input type="submit" value="登录"></p>
</form>
</body>
</html>
获取页面内容和Cookie
访问登录页面,获取HTML源码和服务器返回的Cookie。
<?php
// 1. 初始化 cURL
$ch = curl_init();
// 2. 设置 cURL 选项
$url = 'http://example.com/login_page.html';
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而不是直接输出
curl_setopt($ch, CURLOPT_HEADER, true); // 包含响应头,用于获取Cookie
// 3. 执行请求
$response = curl_exec($ch);
// 4. 检查是否有错误
if (curl_errno($ch)) {
echo 'cURL Error: ' . curl_error($ch);
curl_close($ch);
exit;
}
// 5. 分离响应头和响应体
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header_content = substr($response, 0, $header_size);
$body_content = substr($response, $header_size);
// 6. 从响应头中提取 Set-Cookie
// 注意:这里是一个简化的提取,实际中可能需要更复杂的解析
preg_match_all('/Set-Cookie: (.*?);/i', $header_content, $matches);
$cookies = $matches[1];
// 将Cookie字符串转换为cURL可用的格式
$cookie_string = implode('; ', $cookies);
echo "获取到的页面内容:\n" . $body_content . "\n\n";
echo "获取到的Cookie:\n" . $cookie_string . "\n";
// 7. 关闭 cURL
curl_close($ch);
?>
获取验证码图片
从上一步获取的HTML中,我们可以用正则表达式或DOM解析器找到验证码图片的URL (captcha.php),然后再次使用cURL请求它。
注意:请求验证码时,必须带上第一步获取的Cookie,因为服务器通常用Cookie来关联你的会话和验证码。

// 假设 $cookie_string 已经从上一步获取
// 假设我们从HTML中解析出验证码图片的URL是 captcha.php
$captcha_url = 'http://example.com/captcha.php';
// 初始化一个新的 cURL 资源
$ch_captcha = curl_init();
curl_setopt($ch_captcha, CURLOPT_URL, $captcha_url);
curl_setopt($ch_captcha, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_captcha, CURLOPT_COOKIE, $cookie_string); // 关键:带上Cookie
// 执行请求
$captcha_image_data = curl_exec($ch_captcha);
// 将图片保存到本地,方便查看或交给识别服务
file_put_contents('captcha_code.jpg', $captcha_image_data);
echo "验证码图片已保存为 captcha_code.jpg\n";
curl_close($ch_captcha);
现在你的目录下会有一个 captcha_code.jpg 文件。
处理验证码(核心难点)
这是最复杂的一步,有三种主流策略:
策略A:手动输入(适用于个人或测试)
最简单的方法,将验证码图片显示出来,然后让用户手动输入。
// 显示图片 (在HTML中) // <img src="captcha_code.jpg" alt="Captcha"> // 在命令行脚本中,可以提示用户输入 echo "请打开 captcha_code.jpg 图片,并输入验证码: "; $captcha_code = trim(fgets(STDIN)); // 从命令行读取输入
优点:简单、免费、准确率高。 缺点:无法自动化,需要人工干预。
策略B:使用第三方打码平台(适用于商业或高频率采集)
这是最主流的自动化解决方案,你将验证码图片发送给专业的验证码识别服务,它们会返回识别结果。
国内有很多平台,如:
- 云打码
- 超级鹰
- 打码兔
流程:
- 注册平台账号,获取软件ID和密码。
- 将验证码图片(或图片的二进制数据)发送到平台的API。
- 平台返回识别出的字符串,并扣除你的余额。
伪代码示例(以超级鹰为例):
// 需要先下载超级鹰的SDK并引入
// require_once('Chaojiying.class.php');
// $chaojiying = new Chaojiying('你的用户名', '你的密码', '你的软件ID');
// // 读取验证码图片
// $captcha_image = file_get_contents('captcha_code.jpg');
// // 调用识别接口
// $result = $chaojiying->PostPic($captcha_image, 1001); // 1001是验证码类型代码
// if ($result['status'] == 0) {
// $captcha_code = $result['pic_str']; // 识别成功
// echo "识别结果: " . $captcha_code . "\n";
// } else {
// echo "识别失败: " . $result['err_str'] . "\n";
// }
优点:高度自动化,识别率高(尤其对于复杂验证码)。 缺点:需要付费,有成本。
策略C:使用Tesseract OCR(适用于技术能力强、对成本敏感)
Tesseract是一个开源的OCR(光学字符识别)引擎,你可以将其安装到服务器上,然后通过PHP调用它来识别简单的验证码。
流程:
- 安装Tesseract OCR。
- Linux (Ubuntu/Debian):
sudo apt-get install tesseract-ocr - Windows: 下载安装包并配置环境变量。
- Linux (Ubuntu/Debian):
- 安装PHP的Tesseract扩展,如
tesseract-ocr/php-tesseract-ocr。 - 使用扩展进行识别。
代码示例:
// 需要安装 tesseract-ocr/php-tesseract-ocr 扩展
require_once 'vendor/autoload.php';
use thiagoalessio\TesseractOCR\TesseractOCR;
try {
// 对验证码图片进行预处理(可选但推荐)可以提高识别率
// 灰度化、二值化、降噪等
// 这里我们直接识别
$captcha_code = (new TesseractOCR('captcha_code.jpg'))
->run();
// 清理识别结果,去除空格和换行
$captcha_code = preg_replace('/\s+/', '', $captcha_code);
echo "OCR识别结果: " . $captcha_code . "\n";
} Exception (e) {
echo "OCR识别失败: " . $e->getMessage() . "\n";
}
优点:免费,开源,可控。 缺点:
- 对复杂、扭曲、有干扰线的验证码识别率很低。
- 需要自己搭建和维护环境。
- 技术门槛较高。
提交登录表单
你已经有了所有登录所需的信息:$cookie_string, username, password, 和 $captcha_code。
// 假设这些值已经准备好
$username = 'your_username';
$password = 'your_password';
// $captcha_code 从步骤三获取
// $cookie_string 从步骤一获取
// 登录请求的URL
$login_url = 'http://example.com/login.php';
// 初始化 cURL
$ch_login = curl_init();
// 构造POST数据
$post_data = [
'username' => $username,
'password' => $password,
'captcha_code' => $captcha_code
];
curl_setopt($ch_login, CURLOPT_URL, $login_url);
curl_setopt($ch_login, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_login, CURLOPT_POST, true); // 设置为POST请求
curl_setopt($ch_login, CURLOPT_POSTFIELDS, http_build_query($post_data)); // 设置POST数据
curl_setopt($ch_login, CURLOPT_COOKIE, $cookie_string); // 关键:带上之前的Cookie
// 执行登录请求
$login_response = curl_exec($ch_login);
// 检查登录是否成功
// 通常成功会返回 "登录成功" 或跳转,失败会返回 "验证码错误" 等
if (strpos($login_response, '登录成功') !== false || strpos($login_response, '欢迎') !== false) {
echo "登录成功!\n";
// 登录成功后,$ch_login 会话中已经包含了最新的有效Cookie
// 你可以用这个 $ch_login 继续请求需要登录才能访问的页面
$protected_page_url = 'http://example.com/user/profile.php';
curl_setopt($ch_login, CURLOPT_URL, $protected_page_url);
curl_setopt($ch_login, CURLOPT_POST, false); // 改为GET请求
$profile_page = curl_exec($ch_login);
echo "获取到的用户主页内容:\n" . $profile_page . "\n";
} else {
echo "登录失败!\n";
echo "服务器返回: " . $login_response . "\n";
}
// 关闭 cURL
curl_close($ch_login);
总结与最佳实践
- 会话管理是关键:整个过程都要小心处理Cookie。
CURLOPT_COOKIE是你的好朋友。 - 模拟浏览器:除了Cookie,还可以设置
User-Agent等Header,让请求看起来更像来自真实浏览器。curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
- 错误处理:网络请求随时可能失败,务必加入
curl_errno()和curl_error()的判断。 - 选择合适的验证码解决方案:
- 个人/测试:手动输入。
- 商业/高频:直接上第三方打码平台,省时省力。
- 技术/低成本/简单验证码:可以尝试Tesseract OCR,但要对其效果有合理的预期。
- 尊重网站规则:采集数据时,请务必遵守目标网站的
robots.txt协议和用户协议,不要对服务器造成过大压力,高频率的请求可能会被IP封禁。
通过以上步骤,你就可以用PHP攻克大多数带验证码的网站采集任务了。
