第 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。
课程目录第 1 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
图文教材
本课对照的官方页面:一行脚本安装、命令说明、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。
