Trafilatura 高级技巧:自定义提取、语言检测与性能优化

自定义提取策略、语言检测集成、离线 HTML 批量处理、缓存与增量更新——Trafilatura 进阶用法。

亿牛云技术团队2026年4月29日2 分钟阅读

自定义提取策略

排除特定元素

Trafilatura 允许在提取前对 HTML 进行预处理,排除不需要的部分:

import trafilatura
from lxml import html

# 下载 HTML
downloaded = trafilatura.fetch_url("https://example.com/article")

# 预处理:移除特定元素后再提取
tree = html.fromstring(downloaded)
for element in tree.xpath("//aside | //nav | //div[@class='sidebar']"):
    element.getparent().remove(element)

extracted_html = html.tostring(tree, encoding="unicode")
result = trafilatura.extract(extracted_html, output_format="markdown")

只提取特定区域

如果你的目标页面有明确的正文容器,可以缩小提取范围:

import trafilatura
from lxml import html

downloaded = trafilatura.fetch_url("https://example.com/article")
tree = html.fromstring(downloaded)

# 只提取 <article> 标签内的内容
article_elem = tree.xpath("//article")
if article_elem:
    article_html = html.tostring(article_elem[0], encoding="unicode")
    result = trafilatura.extract(article_html, output_format="markdown")
else:
    # 回退到全页提取
    result = trafilatura.extract(downloaded, output_format="markdown")

自定义保留标签

# 在 Markdown 输出中保留代码块和行内代码
result = trafilatura.extract(
    downloaded,
    output_format="markdown",
    include_formatting=True,  # 保留加粗/斜体/代码
    include_tables=True,      # 保留表格
)

语言检测

Trafilatura 可以集成语言检测,在处理多语言站点时自动识别内容语言:

pip install trafilatura[langid]

或使用更准确的 fasttext 模型:

pip install trafilatura[fasttext]

提取时检测语言

import trafilatura

downloaded = trafilatura.fetch_url("https://example.com/article")
result = trafilatura.extract(
    downloaded,
    output_format="json",
    with_metadata=True,
    target_language="zh",     # 可选:指定目标语言筛选
)

import json
data = json.loads(result)

# 使用 fasttext 检测语言
from trafilatura import language
lang = language.detect(data.get("text", ""))
print(f"检测到语言: {lang}")

按语言筛选

from trafilatura import language

# 检测并过滤非中文内容
text = "Some English text..."
lang, confidence = language.detect_with_confidence(text)
if lang == "zh" and confidence > 0.8:
    print("高质量中文内容")
检测引擎准确率速度安装
langid中等trafilatura[langid]
fasttext中等trafilatura[fasttext]

离线 HTML 批量处理

如果你已经有一个 HTML 文件目录,可以批量离线处理——不需要网络:

import os
import trafilatura
from pathlib import Path

html_dir = Path("./downloaded_pages")
output_dir = Path("./extracted_articles")
output_dir.mkdir(exist_ok=True)

for html_file in html_dir.glob("*.html"):
    with open(html_file, "r", encoding="utf-8") as f:
        html_content = f.read()

    result = trafilatura.extract(
        html_content,
        output_format="markdown",
        with_metadata=True,
    )

    if result:
        output_file = output_dir / f"{html_file.stem}.md"
        with open(output_file, "w", encoding="utf-8") as f:
            f.write(result)
        print(f"✅ {html_file.name} → {output_file.name}")

CLI 批量处理本地文件

# 处理 HTML 文件目录
trafilatura --input-dir ./downloaded_pages --output-dir ./articles

# 处理单个文件
trafilatura --input-file ./page.html --output-file ./article.md

提取速度优化

缓存下载结果

import hashlib
import json
import os
import requests
import trafilatura

CACHE_DIR = "./cache"

def cached_fetch(url):
    """带缓存的下载"""
    cache_key = hashlib.md5(url.encode()).hexdigest()
    cache_path = os.path.join(CACHE_DIR, f"{cache_key}.html")

    if os.path.exists(cache_path):
        with open(cache_path, "r", encoding="utf-8") as f:
            return f.read()

    os.makedirs(CACHE_DIR, exist_ok=True)
    resp = requests.get(url, proxies=PROXY, timeout=20)
    resp.encoding = "utf-8"

    with open(cache_path, "w", encoding="utf-8") as f:
        f.write(resp.text)

    return resp.text

配合缓存,增量更新时可以复用已下载的 HTML,只处理新增 URL。

批量初始化

Trafilatura 在第一次导入时会初始化一些资源。如果批量处理大量页面,可以提前预热:

# 预热——导入后做一次小提取,让模块完成初始化
import trafilatura
_ = trafilatura.extract("<html><body><p>warmup</p></body></html>")

限制处理范围

当页面非常大时,可以限制处理长度来提升速度:

# 只提取正文的前 10000 字符
result = trafilatura.extract(
    downloaded,
    output_format="txt",
    max_tree_size=10000,  # 限制解析的 DOM 节点数
)

增量更新策略

对于持续运行的采集任务,增量更新可以避免重复下载相同页面:

import json
import os
from datetime import datetime

STATE_FILE = "crawl_state.json"

def load_state():
    if os.path.exists(STATE_FILE):
        with open(STATE_FILE, "r") as f:
            return json.load(f)
    return {"processed_urls": [], "last_crawl": None}

def save_state(state):
    with open(STATE_FILE, "w") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

# 加载状态
state = load_state()
processed = set(state.get("processed_urls", []))

# 仅处理新 URL
new_urls = [u for u in all_urls if u not in processed]

for url in new_urls:
    # ... 下载和提取 ...
    processed.add(url)

# 保存状态
state["processed_urls"] = list(processed)
state["last_crawl"] = datetime.now().isoformat()
save_state(state)

总结

技巧适用场景关键代码
自定义元素排除页面有固定噪声区域lxml 预处理
限定提取区域页面结构清晰//article XPath
语言检测多语言采集trafilatura[fasttext]
离线批量已有 HTML 文件trafilatura --input-dir
下载缓存频繁重新处理MD5 缓存
增量更新长期运营任务JSON 状态文件

需要企业代理方案?

我们可根据目标站点、并发规模与稳定性目标提供定制方案。