
本文详解如何使用 Selenium 正确抓取具有统一类名的标题(.chunk-title)和段落(.p0),通过 DOM 层级关系实现“一标题配其下所有段落”的结构化提取,避免全局遍历导致的内容错位。
本文详解如何使用 selenium 正确抓取具有统一类名的标题(`.chunk-title`)和段落(`.p0`),通过 dom 层级关系实现“一标题配其下所有段落”的结构化提取,避免全局遍历导致的内容错位。
在网页爬虫实践中,常见一类结构:多个内容区块(chunk)以相同父容器组织,其中标题与正文分别位于不同子元素,但标题与段落之间并无直接父子嵌套关系——而是同级兄弟元素,或通过共同父节点关联。如目标网站中:
- 所有标题使用 ;
- 所有段落位于
内;...
- 每个 chunk-title 和其后紧邻的 chunk-content 属于同一逻辑章节,但 HTML 中它们是相邻的兄弟节点(而非嵌套)。
因此,若按原始代码方式——先全局提取所有 .chunk-title,再全局提取所有 p.p0——必然导致“标题 × 段落”笛卡尔式错配。根本解法是基于 DOM 结构定位逻辑区块,逐块处理。
✅ 正确做法:按“块单元”遍历,绑定局部上下文
应查找每个独立的语义单元(例如每个 .chunk 容器),再在其内部分别提取标题与段落,确保一对一映射:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() # Selenium 4.6+ 自动管理驱动 driver.get("https://library.municode.com/az/avondale/codes/code_of_ordinances?nodeId=CD_ORD_CH1GEPR") driver.maximize_window() # 等待主内容加载完成 wait = WebDriverWait(driver, 15) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "ul.chunks"))) # 定位所有 chunk 容器(每个代表一个完整条目) chunks = driver.find_elements(By.CSS_SELECTOR, "ul.chunks > li.chunk") with open("avondale_ordinances.txt", "w", encoding="utf-8") as f: for i, chunk in enumerate(chunks, 1): try: # 在当前 chunk 内查找标题(可能为空,需容错) title_elem = chunk.find_element(By.CLASS_NAME, "chunk-title") title_text = title_elem.text.strip() # 在当前 chunk 内查找所有段落(注意:p 元素在 chunk-content 下) para_elems = chunk.find_elements(By.CSS_SELECTOR, ".chunk-content p.p0") para_texts = [p.text.strip() for p in para_elems if p.text.strip()] # 写入结构化内容 f.write(f"--- Article {i} ---\n{title_text}\n\n") for para in para_texts: f.write(f"{para}\n\n") f.write("\n" + "="*60 + "\n\n") except Exception as e: print(f"跳过第 {i} 个区块(缺失标题或段落): {e}") continue print("✅ 文本已按标题-段落结构保存至 avondale_ordinances.txt") driver.quit()⚠️ 关键注意事项
- 不要跨块提取:driver.find_elements(By.CLASS_NAME, "chunk-title") 返回的是全页结果,脱离上下文;必须限定在单个 chunk 元素内调用 .find_element(s)。
- 显式等待优于 time.sleep():使用 WebDriverWait 确保目标元素真实可交互,提升稳定性与效率。
- 编码与换行处理:文件写入务必指定 encoding="utf-8",并用 \n\n 清晰分隔段落,避免文本粘连。
- 异常防御:部分区块可能无标题或无段落(如空节、广告位),需 try-except 包裹,防止中断整个流程。
- 多线程不适用:该任务为 I/O 密集型且依赖浏览器状态同步,多线程反而引发驱动冲突;如需提速,可考虑异步 HTTP 请求(配合 requests + BeautifulSoup)替代 Selenium,但需处理 JS 渲染内容。
✅ 总结
结构化网页抓取的核心原则是:以语义容器为单位,局部作用域内提取关联元素。与其强行“配对”,不如尊重 HTML 的层级逻辑——让每个 chunk 成为独立处理单元。这样既保证准确性,又提升代码可维护性与鲁棒性。
- 所有段落位于











