You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单次CURL请求中捕获随机Token并提交POST数据?

解决单次流程中捕获页面Token并提交POST数据的问题

这个问题很常见——服务器生成的Token通常和用户会话(Session)绑定,两次独立的curl请求会触发新的会话,导致之前拿到的Token失效。要解决这个问题,你需要把「获取Token」和「提交POST数据」放在同一个curl会话里,保持会话连贯性,这样就能用刚拿到的有效Token提交请求了。

核心思路

  1. 初始化一个curl会话,启用Cookie持久化,确保GET和POST请求共享同一个会话。
  2. 发起GET请求,获取包含Token的页面HTML。
  3. 从HTML中提取目标隐藏输入框的Token值(推荐用DOM解析,比正则更可靠)。
  4. 构造POST请求数据,包含提取到的Token和其他表单字段。
  5. 在同一个curl会话中切换为POST模式,提交数据并获取响应。

完整PHP代码实现

<?php
// 替换为你的目标页面URL(包含Token的页面)
$targetPageUrl = 'https://your-target-site.com/page-with-token';
// 替换为POST提交的处理URL(通常和GET页面一致,或单独的提交接口)
$submitUrl = 'https://your-target-site.com/submit-form';

// 初始化curl会话
$ch = curl_init();

// 基础curl配置:保持Cookie、返回响应内容、跟随重定向
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// 启用Cookie存储,确保会话一致(cookie.txt会自动创建,需确保脚本有写入权限)
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
// 模拟浏览器请求头,避免被服务器拦截
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
]);

// 第一步:GET请求获取页面内容
curl_setopt($ch, CURLOPT_URL, $targetPageUrl);
$htmlContent = curl_exec($ch);
if (curl_errno($ch)) {
    die("GET请求失败:" . curl_error($ch));
}

// 第二步:提取Token - 推荐用DOM解析(更稳定,不受HTML属性顺序影响)
$token = '';
$dom = new DOMDocument();
// 抑制HTML解析警告(兼容不规范的页面代码)
libxml_use_internal_errors(true);
$dom->loadHTML($htmlContent);
libxml_clear_errors();

// 通过ID查找隐藏输入框
$clippingInput = $dom->getElementById('clipping');
if ($clippingInput) {
    $token = $clippingInput->getAttribute('value');
}

if (empty($token)) {
    die("无法提取Token,请检查页面结构是否变化");
}

// 第三步:构造POST提交的数据(根据实际表单字段调整)
$postFields = [
    'clipping' => $token, // 注意:这里的键要和表单中该输入框的name属性一致(不是id)
    'username' => 'your-username',
    'password' => 'your-password',
    // 添加其他需要提交的字段
];

// 转换为URL编码的POST字符串
$postData = http_build_query($postFields);

// 第四步:切换为POST模式,提交数据
curl_setopt($ch, CURLOPT_URL, $submitUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);

$postResponse = curl_exec($ch);
if (curl_errno($ch)) {
    die("POST请求失败:" . curl_error($ch));
}

// 关闭curl会话
curl_close($ch);

// 处理并输出响应
echo "POST请求响应结果:<br>" . htmlspecialchars($postResponse);
?>

关键细节说明

  • 会话一致性:CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE是核心,它们让curl在两次请求中共享Cookie(比如Session ID),服务器会认为是同一个用户会话,Token自然有效。
  • DOM解析vs正则:用DOMDocument通过ID查找元素比正则表达式更可靠——如果页面HTML的属性顺序变化(比如type="hidden"放在id前面),正则可能失效,但DOM解析不受影响。如果一定要用正则,也可以用这个兼容写法:
    preg_match('/<input[^>]+id="clipping"[^>]+value="([^"]+)"/i', $htmlContent, $matches);
    $token = isset($matches[1]) ? $matches[1] : '';
    
  • 请求头模拟:添加浏览器样式的User-Agent和Accept头,避免服务器把请求识别为爬虫而拒绝。
  • 错误处理:加入curl_errno和curl_error可以快速定位请求中的问题(比如网络错误、URL无效等)。

对你原函数的改进

如果你想继续使用自己的getStr2函数,也可以调整为更稳定的版本:

function getStr2($content, $startStr, $endStr) {
    $startPos = strpos($content, $startStr);
    if ($startPos === false) return '';
    $startPos += strlen($startStr);
    $endPos = strpos($content, $endStr, $startPos);
    if ($endPos === false) return '';
    return substr($content, $startPos, $endPos - $startPos);
}

// 使用方式
$token = getStr2($htmlContent, '<input id="clipping" type="hidden" value="', '"');

内容的提问来源于stack exchange,提问作者Geraldo Magela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:24:00