柳嘉希

硕士研究生毕业生

软件工程师 | 可扩展的API · 网络爬虫 · 数据集成 · Vibe代码清理专家

BeautifulSoup 与 Selenium:静态解析和浏览器自动化怎么选

BeautifulSoup 和 Selenium 都能处理网页,但定位完全不同。

选择原则

如果页面 HTML 已经包含目标数据,用 BeautifulSoup。它快、简单、资源消耗低。

如果页面需要执行 JavaScript、登录、点击、滚动或处理动态内容,用 Selenium。

BeautifulSoup 初始化

from bs4 import BeautifulSoup
 
soup = BeautifulSoup(html_doc, "html.parser")

查找元素

first_p = soup.find("p")
all_links = soup.find_all("a")
title = soup.find("p", class_="title")

CSS 选择器:

links = soup.select("a.sister")
id_link = soup.select("#link1")
nested = soup.select("p.story a")

获取文本和属性:

text = soup.find("p").get_text()
href = soup.find("a").get("href")

修改和删除:

tag = soup.find("b")
tag.string = "New Title"
 
link = soup.find("a", id="link1")
link.decompose()

Selenium 初始化

from selenium import webdriver
 
driver = webdriver.Chrome()
driver.get("https://example.com")

常用浏览器操作:

driver.maximize_window()
driver.refresh()
driver.back()
driver.forward()
print(driver.current_url)
print(driver.title)

元素定位

from selenium.webdriver.common.by import By
 
driver.find_element(By.ID, "username")
driver.find_element(By.NAME, "email")
driver.find_element(By.CSS_SELECTOR, "button.submit")
driver.find_element(By.XPATH, "//div[@id='content']")

操作元素

input_box.send_keys("my_username")
input_box.clear()
button.click()
form.submit()

显式等待

动态页面必须等待条件,而不是盲目 sleep。

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 
element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located((By.ID, "username"))
)

复杂页面操作

滚动:

driver.execute_script("arguments[0].scrollIntoView();", element)

弹窗:

alert = driver.switch_to.alert
alert.accept()

iframe:

driver.switch_to.frame("iframe_name")
driver.switch_to.default_content()

截图:

driver.save_screenshot("page.png")
element.screenshot("element.png")

实践顺序通常是:静态 HTML 解析优先,其次解析页面内 JSON,最后才启动浏览器自动化。

延伸理解

复习这篇时,不要只记住名词,要把重点放在 静态 HTML 解析、Selenium 动态页面、等待策略、元素定位和反脆弱爬虫流程。这类知识如果只停留在定义层面,很容易在面试或项目中答得很散。更好的理解方式是把它放进一个具体场景:谁在调用它,输入从哪里来,失败后谁负责恢复,数据或状态会不会被重复处理。

  • 爬虫工程的难点通常不是发请求,而是页面变化、等待策略、去重、限速、异常恢复和数据质量。
  • 选择 BeautifulSoup、Selenium 或 Scrapy 时,要先判断页面是否动态、数据规模和后续清洗需求。
  • 可靠爬虫需要日志、断点续跑、失败重试和字段级校验,不能只依赖一次成功运行。

在真实项目中,可以把它当成一个判断框架:先确认输入、约束、失败场景和可观测性,再决定具体工具或写法。 如果一个方案看起来很简单,要继续追问它在规模扩大、权限变化、异常恢复和团队协作下是否仍然成立。

实践检查清单

  • 明确这个知识点在系统中的位置:是开发时约束、运行时能力、基础设施能力,还是协作流程。
  • 写出一个最小可运行例子,并补一个失败例子;只会写 happy path 说明理解还不够稳。
  • 记录常见误用:例如边界条件、权限假设、性能假设、同步/异步差异或环境差异。
  • 把概念和项目经历关联起来:如果面试被追问,可以用自己的项目说明为什么这样选。
  • 最后用一句话总结取舍:它牺牲了什么,换来了什么。

自测问题

  1. 这个主题解决的核心问题是什么?
  2. 如果不用当前方案,还有哪些替代方案?代价是什么?
  3. 最容易出错的边界条件在哪里?
  4. 如何在代码、测试或监控中验证它真的可靠?

项目化应用场景

可以把这类知识放到一个招聘信息或商品信息采集系统里理解:先判断页面是静态 HTML 还是动态渲染,再选择 BeautifulSoup、Selenium 或 Scrapy;采集后要做字段清洗、去重、失败重试和持久化。稳定爬虫的关键不是一次能抓到数据,而是页面结构变化、网络超时、反爬限制和部分字段缺失时仍然能恢复。

常见误区:

  • 直接写死脆弱 selector,没有 fallback。
  • 没有限速和重试,容易被封或丢数据。
  • 只保存原始数据,不做字段级质量检查。