Flyscrape 是一个命令行网页抓取工具,抓取逻辑通过 JavaScript 脚本编写。它是独立工具(单一二进制文件),支持类似 jQuery 的选择器,并可通过无头浏览器渲染 JavaScript 较重的页面。
用途
Flyscrape 用于编写和运行网页抓取脚本。当用户提出抓取网站的需求时,可使用该技能。
主要能力
- 使用 JavaScript 脚本定义抓取配置与数据提取逻辑。
- 提供类似 jQuery 的查询 API,用于查找元素、读取文本/HTML/属性、判断属性与类是否存在。
- 支持集合操作:计数、取首尾元素、按索引取值、映射为数组、过滤元素。
- 支持遍历:父元素、子元素、兄弟元素、相邻兄弟、全部前后兄弟、直到某选择器的兄弟元素。
- 支持跟随链接与分页(通过 depth 与 follow 配置)。
- 支持无头 Chromium 浏览器模式,用于 JavaScript 较重的站点。
- 支持嵌套抓取(对链接页面再次抓取)。
- 支持下载文件(通过 flyscrape/http 的 download)。
- 支持限速、并发控制与文件缓存。
使用方式
常用命令:
- flyscrape new script.js:从模板创建新脚本。
- flyscrape dev script.js:开发模式,监听变化并重新运行(带缓存)。
- flyscrape run script.js:运行抓取器。
- flyscrape run script.js --url "http://example.com" --depth 3:通过命令行覆盖配置。
- flyscrape run script.js --output.file results.json:指定输出文件。
脚本结构:每个脚本包含两部分——config(控制行为)与 default 函数(提取数据)。
export const config = { url: "https://example.com", };
export default function({ doc, url, absoluteURL, scrape, follow }) { return { title: doc.find("h1").text(), }; }
default 函数参数说明:doc 为解析后的 HTML 文档(类似 jQuery API);url 为当前页面 URL;absoluteURL(path) 将相对 URL 转为绝对 URL;scrape(url, fn) 对链接页面进行嵌套抓取;follow(url) 手动跟随链接(配合 follow: [] 使用)。返回的对象会成为 JSON 输出。
主要配置项:url(起始 URL)、urls(多个起始 URL,默认 [])、depth(跟随链接深度,默认 0,即不跟随)、follow(要跟随的链接 CSS 选择器,默认 ["a[href]"])、browser(启用无头 Chromium,默认 false)、cache(设为 "file" 缓存请求)、rate(每分钟请求数限制)、concurrency(最大并发请求数)。
查询 API 示例:doc.find(".selector") 查找元素;el.text() 获取文本;el.html() 获取内部 HTML;el.attr("href") 获取属性;el.hasAttr("data-id") 判断属性存在;el.hasClass("active") 判断类存在。集合操作:items.length()、items.first()/items.last()、items.get(0)、items.map(el => el.text())、items.filter(el => el.hasClass("x"))。遍历:el.parent()、el.children()、el.siblings()、el.prev()/el.next()、el.prevAll()/el.nextAll()、el.prevUntil("selector")。
常见模式:
跟随分页:
export const config = { url: "https://example.com/posts", depth: 10, follow: [".pagination a.next"], };
浏览器模式(JavaScript 较重的站点):
export const config = { url: "https://spa-site.com", browser: true, headless: true, };
嵌套抓取(详情页):
export default function({ doc, scrape, absoluteURL }) { const links = doc.find(".product-link"); return { products: links.map(link => { const detailUrl = absoluteURL(link.attr("href")); return scrape(detailUrl, ({ doc }) => ({ name: doc.find("h1").text(), price: doc.find(".price").text(), })); }), }; }
下载文件:
import { download } from "flyscrape/http";
export default function({ doc, absoluteURL }) { doc.find("img").each(img => { download(absoluteURL(img.attr("src")), "images/"); }); return { downloaded: true }; }
限速与缓存:
export const config = { url: "https://example.com", rate: 30, concurrency: 2, cache: "file", };
工作流:创建(flyscrape new myscript.js)→ 开发(flyscrape dev myscript.js,使用缓存响应迭代)→ 运行(flyscrape run myscript.js,完整执行)→ 输出(flyscrape run myscript.js --output.file results.json)。
适用场景
- 抓取网站数据并输出为 JSON。
- 需要跟随分页或链接进行多页抓取。
- 抓取依赖 JavaScript 渲染的页面(启用 browser 模式)。
- 对列表页与详情页进行嵌套抓取。
- 下载页面中的文件(如图片)。
- 需要控制请求频率、并发与缓存的礼貌抓取。
限制与排错提示
- 被拦截(403):可添加 User-Agent 头、降低 rate、使用 browser: true。
- 结果为空:检查站点是否需要浏览器模式,核对选择器。
- 链接未被跟随:设置 depth > 0,检查 follow 选择器。
- 性能较慢:提高 concurrency,启用 cache: "file"。
参考文件:references/config.md(完整配置选项)、references/query-api.md(完整查询 API 文档)、references/recipes.md(常见模式与代码片段)、references/troubleshooting.md(问题解决指南)、examples/(可直接使用的示例脚本)。
外部资源:文档 https://flyscrape.com/docs/getting-started/ ;GitHub https://github.com/philippta/flyscrape ;示例 https://github.com/philippta/flyscrape/tree/master/examples 。