
本文详解为何使用 mw-parser-output 类无法提取 Wikisource 书籍正文,并提供两种可靠方案:一是精准定位 prp-pages-output 容器直接获取全文;二是通过 CSS 选择器跳过元信息,仅提取纯书籍内容。
本文详解为何使用 `mw-parser-output` 类无法提取 wikisource 书籍正文,并提供两种可靠方案:一是精准定位 `prp-pages-output` 容器直接获取全文;二是通过 css 选择器跳过元信息,仅提取纯书籍内容。
Wikisource 的 HTML 结构具有高度定制性,其页面并非简单线性排布,而是嵌套多层语义化容器。初学者常误用通用 MediaWiki 类名(如 mw-parser-output)定位正文,但该类在页面中重复出现两次:第一次出现在页首元数据区域(含作者、版本说明、导航链接等),第二次才包裹真正的书籍内容。而 soup.find() 默认返回首个匹配元素,导致提取结果为空或混入无关信息。
✅ 推荐方案一:直取 prp-pages-output 容器(简洁可靠)
Wikisource 为书籍正文专门设置了语义化类名 prp-pages-output(Page Rendering Plugin),它唯一且稳定地包裹全部章节文本。无需遍历子标签,调用 .get_text() 即可安全提取:
import requests
from bs4 import BeautifulSoup
def extract_text_simple(url):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# 精准定位书籍正文容器(唯一且语义明确)
text_section = soup.find("div", class_="prp-pages-output")
if not text_section:
raise ValueError("❌ 未找到 'prp-pages-output' 容器,请确认 URL 是否有效或页面结构是否变更")
# 一键提取所有可见文本,自动处理换行与空白
return text_section.get_text(strip=True)
except requests.RequestException as e:
print(f"⚠️ 网络请求失败: {e}")
return None
except Exception as e:
print(f"❌ 解析异常: {e}")
return None
# 示例调用
url = "https://fr.wikisource.org/wiki/Le_P%C3%A8re_Goriot_(1855)"
text = extract_text_simple(url)
print(f"✅ 成功提取 {len(text)} 字符\n{text[:200]}...")优势:代码简短、鲁棒性强、兼容多数 Wikisource 书籍页(法、英、中等语言站均采用此约定类名)。
✅ 推荐方案二:CSS 选择器精准过滤(纯正文专用)
若需严格排除页眉、页脚、导航栏等非正文内容(例如只保留小说章节段落),可利用 Wikisource 的结构特征:正文段落均位于 <div itemid> 元素之后的兄弟节点中。以下选择器 <code>div.prp-pages-output > div[itemid] ~ * 表示:
- 在
prp-pages-output容器内; - 找到首个带
itemid属性的div(即章节起始标记); - 选取其后所有同级兄弟元素(
~ *)——即真正的小说段落。
def extract_text_pure(url):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# 定位正文段落:跳过元信息,只取章节内容
text_elements = soup.select("div.prp-pages-output > div[itemid] ~ *")
if not text_elements:
raise ValueError("⚠️ 未检测到章节内容,请检查页面是否含 'div[itemid]' 标记")
# 清洗并拼接(保留段落分隔)
lines = [elem.get_text(strip=True) for elem in text_elements]
return "\n".join(line for line in lines if line) # 过滤空行
except Exception as e:
print(f"❌ 提取失败: {e}")
return None
# 使用示例
text_pure = extract_text_pure(url)
print(f"? 纯正文共 {len(text_pure)} 字符(不含元数据)")⚠️ 关键注意事项
-
User-Agent 必须设置:Wikisource 可能拒绝默认
requestsUA 请求。建议添加头部:headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"} response = requests.get(url, headers=headers, timeout=10) -
编码与语言适配:法文页面含 UTF-8 特殊字符,
response.text已自动解码,无需手动response.content.decode()。 -
反爬与频率控制:批量抓取时务必遵守
robots.txt(如https://fr.wikisource.org/robots.txt),添加time.sleep(1)避免被限流。 -
结构变动预警:Wikisource 插件更新可能导致
prp-pages-output类名变更。生产环境建议增加 fallback 逻辑(如回退至mw-parser-output的第二个匹配项)。
通过以上任一方案,您均可稳定、高效地从 Wikisource 提取高质量书籍文本,为后续 NLP 分析、文本存档或电子书生成奠定坚实基础。

















