
1. 从零跑通第一个 Node 爬虫axios 与 puppeteer 两条路线怎么选如果你刚开始接触 Node 爬虫大概率会卡在同一个问题上目标页面的数据到底藏在接口里还是渲染在 HTML 里。前者用 axios 直接请求就能拿到 JSON后者往往要等浏览器把 JavaScript 执行完才能看到真实内容。这两种场景对应两条完全不同的抓取路线选错了工具你会对着空数组怀疑人生。这篇内容面向 Node 爬虫入门读者把 axios 静态请求和 puppeteer 动态渲染两条路线拆开讲清楚并且在请求层接入 TaoToken 统一 Key/API 通道让请求头、鉴权、模型调用这些容易出错的环节有一个统一入口。你可以跟着把 config 骨架复制下来改几个参数就能跑通第一个爬虫最后我会给出抓取结果的校验动作确认数据真的落盘而不是空壳。先说结论axios 适合接口型数据速度快、资源占用低puppeteer 适合服务端渲染或强依赖 JS 的页面能拿到最终 DOM但启动成本高。两者不是替代关系而是互补。实际项目里我经常先用 axios 试探接口拿不到再上 puppeteer。2. TaoToken 前置准备统一 Key 与 API 通道在写爬虫之前先把请求层的基础设施搭好。爬虫最烦的不是解析逻辑而是请求头、鉴权、限流这些杂事。TaoToken 在这里的作用是提供一个统一的 Key 和 API 通道你不需要在每个脚本里散落不同的 token而是集中管理。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数直接用于代码里的 baseURL。你需要先拿到一个可用的 Key。进入控制台创建 API Key路径是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建完成后复制保存。如果你后续要做长期编码或 Agent 类任务可以了解 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。想先验证模型对话是否通可以用模型对话页https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。注意Key 只放在环境变量里不要硬编码进脚本提交到仓库。这是爬虫项目最常见的泄露点。3. 可复制配置axios 静态请求骨架先建项目目录初始化并安装依赖mkdir node-spider-demo cd node-spider-demo npm init -y npm install axios cheerio dotenv在项目根目录创建.env文件写入你的 KeyTAOTOKEN_API_KEY你的Key TAOTOKEN_BASE_URLhttps://taotoken.net/api接着创建config.js这是整个爬虫的请求层骨架axios 实例、超时、请求头都在这里统一配置// config.js require(dotenv).config(); const axios require(axios); const client axios.create({ baseURL: process.env.TAOTOKEN_BASE_URL, timeout: 15000, headers: { Authorization: Bearer ${process.env.TAOTOKEN_API_KEY}, Content-Type: application/json, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } }); module.exports client;这里有几个参数值得说明。timeout设 15 秒太短容易误杀慢接口太长会拖住整个脚本。User-Agent必须带很多站点会直接拒绝空 UA 的请求。Authorization用 Bearer 格式Key 从环境变量读取。然后写第一个抓取脚本spider-axios.js目标是接口型数据// spider-axios.js const fs require(fs); const client require(./config); (async () { try { const { data } await client.get(/user_api/v1/author/recommend, { params: { category_id: , cursor: 0, limit: 20 } }); console.log(状态码正常数据条数, data?.data?.length ?? 未知); fs.writeFileSync(./data.json, JSON.stringify(data, null, 2)); console.log(已写入 data.json); } catch (err) { console.error(请求失败, err.response?.status, err.message); } })();运行node spider-axios.js如果看到数据条数和写入提示说明静态请求这条路线通了。这里的关键是params传参axios 会自动拼成查询字符串比手动拼 URL 干净得多。4. puppeteer 动态渲染拿到 JS 执行后的 DOM有些页面你直接请求 HTML返回的 body 里只有一堆 script 标签真实内容要等浏览器执行完 JS 才出现。这时候 axios 拿到的就是空壳必须换 puppeteer。安装npm install puppeteer写spider-puppeteer.js核心是启动浏览器、等待目标元素出现、再提取内容// spider-puppeteer.js const fs require(fs); const puppeteer require(puppeteer); (async () { const browser await puppeteer.launch({ headless: new, args: [--no-sandbox, --disable-setuid-sandbox] }); const page await browser.newPage(); await page.setUserAgent(Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36); await page.goto(https://example.com/list, { waitUntil: networkidle2 }); await page.waitForSelector(.item-title, { timeout: 10000 }); const items await page.$$eval(.item-title, els els.map(el el.innerText.trim()) ); console.log(抓取条数, items.length); fs.writeFileSync(./items.json, JSON.stringify(items, null, 2)); await browser.close(); })();waitUntil: networkidle2表示等网络基本空闲再继续waitForSelector是更精确的等待方式目标元素没出现就超时。这两个配合能避免大部分「页面还没渲染完就抓」的问题。$$eval在页面上下文里执行返回的是纯数据不会把 DOM 对象带出来。如果你需要抓取的内容在 iframe 里用page.frames()找到对应 frame 再操作这一点和普通页面不同容易踩坑。5. 验证请求与成功结果怎么确认数据真的抓到了跑完脚本不代表成功空数组、登录页、验证码页都会让脚本「正常结束」但数据是错的。我习惯做三层校验。第一层看条数。脚本里打印items.length或data.length如果是 0先别急着解析回去看请求是否被重定向。第二层看字段。把第一条数据打印出来确认关键字段有值console.log(首条样本, JSON.stringify(items[0], null, 2));第三层看落盘文件。打开data.json或items.json确认不是[]也不是 HTML 片段。如果文件里出现!DOCTYPE html说明你抓到的是错误页或反爬页。对于接入 TaoToken 的请求还可以用模型对话页做一次连通性验证https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 确认 Key 和通道本身没问题再排查爬虫逻辑。6. 本篇常见错排查报错 401 或 403先检查.env里的 Key 是否被正确读取dotenv要在require(axios)之前调用。再确认Authorization格式是Bearer加空格加 Key。axios 返回 HTML 而不是 JSON目标地址可能不是接口或者被重定向到登录页。打印err.response?.data看实际返回内容必要时换 puppeteer。puppeteer 启动失败常见于缺少系统依赖或沙箱权限。加--no-sandbox参数Linux 环境还要确认 Chromium 依赖已安装。waitForSelector 超时选择器写错了或者元素在 iframe 里。先用page.content()打印当前 HTML确认选择器是否存在。抓到的中文乱码检查响应编码axios 默认按 UTF-8 处理如果目标站点是 GBK需要手动转码。请求频率过高被封加await new Promise(r setTimeout(r, 1000))做间隔别用并发硬冲。排障和接入相关的文档入口在这里API Keys 管理 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。如果你用 Claude Code 做开发Anthropic 相关配置参考 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 。最后给一个实用习惯每次改完选择器或请求参数先只跑一条数据确认字段对了再放开全量。爬虫调试最耗时的不是写代码而是反复跑全量才发现解析错了。把校验动作前置能省掉大量等待。