大模型 RAG 网页抓取能力对照实验:豆包、千问底层抓取引擎实测

文章目录

引言

在检索增强生成(RAG)和AI Agent日益普及的今天,大语言模型(LLM)的"联网读取网页"能力已经成为RAG知识库、网页问答Agent的核心底座。但在交互界面之下,它的抓取行为是典型黑盒:模型是直接HTTP拉取原始HTML,还是启动Headless浏览器完整渲染?能否执行JS、等待异步渲染?子资源加载策略、URL解析容错、自动化指纹伪装、链接递归抓取的行为差异,直接决定RAG的数据保真度、幻觉概率、站点安全边界。

为量化观测该行为,本次实验在自有云服务器 cnfaq.cn 部署一套零配置纯前端探针页面 ,以Nginx原始访问日志作为客观核验证据,对豆包、千问两款模型的网页抓取链路做对照探测。实验的核心原则:模型输出仅作为参考,服务端日志是判定真实行为的金标准,用来区分真实渲染结果和模型幻觉编造内容,为RAG系统选型、站点反爬策略、提示词约束设计提供实测依据。

探针不依赖后端接口、无需修改Nginx配置;利用404埋点请求做JS执行的可观测证据,所有探测逻辑全部在前端页面内完成,贴近真实用户访问环境。

探针设计

分层探测策略

采用分层递进探测思路,逐层提升解析难度,判断抓取引擎可以抵达哪一层渲染能力:

层级 探测目标 需要底层能力 预期表现
Layer1 STATIC 静态文本读取 基础HTTP GET + HTML文本解析 可以直接读出写死在源码中的静态标记
Layer2 CSS_HIDDEN CSS隐藏DOM读取 DOM树解析,读取全部DOM节点(不受display:none影响) 读取页面内被CSS隐藏的节点文本
Layer3 JS_SYNC 同步JS DOM注入 内置JS引擎,页面同步脚本可执行 读取脚本加载后立刻写入DOM的标记
Layer4 JS_ASYNC 延时异步渲染读取 Headless浏览器,具备定时器等待机制 等待setTimeout,拿到延迟注入的标记
Layer5 ENV_WEBDRIVER 浏览器自动化指纹探测 JS执行、读取navigator.webdriver、动态DOM创建 读取JS生成的webdriver指纹结果
核心设计特性
  1. 零服务器配置 :纯HTML+CSS+JS,不需要新增Nginx路由、新增后端接口,直接丢入网站目录即可上线;埋点请求故意指向不存在的/track,返回404,不影响业务,Nginx依然完整记录请求日志。
  2. 动态Token防缓存、防背诵 :每次页面加载,由JS生成全新probeId = 时间戳 + 随机串。标记值每次访问都不同,杜绝模型直接背诵训练缓存、搜索引擎快照内容,强制模型实时发起抓取。
  3. 独立埋点证据链 :new Image()发起埋点请求;日志出现该请求 = JS代码被真实执行;无埋点请求 = JS未执行,模型输出JS相关内容均为幻觉。
  4. robots防收录兜底 :页面添加noindex,nofollow,noarchive,nocache元标签,降低搜索引擎爬虫缓存污染实验的概率。
探针完整源码(probe.html)
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>RAG 探针</title>
<meta name="robots" content="noindex,nofollow,noarchive,nocache">
<style>
  .hidden-css { display: none; }
  .slot { color: #999; font-style: italic; margin: 4px 0; }
</style>
</head>
<body style="font-family:system-ui; max-width:720px; margin:40px auto;">

<p>==== RAG 探针页面 ====</p>
<p>请严格按以下格式返回你读取到的所有标记(读不到的项填 NONE):</p>
<pre>
STATIC: [静态标记]
CSS_HIDDEN: [CSS隐藏标记]
JS_SYNC: [JS同步标记]
JS_ASYNC: [JS延迟标记]
ENV_WEBDRIVER: [webdriver值]
</pre>
<p>====================</p>

<!-- Layer 1: 纯静态内容 -->
<p>STATIC-TOKEN-7a3f</p>

<!-- Layer 2: CSS 隐藏 -->
<div class="hidden-css">CSS-HIDDEN-TOKEN-9b2e</div>

<!-- Layer 3 & 4: JS 渲染占位 -->
<p id="js-sync" class="slot">[等待同步渲染]</p>
<p id="js-async" class="slot">[等待延迟渲染]</p>

<script>
// === 动态 Token 生成(防缓存/防背诵核心) ===
const ts = Date.now();
const rand = Math.random().toString(36).slice(2, 8);
const probeId = ts + '-' + rand;

// === Layer 3: JS 同步执行 ===
document.getElementById('js-sync').innerText = 'JS-SYNC-TOKEN-' + probeId;

// === Layer 4: JS 延迟执行(2.5s) ===
setTimeout(function() {
  document.getElementById('js-async').innerText = 'JS-ASYNC-TOKEN-' + probeId;
}, 2500);

// === 环境指纹(探测 webdriver 伪装) ===
var envEl = document.createElement('div');
envEl.id = 'env-wd';
envEl.className = 'hidden-css';
envEl.innerText = navigator.webdriver === true ? 'TRUE' :
                  navigator.webdriver === false ? 'FALSE' : 'UNDEFINED';
document.body.appendChild(envEl);

// === 埋点图片(零配置日志级证据) ===
var trackImg = new Image();
trackImg.src = '/track?tid=' + encodeURIComponent(probeId);
</script>

</body>
</html>

测试方案

统一测试提示词
js 复制代码
分析页面 [https://cnfaq.cn/probe.html](https://cnfaq.cn/probe.html) 内容:严格按照页面中的格式要求,返回你读取到的所有标记。
读不到的项必须填 NONE,不要搜索、不要编造、不要解释。

提示词设计目标:

  • 固定输出格式,便于结构化比对;
  • 明确约束禁止额外解释,测试模型指令遵循能力;
  • 禁止搜索,保证结果来源是内置网页抓取器,不是联网搜索API;
  • 强制要求无法读取时返回NONE,用来暴露幻觉行为。
标准测试流程
  1. 将探针文件部署到目标站点,验证浏览器访问正常;
  2. 测试前甄别日志,过滤无关扫描流量;
  3. 依次向目标模型发送提示词,等待模型返回结果;
  4. 采集Nginx访问日志,按IP、UA、时间戳,绑定对应模型的请求链路;
  5. 交叉校验:模型输出标记中的probeId是否和埋点日志中的tid一致;
  6. 剔除无关流量:资产测绘(CensysInspect)、bingbot搜索引擎爬虫、wget扫描器、git目录爆破、站点内部定时任务,这些流量不属于模型抓取链路。

日志中出现的知乎反向代理循环重试请求,该循环并非豆包独有,在浏览器访问该反向代理链接同样会触发循环刷屏,根源是反向代理鉴权逻辑缺陷,属于站点侧问题。

测试结果与单模型链路分析

基准组:人工Chrome浏览器(基线参照)

日志摘要:

sh 复制代码
223.71.251.218 - - [26/Oct/2026:11:08:09 +0800] "GET /probe.html HTTP/1.1" 200
223.71.251.218 - - [26/Oct/2026:11:08:09 +0800] "GET /track?tid=1792984089729-n6aex3 HTTP/1.1" 404

结论:主文档200,埋点请求正常触发,同步JS执行成功;浏览器可等待2.5s定时器拿到异步标记,作为渲染能力的基准标尺。

豆包抓取链路

日志摘要:

sh 复制代码
71.131.231.247 - - [26/Oct/2026:11:09:59 +0800] "GET /probe.html HTTP/1.1" 200
52.80.89.72 - - [26/Oct/2026:11:09:59 +0800] "GET /track?tid=1792984199689-14m46s HTTP/1.1" 404
54.222.135.81 - - "GET /question/2016275980306645511/answer/2087714199141142763 HTTP/1.1" 403(循环重试)

豆包输出:

js 复制代码
STATIC: STATIC-TOKEN-7a3f
CSS_HIDDEN: CSS-HIDDEN-TOKEN-9b2e
JS_SYNC: JS-SYNC-TOKEN-1792984199689-14m46s
JS_ASYNC: NONE
ENV_WEBDRIVER: NONE

行为判定:

  1. ✅ 存在埋点请求,probeId与日志tid完全匹配,内置Chromium无头渲染引擎、V8 JS引擎正常工作,支持同步JS执行、子资源加载;
  2. ✅ 可以读取CSS隐藏DOM节点;
  3. ❌ 2.5s延时异步JS返回NONE:渲染超时阈值小于2.5s,不会长时间挂起等待定时器;
  4. ❌ ENV_WEBDRIVER返回NONE:没有读取/注入navigator.webdriver属性;
  5. ✅ 指令遵循严格:没有额外解释、严格遵守输出格式;
  6. ⚠️ 架构特征:主文档请求IP和埋点子资源IP不一致,是网关/调度节点与渲染节点分离的分布式架构;
  7. ⚠️ 附加抓取行为:自动提取页面内超链接,递归发起跟随抓取,遇到鉴权拦截链接时持续重试。
千问抓取链路

日志摘要:

js 复制代码
49.7.6.33 - - [26/Oct/2026:11:19:55 +0800] "GET /probe.html HTTP/1.1" 200
49.7.6.46 - - [26/Oct/2026:11:19:56 +0800] "GET /probe.html) HTTP/1.1" 404
49.7.6.21 - - [26/Oct/2026:11:20:03 +0800] "GET /probe.html HTTP/1.1" 200

千问输出摘要:

js 复制代码
STATIC: STATIC-TOKEN-7a3f
CSS_HIDDEN: CSS-HIDDEN-TOKEN-9b2e
JS_SYNC: JS-SYNC-TOKEN-1792984803251-prjprb
JS_ASYNC: NONE
ENV_WEBDRIVER: FALSE

行为判定:

  1. ❌ 全程无/track埋点请求,没有执行JS,仅纯HTTP下载原始HTML源码;
  2. ❗ 幻觉实锤:输出里JS_SYNC、ENV_WEBDRIVER的probeId和日志时间、tid完全不匹配,JS相关内容属于模型编造,不是页面渲染结果;
  3. ✅ 仅能读取源码内原生静态内容、源码内的隐藏DOM文本(不需要JS执行、不需要样式计算);
  4. ⚠️ URL解析缺陷:文本解析时错误把右括号)拼接进URL路径,生成无效404请求;
  5. ❌ 指令遵循差:无视"不要解释"约束,输出大量前置分析文本;
  6. ✅ 本次观测没有自动跟随链接递归抓取行为;
  7. ⚠️ 架构特征:抓取请求全部来自49.7.6.x同子网,属于同子网负载均衡。

横向对比矩阵

分层能力对比
探测维度 豆包 千问 人工浏览器基线
Layer1 STATIC ✅ ✅ ✅
Layer2 CSS_HIDDEN ✅ ✅(源码存在) ✅
Layer3 JS_SYNC ✅(日志佐证) ❌(输出为幻觉) ✅
Layer4 JS_ASYNC(2.5s延时) ❌ 超时不等待 ❌ 无JS引擎 ✅
Layer5 ENV_WEBDRIVER ❌ 返回NONE ❌(幻觉输出FALSE) ✅
Image埋点子资源触发 ✅ ❌ 沙箱拦截/不执行JS ✅
架构与行为对比
对比项 豆包 千问
底层抓取引擎 Headless Chromium,带V8 JS引擎 纯HTTP源码拉取,本次观测无JS执行环境
网络架构 分布式异构,主请求与子资源节点IP分离 同子网负载均衡池
UA标识 Chrome/117 Chrome/126
子资源加载策略 new Image()可正常发起请求 JS沙箱不执行,子资源请求无法触发
URL文本容错 正常 差,边界符号污染URL路径
链接递归抓取 开启,自动提取页面链接预取 本次未观测到跟随抓取
指令遵循能力 强,严格按格式输出、无多余文本 弱,容易追加解释文本

核心发现

  1. 同步JS和异步延时渲染是明确分水岭:两款模型都无法稳定支持2.5s级别的异步延时渲染;豆包虽然具备完整JS引擎,但渲染超时窗口很短,优先快速返回,不会长时间等待前端异步数据。对于SPA、接口懒加载、延时渲染页面,两者都存在内容缺失风险。
  2. 沙箱策略差异巨大:豆包渲染沙箱允许Image对象发起子资源请求,千问当前这套抓取链路不运行JS脚本,前端埋点、图片统计、前端监控完全失效。站点前端埋点数据无法捕获千问爬虫访问。
  3. 幻觉风险隐藏在JS场景:仅依靠模型返回结果做校验是不可靠的。千问在完全没有JS执行的前提下,依然输出了格式正确、看起来合理的JS标记,属于典型结构化幻觉,在生产RAG场景极易造成错误结论。
  4. 链接递归抓取带来安全侧影响:豆包自动跟随页面内链接抓取,当页面包含内部鉴权接口、反向代理、内部管理链接时,会产生大量无效重试请求,对站点稳定性、接口限流造成压力。在RAG提示词中必须增加约束:仅抓取指定单页面,不跟随页面内其他链接。
  5. URL鲁棒性问题:千问的URL文本解析器对括号等符号处理存在缺陷,在URL附带参数、包含特殊符号的真实业务链接场景,存在抓取失败隐患。

RAG工程落地启示

  1. 探针埋点方案适配:当前Image埋点只对豆包有效;后续探针如果要兼容千问这类无JS引擎抓取器,不能依赖前端JS埋点,优先使用静态标记、服务端侧埋点。
  2. 页面适配选型
    • 静态页面、内容全部写死HTML源码:两者都可以稳定采集;
    • 同步JS渲染页面(SPA首屏同步注入):优先选择豆包;
    • 依赖长延时、XHR异步拉取数据的页面:两者都不适合,建议自建可控渲染爬虫,自定义超时等待时间。
  3. 核验体系必须分层
    • 模型输出是上层结果,日志才是可信证据;生产RAG系统做网页抓取校验,建议增加服务端侧的访问日志对账机制,识别幻觉。
  4. 提示词加固:针对容易溢出指令的模型,使用Few-shot示例、强约束system prompt,限制输出格式,禁止额外解释;同时增加"不跟随页面内其他链接、仅读取目标页面"约束。

附录

知乎robots约束、AI抓取表现的矛盾点与验证方案

知乎 robots.txt 仅对Googlebot、bingbot、Baiduspider等少数搜索引擎爬虫开放问答路径,不存在阿里系爬虫的放行条目,兜底 User-agent: * 规则协议层面禁止未明确标识的爬虫访问常规问答页面;同时本地curl即便配置浏览器UA,访问知乎链接也会被风控拦截,但千问却时常可以提取知乎页面内容,由此形成一组矛盾:既不存在robots赋予的豁免权限,常规实时GET请求又普遍被拦截。

进一步实验设计:本实验核心思路是切断快照来源,使用未收录新链接作为干净测试样本,在禁用搜索工具的前提下观测抓取结果,并配合服务端访问日志判定流量来源,以此区分快照召回与实时抓取两种机制。

  1. 在知乎发布一条全新回答,保证该链接暂未被任意搜索引擎收录;
  2. 在千问侧使用强制约束提示词关闭联网搜索能力,仅允许直接抓取目标URL;
  3. 结果判定:若仍可读出内容且知乎服务端日志捕获到访问记录,则为实时抓取放行;若读取失败,则证明能力依赖外部存量快照。
真实请求记录参考(含UA和来源IP)
sh 复制代码
-- 豆包访问期间(含无关请求):
71.131.231.247 - - [26/Oct/2026:11:09:59 +0800] "GET /probe.html HTTP/1.1" 200 1443 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-" "cnfaq.cn" "-"
52.80.89.72 - - [26/Oct/2026:11:09:59 +0800] "GET /track?tid=1792984199689-14m46s HTTP/1.1" 404 315 "https://cnfaq.cn/probe.html" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-" "cnfaq.cn" "-"
54.222.135.81 - - [26/Oct/2026:11:10:01 +0800] "GET /question/2016275980306645511/answer/2087714199141142763 HTTP/1.1" 403 605 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-" "zhihu.cnfaq.cn" "111.13.145.159:443"
(注:以上/2087714199141142763请求重复了N遍,进行了刷屏,此处省略。此外,该处循环是因为该转发本身不完备,我在浏览器访问该地址也会重复刷屏,涉及到验证不通过的原因导致)
39.107.52.162 - - [26/Oct/2026:11:10:05 +0800] "GET /cron/a56olz0AQ6s5NLaPtogeWhAaJE7scxZU HTTP/1.1" 200 17 "-" "Wget/1.14 (linux-gnu)" "-" "nav.cnfaq.cn" "127.0.0.1:9021"
65.49.20.66 - - [26/Oct/2026:11:10:09 +0800] "GET /geoserver/web/ HTTP/1.1" 302 145 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" "-" "39.107.52.162" "-"
40.77.167.13 - - [26/Oct/2026:11:12:24 +0800] "GET /guest/links?page=2&orderBy=random HTTP/1.1" 200 30877 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/116.0.1938.76 Safari/537.36" "-" "nav.cnfaq.cn" "127.0.0.1:9021"
40.77.167.13 - - [26/Oct/2026:11:12:35 +0800] "GET /guest/links?orderBy=random&page=4 HTTP/1.1" 200 30845 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/116.0.1938.76 Safari/537.36" "-" "nav.cnfaq.cn" "127.0.0.1:9021"
52.167.144.173 - - [26/Oct/2026:11:12:43 +0800] "GET /guest/tags/3?orderBy=random&link-display=1&orderDir=asc HTTP/1.1" 200 15173 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/116.0.1938.76 Safari/537.36" "-" "nav.cnfaq.cn" "127.0.0.1:9021"
65.49.20.66 - - [26/Oct/2026:11:14:49 +0800] "GET /.git/config HTTP/1.1" 302 145 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" "-" "39.107.52.162" "-"

-- 千问访问期间(含无关请求):
49.7.6.33 - - [26/Oct/2026:11:19:55 +0800] "GET /probe.html HTTP/1.1" 200 1443 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
49.7.6.46 - - [26/Oct/2026:11:19:56 +0800] "GET /probe.html) HTTP/1.1" 404 315 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
49.7.6.46 - - [26/Oct/2026:11:19:56 +0800] "GET /errors/errors.css HTTP/1.1" 200 833 "https://cnfaq.cn/probe.html)" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
49.7.6.46 - - [26/Oct/2026:11:19:56 +0800] "GET /errors/errors.js HTTP/1.1" 200 344 "https://cnfaq.cn/probe.html)" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
49.7.6.46 - - [26/Oct/2026:11:19:56 +0800] "GET /errors/tsparticles.bundle.min.js HTTP/1.1" 200 45860 "https://cnfaq.cn/probe.html)" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
49.7.6.21 - - [26/Oct/2026:11:20:03 +0800] "GET /probe.html HTTP/1.1" 200 1443 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.54 Safari/537.36" "-" "cnfaq.cn" "-"
59.82.83.83 - - [26/Oct/2026:11:20:31 +0800] "GET / HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Linux; Android 9; ASUS_X00TD; Flow) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/359.0.0.288 Mobile Safari/537.36" "-" "fy.cnfaq.cn" "-"
59.82.83.108 - - [26/Oct/2026:11:20:31 +0800] "GET /fy HTTP/1.1" 404 315 "-" "Mozilla/5.0 (Linux; Android 9; ASUS_X00TD; Flow) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/359.0.0.288 Mobile Safari/537.36" "-" "tools.cnfaq.cn" "-"
相关推荐
god_cvz1 小时前
第三章:12、经验沉淀与自优化
java·ai
西索斯coding1 小时前
Kimi K2.6 与 Qwen3.7 Max:跨文件修复评测与成本核算方法(2026)
开发语言·python·ai
程序员清风1 小时前
Claude Code 新手快速上手指南
人工智能·程序人生·ai
又蓝2 小时前
【元宝搜索开发者征文大赛】用 FastAPI + Vue3 做了个 AI 炒股工具,接了六个分析师和腾讯元宝搜索
人工智能·python·ai·fastapi
在世修行2 小时前
智学文枢:文科分析引擎
python·ai·pyside·文科分析
全栈练习生2 小时前
DeepSeek 稀疏注意力
python·ai
mjhcsp2 小时前
Code date creation v8.0 竞赛数据生成与对拍实战指南
算法·ai·深度优先·cdc
fensnote3 小时前
一句话,让 AI 把一块 ESP8266 从头调到能上网
ai·esp8266·nodemcu·workbuddy
codigger3 小时前
前端没有被杀死,被杀死的是"只会把设计稿变成页面"
前端·ai·ai编程·编程语言·全栈·#人工智能