(五)用 CSS 选择器定位同一张卡片的字段
1. 选择范围与返回结果
| 写法 | 从当前节点开始选择的内容 |
|---|---|
article.book-card |
标签为 article、class 包含 book-card 的节点 |
main#catalog |
标签为 main、id 为 catalog 的节点 |
h2 a |
位于 h2 内部的 a,层数可以超过一层 |
ul.tags > li |
tags 列表的直接 li 子节点 |
a.detail[href] |
有 href 属性的 detail 链接 |
a[rel~="next"] |
rel 的空格分隔值中包含 next 的 a |
.select 交回匹配节点列表,.select_one 交回第一个匹配节点,没找到时为 None。先选中某个 article,再在它上面调用这两个方法,查找就限定在这张卡片里。
2. 平铺后配对会丢掉没有标签的书
# 项目文件:demos/selector_scope.py
# 错误示例的平铺 zip 丢掉没有标签的第二本;逐张卡片提取保留它。
from pathlib import Path
from bs4 import BeautifulSoup
html = (Path(__file__).resolve().parents[1] / "samples/cards.html").read_text(
encoding="utf-8"
)
soup = BeautifulSoup(html, "html.parser")
titles = soup.select("h2 a")
tag_groups = soup.select("ul.tags")
print(
"平铺数量",
len(titles),
len(tag_groups),
"配对后",
len(list(zip(titles, tag_groups))),
)
for card in soup.select("article.book-card"):
title = card.select_one("h2 a").get_text(" ", strip=True)
tags = [tag.get_text(strip=True) for tag in card.select("ul.tags > li")]
print(card["data-id"], title, tags)第一行是 平铺数量 2 1 配对后 1。标题有两个,标签组只有一个;zip 在较短的一边结束,所以第二本直接消失了。后面的逐卡片读取则得到:
b101 Python 入门 ['基础', '语法']
b102 NumPy 实践 []
字段之间的关系来自它们共同所在的 article,不能靠两份列表“恰好排在同一位置”来猜。第二本没有标签节点时,.select 得到空列表,书籍本身仍然保留。