第 1 课

装好 Lightpanda,用 fetch 把 JS 页面变成 Markdown

用官方一行脚本安装并锁定 1.0.2、关闭遥测,对比 curl 和 fetch 抓 JS 渲染页面的差别,用 --dump-selector 取片段、--strip-mode clutter 只留正文,用 --wait-until、--wait-selector、--wait-script 等异步内容,再用 --json 批量抓取和 --fail-on-http-error 处理 404。

图文20 分钟Lightpanda 官方文档 ↗

课程目录第 1 / 3 课

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文教材

本课对照的官方页面:一行脚本安装、命令说明、fetch 参数、通用参数。命令与输出在 Linux x86_64 云主机上实测(Lightpanda 1.0.2),输出为节选。

这一课装好 Lightpanda,再用它的 fetch 命令抓一个靠 JavaScript 渲染内容的页面,转成大模型好读的 Markdown。全程不需要账号,也不花钱。

第 1 步:用官方脚本安装并锁定版本

官方系统要求:Debian 12、Ubuntu 22.04/24.04(x86-64 和 arm64)、macOS 13 及以上;Windows 用户需要在 WSL 里安装。一行脚本需要系统里有 curl、jq 和 sha256sum。

安装脚本默认装最新的 nightly 每日构建版。想要稳定可复现,在命令末尾加版本号,本课锁定 1.0.2:

curl -fsSL https://pkg.lightpanda.io/install.sh | bash -s "1.0.2"
export PATH="$HOME/.local/bin:$PATH"

对照结果(节选):

=== Lightpanda Setup ===
Download version: 1.0.2
Install directory: /home/box/.local/bin
Detected: Linux x86_64
Fetching expected checksum from GitHub API...
Verifying checksum...
Checksum verified OK.
Lightpanda installed successfully!
Binary location: /home/box/.local/bin/lightpanda

脚本会从 GitHub 下载对应平台的二进制文件,并核对 SHA256 校验值。export PATH 那一行写进 ~/.bashrc 或 ~/.zshrc,以后打开终端就能直接用。

Lightpanda 默认会上报使用遥测数据。不想上报的话,设置官方提供的环境变量即可,本课后面的命令都在这个设置下运行:

export LIGHTPANDA_DISABLE_TELEMETRY=true

检查版本和可用命令:

lightpanda version
lightpanda version --check
lightpanda help

对照结果(节选):

1.0.2
You run the latest version 1.0.2
(help 列出的命令)agent  completion  fetch  help  mcp  run  serve  version

本课会用到其中三个:fetch 抓单页,serve 开 CDP 服务(第 2 课),mcp 开 MCP 服务(第 3 课)。

第 2 步:对比普通下载和 fetch

官方文档常用的练习站 quotes.toscrape.com 有一个 /js/ 版本,名言列表是页面加载后由 JavaScript 生成的。先用 curl 直接下载 HTML,数一下里面有几条名言:

curl -s https://quotes.toscrape.com/js/ | grep -c 'class="quote"'

对照结果:

0

结果是 0,因为原始 HTML 里只有脚本,没有内容。换成 Lightpanda,它会执行页面里的 JavaScript,再把渲染后的页面转成 Markdown:

lightpanda fetch --dump markdown https://quotes.toscrape.com/js/

对照结果(节选):

# [Quotes to Scrape](https://quotes.toscrape.com/)

[Login](https://quotes.toscrape.com/login)
“The world as we have created it is a process of our thinking.
It cannot be changed without changing our thinking.”by Albert Einstein
Tags: change deep\-thoughts thinking world

10 条名言都出来了。测试机上这条命令约 0.85 秒跑完,峰值内存约 30 MB(用 Python 的 resource 模块量的)。

--dump 支持这几种格式:html、markdown、semantic_tree、semantic_tree_text、pdf、png。其中 pdf 和 png 只是按文字排版画出来的,不是像素级截图。其中 semantic_tree_text 是给大模型看的简化语义树,每行带节点编号和角色:

lightpanda fetch --dump semantic_tree_text \
  https://quotes.toscrape.com/js/ | head -8

对照结果:

1 RootWebArea 'Quotes to Scrape'
 7 heading 'Quotes to Scrape'
  8 [i] link 'Quotes to Scrape'
 10 paragraph
  11 [i] link 'Login'
 14 '“The world as we have created it is a process of our thinking. ...”'
 16 'by'
 18 'Albert Einstein'

head 读够 8 行就关闭管道,Lightpanda 随后会在终端打印 err=WriteFailed 的日志,这是正常现象,不影响结果。

[i] 表示这个节点可以交互(能点击或输入)。

第 3 步:只取页面里的一部分

整页 Markdown 往往太长。--dump-selector 按 CSS 选择器只输出匹配的第一个元素:

lightpanda fetch --dump html --dump-selector '.quote .text' \
  https://quotes.toscrape.com/js/

对照结果:

<span class="text">“The world as we have created it is a process of our
thinking. It cannot be changed without changing our thinking.”</span>

(排版折行,实际输出是一行。)

文章类页面可以用 --strip-mode clutter 去掉导航、侧栏、页脚,只留正文。拿 Lightpanda 1.0 的发布博文对比一下:

U=https://lightpanda.io/blog/posts/lightpanda-1-0
lightpanda fetch --dump markdown "$U" > full.md
lightpanda fetch --dump markdown --strip-mode clutter "$U" > clean.md
wc -c full.md clean.md
head -3 clean.md

对照结果:

19490 full.md
15338 clean.md
# Lightpanda 1.0: Out of Beta and Ready for Production

full.md 开头是网站导航、登录注册链接,clean.md 直接从文章标题开始。--strip-mode 还可以取 js、css、ui、invisible、shell,要去掉多组时把这个参数重复写几次。

第 4 步:等异步内容加载完再抓

fetch 默认在页面 load 事件后输出。有些页面在 load 之后才用 XHR 或 fetch 请求数据,这时会抓到空内容。官方演示站 campfire-commerce 就是这样,价格是后加载的:

U=https://demo-browser.lightpanda.io/campfire-commerce/
lightpanda fetch --dump html --dump-selector '#product-price' "$U"

对照结果:

<h4 id="product-price"></h4>

价格是空的。有三种办法让它等一等:

# 办法一:等网络空闲
lightpanda fetch --wait-until networkidle \
  --dump html --dump-selector '#product-price' "$U"

# 办法二:等某个元素出现(评论区里第一个 h4)
lightpanda fetch --wait-selector '#product-reviews h4' \
  --dump html --dump-selector '#product-price' "$U"

# 办法三:等一段 JS 表达式为真
JS="document.querySelector('#product-price')?.textContent.includes('\$')"
lightpanda fetch --wait-script "$JS" \
  --dump html --dump-selector '#product-price' "$U"

三条命令的对照结果相同:

<h4 id="product-price">$244.99</h4>

--wait-until 可选 load、domcontentloaded、networkalmostidle、networkidle、done。默认最长等 5000 毫秒,可用 --wait-ms 调整。

用 --wait-script 时要注意:指定了 --wait-selector 或 --wait-script 后,官方默认不再先等 load,脚本在页面加载过程中就开始检查,元素可能还不存在。实测不加 ?. 时报错 Cannot read properties of null,并以 SelectorNotFound 退出。

第 5 步:批量抓取并输出 JSON

一次传多个网址时必须加 --json。结果是一个 JSON 对象,results 数组里每个网址一项:

lightpanda fetch --json --dump markdown --dump-max-bytes 200 \
  https://quotes.toscrape.com/js/ \
  https://quotes.toscrape.com/js/page/2/ \
  https://quotes.toscrape.com/nope-404 > multi.json
jq -r '.results[] | "\(.http_status) \(.url)"' multi.json
jq -r '.results[0] | keys | join(", ")' multi.json

对照结果:

200 https://quotes.toscrape.com/js/
200 https://quotes.toscrape.com/js/page/2/
404 https://quotes.toscrape.com/nope-404
bot_challenge, content, dump, error, headers, http_status, page_status, url

页面内容在 content 字段,dump 字段只记录输出格式(这里是 markdown)。--dump-max-bytes 200 把每页内容截到 200 字节,超出部分标 [truncated]。page_status 里有 JS 报错数等信息,排查时有用。

单个网址时,如果希望 4xx、5xx 让脚本失败,加 --fail-on-http-error:

lightpanda fetch --fail-on-http-error --dump markdown \
  https://quotes.toscrape.com/nope-404
echo "exit code: $?"

对照结果(节选):

$level=error $msg="page http error" ... status=404
exit code: 22

抓别人的网站时,加 --obey-robots 让 Lightpanda 先读取并遵守对方的 robots.txt。官方也提醒不要对小网站高频请求。

小结

  • 一行脚本装好 Lightpanda,bash -s "1.0.2" 锁定版本,LIGHTPANDA_DISABLE_TELEMETRY=true 关闭遥测
  • fetch --dump markdown 执行 JavaScript 后输出 Markdown,curl 拿不到的内容它能拿到
  • --dump-selector 取片段,--strip-mode clutter 只留正文
  • 异步加载的内容用 --wait-until networkidle、--wait-selector 或 --wait-script 等待
  • 多个网址用 --json 批量输出,正文在 content 字段;--fail-on-http-error 遇 4xx/5xx 退出码为 22

下一课用 serve 开 CDP 服务,让 Puppeteer、Playwright 和 Python 脚本驱动 Lightpanda。