Python 现代开发学习笔记

(五)用 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 得到空列表,书籍本身仍然保留。

平铺提取会因标签组较少而截断配对,逐卡片提取则为第二本保留空标签列表

笔记正文与全部题解 · Ctrl / ⌘ K