
本文介绍使用BeautifulSoup自动化提取维基百科文章中各<h3>子章节的正文文本、内链URL及参考文献锚点,并按章节组织为Pandas DataFrame,适用于初学者掌握动态边界识别与树遍历技巧。
本文介绍使用beautifulsoup自动化提取维基百科文章中各`
`子章节的正文文本、内链url及参考文献锚点,并按章节组织为pandas dataframe,适用于初学者掌握动态边界识别与树遍历技巧。
在网页抓取实践中,一个常见难点是:如何准确界定每个逻辑章节的范围? 尤其在维基百科这类结构松散但语义清晰的页面中,章节并非由显式容器包裹,而是依赖标题标签(如<h3>)及其后连续的段落(<p>)、列表或引用块构成,直到下一个同级标题(如另一<h3>)或更高层级标题(如<h2>)出现为止。本文以《Machine learning》英文维基页面为例,系统讲解如何稳健提取“Artificial intelligence”至“Statistical Physics”之间的全部<h3>子章节内容,并构建含chapter(章节名)、text(纯文本)、links(所有<a>链接的href)、cite_ref(参考文献锚点如#cite_note-xx)四列的DataFrame。
核心思路:基于DOM树遍历的“标题驱动”分段
关键不在于硬编码段落数量(如[:3]),而在于利用HTML的兄弟节点关系与标签语义动态截断:
- 每个<h3>即为新章节起点;
- 使用.find_next_siblings()获取其后所有同级后续元素;
- 遍历时逐个判断:若为<p>,则提取文本与链接;若再次遇到<h3>,说明当前章节结束,立即break;
- 为防止越界(如误入后续<h2>主章节),可在特定章节名(如"Statistical Physics")后主动终止循环。
完整可运行代码示例
import pandas as pd
from bs4 import BeautifulSoup
import requests
url = "https://www.php.cn/link/71d779e5d91a630bc0f3cfc3a6db1d93"
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
data = []
# 遍历所有 h3 标题(即子章节)
for h3 in soup.select("h3"):
# 提取章节名:维基通常将标题文本放在 <span id="..."> 内
chapter_title = h3.find("span", {"id": True})
if not chapter_title:
continue # 跳过无id的h3(如空标题或装饰性标题)
chapter_name = chapter_title.get_text(strip=True)
# 初始化本章节数据字典
chapter_data = {
"chapter": chapter_name,
"text": "",
"links": [],
"cite_ref": []
}
# 向下遍历所有后续兄弟节点
for sibling in h3.find_next_siblings():
if sibling.name == "p":
# 累加段落文本(去首尾空白,避免换行符干扰)
chapter_data["text"] += " " + sibling.get_text(strip=True)
# 提取所有<a>标签的href(包括站内链接和锚点)
chapter_data["links"].extend([
a.get("href") for a in sibling.select("a[href]")
])
# 提取所有形如 #cite_note-xxx 的参考文献锚点链接
chapter_data["cite_ref"].extend([
c.get("href") for c in sibling.select("[id^=cite_ref] a[href]")
])
elif sibling.name in ["h3", "h2"]: # 遇到新章节或主章节,结束当前段落
break
data.append(chapter_data)
# 满足终点条件时提前退出(避免处理无关章节)
if chapter_name == "Statistical Physics":
break
# 构建DataFrame,自动处理列表字段(保持可读性)
df = pd.DataFrame(data)
print(df[["chapter", "text"]].head()) # 查看前几行章节名与文本摘要注意事项与优化建议
- ✅ 鲁棒性增强:实际应用中建议添加异常处理(如try/except捕获网络请求或解析失败)、设置requests超时与User-Agent头,避免被反爬拦截;
- ✅ 文本清洗:维基页面常含[1]类上标引用、编辑标记(如[edit]),可用正则(如re.sub(r'[d+]|\[edit\]', '', text))进一步清理;
- ✅ 链接去重与归一化:links列表可能含重复URL或相对路径(如/wiki/Python),建议用set()去重,并用urllib.parse.urljoin(base_url, href)转为绝对链接;
- ⚠️ 注意动态内容:维基部分区域(如信息框、脚注区)由JavaScript渲染,requests+BeautifulSoup无法获取,需改用Selenium或检查API(如https://en.wikipedia.org/w/api/rest_v1/page/html/Machine_learning);
- ? 扩展性提示:若需提取表格、代码块或图片,只需在sibling.name判断中增加"table"、"pre"、"img"等分支即可。
通过本方法,你不再需要手动计数段落,而是让代码“读懂”HTML的语义结构——这是进阶网络爬虫的核心能力。坚持练习此类DOM导航模式,复杂页面解析将变得清晰可控。

















