智能爬取:用 Trafilatura 发现和抓取整站内容
自动解析 Sitemap 和 RSS Feed 发现全站页面,URL 去重与过滤,配合代理实现整站内容采集。
亿牛云技术团队2026年4月23日2 分钟阅读
从 Sitemap 发现 URL
Trafilatura 可以自动解析网站的 Sitemap 文件(XML 和 TXT 格式):
import trafilatura
# 自动发现并解析 sitemap
urls = trafilatura.sitemaps.sitemap_search("https://example.com")
print(f"发现 {len(urls)} 个 URL")
# 查看前 10 个
for url in urls[:10]:
print(url)
sitemap_search() 会自动尝试常见路径(/sitemap.xml、/sitemap_index.xml)并解析嵌套的 sitemap 索引文件。
指定 sitemap URL
from trafilatura.sitemaps import parse_sitemap
# 直接指定 sitemap URL
urls = parse_sitemap("https://example.com/sitemap.xml")
print(f"从 sitemap 提取了 {len(urls)} 个 URL")
URL 过滤
发现大量 URL 后,通常需要筛选目标:
# 只保留 /blog/ 路径下的文章
blog_urls = [u for u in urls if "/blog/" in u]
# 排除特定路径
filtered = [u for u in urls if not "/tag/" in u and not "/author/" in u]
# 限定域名
same_domain = [u for u in urls if u.startswith("https://example.com")]
| 过滤方式 | 代码 | 适用场景 |
|---|---|---|
| 路径前缀 | url.startswith("https://example.com/blog/") | 只采集博客 |
| 路径包含 | "/article/" in url | 只采集文章页 |
| 排除模式 | "/tag/" not in url | 排除标签页 |
| 正则匹配 | re.search(r"/\d{4}/\d{2}/", url) | 匹配日期路径 |
从 RSS/ATOM Feed 获取更新
适合持续追踪更新的站点:
from trafilatura.feeds import find_feed_urls, parse_feed
# 自动发现 feed
feed_urls = find_feed_urls("https://example.com")
print(f"发现 {len(feed_urls)} 个 feed")
# 解析 feed 中的文章
for feed_url in feed_urls:
entries = parse_feed(feed_url)
for entry in entries:
print(f"{entry.title}: {entry.url}")
支持格式:RSS 2.0、ATOM、JSON Feed。
增量更新策略
import json
from trafilatura.feeds import find_feed_urls, parse_feed
# 加载已处理的 URL
try:
with open("processed_urls.json", "r") as f:
processed = set(json.load(f))
except FileNotFoundError:
processed = set()
# 获取最新 feed
feed_urls = find_feed_urls("https://example.com/blog")
new_articles = []
for feed_url in feed_urls:
entries = parse_feed(feed_url)
for entry in entries:
if entry.url not in processed:
new_articles.append(entry.url)
print(f"新增 {len(new_articles)} 篇文章")
# 保存已处理列表
processed.update(new_articles)
with open("processed_urls.json", "w") as f:
json.dump(list(processed), f)
组合使用:自动发现并提取
import trafilatura
from trafilatura.sitemaps import sitemap_search
from trafilatura.feeds import find_feed_urls, parse_feed
# 1. 从 sitemap 发现历史文章
sitemap_urls = sitemap_search("https://example.com")
blog_urls = [u for u in sitemap_urls if "/blog/" in u]
# 2. 从 feed 发现最新文章
feed_urls = find_feed_urls("https://example.com/blog")
feed_article_urls = []
for feed_url in feed_urls:
entries = parse_feed(feed_url)
feed_article_urls.extend([e.url for e in entries])
# 3. 合并去重
all_urls = list(set(blog_urls + feed_article_urls))
print(f"共发现 {len(all_urls)} 篇独立文章")
# 4. 批量提取正文
for url in all_urls[:5]: # 先试前 5 篇
downloaded = trafilatura.fetch_url(url)
result = trafilatura.extract(downloaded, output_format="markdown")
if result:
print(f"✅ {url}")
配合代理进行整站采集
使用 16YUN API 代理时,可以先提取 IP 列表,再分配给批量请求:
import trafilatura
import requests
import random
# 用 API 代理提取一批 IP
api_url = "http://ip.16yun.cn:817/myip/pl/xxx/?s=xxx&u=user&format=json&count=20"
response = requests.get(api_url)
proxy_list = response.json() # 返回 [{ip:port}, ...]
# 批量提取正文——每次随机选一个代理
for url in all_urls:
proxy = random.choice(proxy_list)
proxies = {
"http": f"http://user:pass@{proxy['ip']}:{proxy['port']}",
"https": f"http://user:pass@{proxy['ip']}:{proxy['port']}",
}
try:
resp = requests.get(url, proxies=proxies, timeout=15)
resp.encoding = "utf-8"
result = trafilatura.extract(resp.text, output_format="markdown")
if result:
# 保存结果
with open(f"articles/{url.split('/')[-1]}.md", "w") as f:
f.write(result)
print(f"✅ {url}")
except Exception as e:
print(f"❌ {url}: {e}")
错误处理要点
参照 16YUN 帮助文档中的错误码处理:
| 状态码 | 原因 | 应对 |
|---|---|---|
| 429 | 请求频率过高 | 降低并发、增加间隔、更换 IP |
| 407 | 代理认证失败 | 核对用户名密码 |
| 504 | 目标站超时 | 重试 2-3 次,跳过持续失败页面 |
CLI 方式
# 通过 sitemap 发现 URL
trafilatura --sitemap https://example.com/sitemap.xml
# 通过 feed 发现 URL
trafilatura --feed https://example.com/feed.xml
# 从 URL 列表文件批量提取
trafilatura --list urls.txt --output-dir ./articles
注意事项
- Sitemap 可能包含大量 URL(数万甚至百万级),建议先过滤再提取
- 注意 robots.txt 的爬取限制,控制请求频率
- 长期运行的采集任务建议加入断点续传机制,记录已处理的 URL
- 配合 16YUN 爬虫代理的隧道模式可以简化代理管理——设置一个入口即可
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。