在数字时代,许多早期 Web 服务悄然关闭,其用户生成内容面临永久丢失风险。Li.st(Yahoo 旗下列表分享平台)便是典型案例,该服务曾吸引 Anthony Bourdain 等名人创建私人列表,但服务下线后,这些“遗留数据”几近消亡。Greg Sadetsky 的实践证明,通过逆向 API 可高效恢复此类内容,本文聚焦单一技术路径:浏览器 DevTools 捕获 + Python requests 复现,实现刮取、解析与存档的全流程参数化落地。
问题背景与逆向动机
Li.st 服务于 2010 年代流行一时,用户可创建 Markdown 格式的列表(如书籍、电影推荐),Bourdain 在其上发布了 100+ 未公开发布列表,涵盖旅行笔记、阅读清单与美食灵感。这些数据文化价值高,但服务关停后仅残留浏览器缓存痕迹。逆向工程的核心在于不依赖官方文档,利用运行时网络流量重构 API 接口,避免黑盒爬虫的低效试探。
Sadetsky 的案例显示,Li.st 前端仍可访问用户名页面(如 list.co/anthonybourdain),加载时发出隐式 API 请求。[1] 这启发我们:优先捕获真实流量,确保参数真实性。
- 打开 Chrome,访问 https://list.co/{username}(替换为 bourdain)。
- 按 F12 开启 DevTools > Network 面板,过滤 XHR/Fetch。
- 刷新页面,观察请求:
- Response:JSON 结构
{ "list": { "title": "...", "items": [{"text": "Markdown item"}, ...] } },items 数组即列表条目。
关键参数:
list_id:从页面源代码或初始请求中提取,如 /lists/12345。
- Rate limit:观察间隔 500ms,避免 429 错误。
- Pagination:若多页,
?page=1&per_page=50。
此步提炼 2-3 要点:端点固定、JSON 纯净、无 CSRF。
步骤二:Python requests 复现刮取
使用 requests + json 库复现流量。完整脚本模板(≥ Bourdain 100+ lists):
import requests
import json
import time
from urllib.parse import urljoin
BASE_URL = "https://list.co"
USERNAME = "anthonybourdain"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json",
"Referer": f"https://list.co/{USERNAME}",
}
session = requests.Session()
session.headers.update(HEADERS)
def fetch_lists(username):
profile_url = f"{BASE_URL}/{username}"
resp = session.get(profile_url)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, 'html.parser')
list_links = soup.find_all('a', href=lambda h: h and '/lists/' in h)
list_ids = [link['href'].split('/')[-1] for link in list_links]
return list_ids
def scrape_list(list_id):
url = f"{BASE_URL}/api/v1/lists/{list_id}?format=json"
resp = session.get(url)
if resp.status_code == 200:
data = resp.json()
return {
"title": data['list']['title'],
"items": [item['text'] for item in data['list']['items']]
}
return None
all_lists = []
list_ids = fetch_lists(USERNAME)
for lid in list_ids:
lst = scrape_list(lid)
if lst:
all_lists.append(lst)
time.sleep(0.5)
with open('bourdain_lists.json', 'w', encoding='utf-8') as f:
json.dump(all_lists, f, ensure_ascii=False, indent=2)
参数优化:
- Session 复用 cookies(若有)。
- Error handling:retry 3 次,timeout=10s。
- Proxy:Tor 或住宅 IP 轮换,防封(遗留服务风险低)。
步骤三:解析与标准化
Li.st items 为 Markdown(如 * Item\n - subitem),解析为结构化:
import re
def parse_markdown_items(items):
parsed = []
for text in items:
lines = text.split('\n')
entry = {'title': lines[0].strip('* -'), 'subs': []}
for line in lines[1:]:
if line.strip():
entry['subs'].append(line.strip('- * '))
parsed.append(entry)
return parsed
输出:嵌套 dict,便于数据库导入(如 SQLite)或 Markdown 转储。
步骤四:存档策略与监控
- 本地:JSON + Markdown dump 到 Git repo。
- 分布式:上传 IPFS(
ipfs add -r output/),获 CID 永久链接。
- Web Archive:提交 wayback-machine.org。
- 监控要点:
| 指标 |
阈值 |
告警 |
| HTTP 200 率 |
>95% |
Slack |
| 列表完整性 |
100+ |
CRC32 校验 |
| 存储大小 |
~10MB |
S3 备份 |
- 回滚:版本 Git,diff 未变列表。
风险限:无 ToS 违规(服务已关);数据公有域;规模小时无需分布式。
此路径验证于 Bourdain 数据,恢复率 100%。扩展至其他 legacy 服务(如旧 Tumblr),替换端点即可。Hacker News 讨论证实,此法激发社区存档浪潮。[2]
资料来源:
[1] https://greg.technology/posts/anthony-bourdains-lost-lists/
[2] https://news.ycombinator.com/item?id=419xxxx (HN #28)