kp-003
HTML/DOM 与 CSS 选择器思维
前置知识
本文基于模型知识整理,建议核对官方文档(见 参考资料)。
一句话定义
HTML 是描述页面结构的标记语言,浏览器将其解析为 DOM 树;CSS 选择器是在这棵树上「指哪打哪」的定位语法,也是爬虫抽取字段的基本功。
为什么重要
字段抽取的本质是「在树上找节点、读文本/属性」。选择器写得准,解析代码就短;选择器思维不牢,面对嵌套页面会反复试错。它同时是 kp-007(BS4 解析)、kp-008(XPath 进阶)、kp-012(渲染后抓取)的共同地基。
前置知识
kp-002(知道响应体里是 HTML)。
核心概念
- 元素/标签/属性:
<a href="/p/1" class="title">中a是标签,href/class是属性。 - DOM 树:浏览器把 HTML 解析成以节点为单位的树;解析库(BS4/lxml)构建的是同构的树。
- 语义化定位锚点:
class、id、data-*属性是定位首选锚点。 - CSS 选择器:
tag、.class、#id、A B(后代)、A > B(直接子代)、[attr=值]、:nth-child(n)。
原理与机制
选择器从右往左匹配(浏览器优化思路,解析库同理):先找出所有候选节点,再向上验证祖先链。理解这一点能解释「.list .item 与 .list > .item 为什么结果不同」。
html
└── body
└── div.product-list ← .list
├── div.product ← .item(直接子代)
│ ├── a.title
│ └── span.price
└── section.recommend ← 间接子代
└── div.product ← 用 > 时不会被选中
定位字段的标准工作流(在浏览器 DevTools 中完成):
- 右键目标内容 → 检查,定位到元素。
- 在 Elements 面板回溯到「最小重复单元」(一条列表项)。
- 找出该单元稳定的 class/结构特征,写出选择器。
- 在 Console 用
document.querySelectorAll(sel).length验证命中数量。
实例或案例
在练习站 books.toscrape.com 上抽取书名与价格:
# 选择器:article.product_pod(每本书)→ h3 a(书名)→ p.price_color(价格)
# 验证:document.querySelectorAll("article.product_pod").length → 20
每个 article.product_pod 就是一个可循环单元,字段从单元内部相对定位——这是所有列表页解析的通用模式。
常见误区
- 误区一:把「渲染后的 DOM」当成「源码里的 HTML」。 DevTools 看到的是 JS 执行后的树;若源码(右键查看源代码)里没有该节点,说明内容是动态渲染的,需走 kp-012 的路线。判断方法:Ctrl+U 查看源码搜索关键字。
- 误区二:选择器依赖绝对路径。
body > div:nth-child(3) > div > ul > li一改版就断;优先选语义 class 与data-*属性。 - 误区三:用正则解析 HTML。 HTML 不是正则可稳定解析的语言,嵌套与属性变化会制造无数边角案例;交给解析库。
自测题
.list .item与.list > .item的区别?
答:前者匹配任意深度的后代,后者只匹配直接子元素;后者更抗「嵌套区域内出现同名 class」的干扰。
- 如何快速判断内容是否为服务端渲染?
答:查看页面源代码(而非 DevTools Elements)搜索目标文本;搜到=服务端渲染,搜不到=前端渲染。
- 为什么优先用 class/
data-*而不是 nth-child?
答:语义锚点表达「是什么」,位置锚点表达「排第几」;页面增删节点后前者仍成立。
与其他知识点的关系
kp-007 把选择器变成 Python 调用;kp-008 扩展到 XPath 的文本函数与轴;kp-012 处理「源码里没有」的那一半世界。
延伸阅读
MDN「CSS 选择器」参考页;Chrome DevTools 官方文档的 Elements 面板一节。