Python爬虫四大核心工具解析
在 Python 爬虫技术栈中,re
(正则)、XPath
、Beautiful Soup
、Selenium
分别对应 文本匹配、HTML 精准定位、HTML 友好解析、动态页面自动化 四大核心需求,是解决 “数据提取” 和 “动态页面突破” 的关键工具。以下从 核心含义、核心作用、关键用法、实战案例 四个维度逐一拆解,明确各工具的定位与边界:
一、re(正则表达式库)—— 通用文本匹配工具
1. 核心含义
re
是 Python内置的正则表达式库,无需额外安装,用于通过 “模式字符串” 匹配文本中符合特定规则的内容(如 IP 地址、URL、手机号、隐藏在 JS 中的接口地址)。它不依赖 HTML/XML 结构,本质是 “文本模式匹配引擎”。
2. 核心作用
解决 “非结构化文本提取” 问题 —— 当数据未包裹在 HTML 标签中(如 JS 代码里的变量、日志中的关键字、纯文本中的特定格式内容),或 HTML 解析库无法精准匹配时,用re
通过 “格式规则” 提取数据。
注意:re
不是为 HTML 解析设计的,避免用它直接解析完整 HTML(HTML 结构灵活,正则易因标签嵌套 / 属性变化失效)。
3. 关键知识点(核心语法)
核心方法 | 作用 | 示例 |
---|---|---|
re.compile(pattern) | 编译正则表达式(重复使用时提升效率,推荐优先使用) | ip_pattern = re.compile(r'\b(?:25[0-5]\.){3}25[0-5]\b') (匹配 IP) |
re.findall(pattern, text) | 提取文本中所有符合 pattern 的内容,返回列表 | ips = ip_pattern.findall(log_text) (从日志中提取所有 IP) |
re.search(pattern, text) | 匹配文本中第一个符合 pattern 的内容,返回Match 对象(需用group() 取值) | api_match = re.search(r'var api = "([^"]+)"', js_text) ;api = api_match.group(1) (从 JS 中提取 API 地址) |
re.sub(pattern, repl, text) | 替换文本中符合 pattern 的内容(如清理特殊字符) | clean_text = re.sub(r'\s+', ' ', messy_text) (将多个空格替换为单个空格) |
常用正则模式示例:
- 匹配 URL:
r'https?://[^\s"\']+'
(匹配 http/https 开头,到空格、双引号、单引号结束的 URL) - 匹配手机号:
r'1[3-9]\d{9}'
(匹配 11 位手机号,开头为 13-9)
4. 实战案例:从 JS 代码中提取接口地址
假设目标页面的 JS 代码包含:var goodsApi = "https://example.com/api/goods?page=1";
,用re
提取该接口:
import re
import requests# 1. 获取包含JS的页面HTML
url = "https://example.com/goods"
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0..."})# 2. 编译正则模式(匹配 var 变量名 = "接口地址")
api_pattern = re.compile(r'var goodsApi = "([^"]+)"') # () 捕获接口地址(排除双引号)# 3. 提取并打印接口
api_match = api_pattern.search(response.text)
if api_match:api_url = api_match.group(1) # group(1) 取第一个捕获组的内容print("提取的接口地址:", api_url) # 输出:https://example.com/api/goods?page=1
二、Beautiful Soup(BS4)—— 友好的 HTML/XML 解析库
1. 核心含义
Beautiful Soup
(简称 BS4)是 Python 第三方HTML/XML 解析库,需额外安装(pip install beautifulsoup4
)。它将 HTML 文本解析为 “树形结构”,提供人类友好的 API(如find
、find_all
),无需懂复杂的 DOM 操作,即可快速定位和提取标签内的数据。
2. 核心作用
解决 “HTML 标签数据提取繁琐” 问题 —— 针对结构相对规整的静态 HTML(如新闻列表、商品详情页),通过 “标签名 + 属性”(如div class="product-name"
)定位数据,比re
更稳定,比XPath
更易上手。
3. 关键知识点(核心用法)
(1)解析器选择(必须指定,推荐lxml
)
BS4 本身不具备解析能力,需依赖第三方解析器,优先级:
lxml
:速度最快、容错性强(需安装pip install lxml
),推荐首选;html.parser
:Python 内置,无需额外安装,速度慢,适合简单场景;html5lib
:兼容 HTML5 语法,速度最慢,极少用。
(2)核心方法
方法 | 作用 | 示例 |
---|---|---|
soup = BeautifulSoup(html, "lxml") | 初始化解析对象,将 HTML 转为树形结构 | soup = BeautifulSoup(response.text, "lxml") |
soup.find(tag, attrs) | 提取单个符合条件的标签(找不到返回None ) | name_tag = soup.find("h3", class_="product-name") (找 class 为 product-name 的 h3 标签,注意 class_带下划线,避免与 Python 关键字冲突) |
soup.find_all(tag, attrs) | 提取所有符合条件的标签,返回列表(找不到返回空列表) | price_tags = soup.find_all("span", class_="current-price") (找所有 class 为 current-price 的 span 标签) |
tag.text | 提取标签内的纯文本(自动去除标签和多余空格) | product_name = name_tag.text.strip() (获取商品名称并清理空格) |
tag["属性名"] | 提取标签的属性值(如href 、src ) | product_link = soup.find("a")["href"] (获取 a 标签的链接) |
4. 实战案例:解析电商商品列表
假设目标页面的商品列表 HTML 结构:
<ul class="goods-list"><li class="goods-item"><h3 class="goods-name">2024新款笔记本电脑</h3><span class="goods-price">¥4999</span><a href="/goods/123" class="goods-link">查看详情</a></li><li class="goods-item">...</li> <!-- 更多商品 -->
</ul>
用 BS4 提取所有商品的 “名称 + 价格 + 链接”:
from bs4 import BeautifulSoup
import requests# 1. 获取页面HTML
url = "https://example.com/goods-list"
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0..."})# 2. 初始化BS4解析对象
soup = BeautifulSoup(response.text, "lxml")# 3. 提取所有商品项(li标签,class为goods-item)
goods_items = soup.find_all("li", class_="goods-item")# 4. 遍历提取数据
for item in goods_items:# 商品名称name = item.find("h3", class_="goods-name").text.strip()# 商品价格price = item.find("span", class_="goods-price").text.strip()# 商品链接link = item.find("a", class_="goods-link")["href"]# 打印结果print(f"名称:{name} | 价格:{price} | 链接:https://example.com{link}")
三、XPath —— 精准的 HTML/XML 路径查询语言
1. 核心含义
XPath
(XML Path Language)是用于定位 XML/HTML 文档中节点的语言,不是 Python 库,需通过lxml
库(pip install lxml
)在 Python 中实现。它通过 “路径表达式” 描述节点在树形结构中的位置,比 BS4 更精准、更灵活,尤其适合复杂层级的标签定位。
2. 核心作用
解决 “复杂 HTML 层级定位难” 问题 —— 当数据嵌套在多层标签中(如div[id="main"]/ul/li/div[2]/span
),或需要按 “标签属性 + 文本内容” 组合筛选时,XPath 比 BS4 更简洁高效(一行表达式即可定位,无需多次find
)。
3. 关键知识点(核心语法)
(1)基础路径表达式
表达式 | 作用 | 示例 |
---|---|---|
/ | 从根节点开始,匹配直接子节点(严格层级,类似文件路径) | /html/body/div (匹配根节点 html 下的 body 下的直接 div 子节点) |
// | 从任意节点开始,匹配所有符合条件的节点(忽略层级,最常用) | //li[@class="goods-item"] (匹配所有 class 为 goods-item 的 li 节点,无论层级) |
@ | 匹配标签的属性(用于筛选属性或获取属性值) | //a/@href (获取所有 a 标签的 href 属性值);//div[@id="main"] (匹配 id 为 main 的 div 节点) |
text() | 匹配标签内的文本内容(用于提取文本或筛选含特定文本的标签) | //h3/text() (获取所有 h3 标签的文本);//span[text()="¥4999"] (匹配文本为 ¥4999 的 span 节点) |
[] | 条件筛选(支持and /or 逻辑、索引) | //li[@class="goods-item" and @data-id="123"] (匹配 class 为 goods-item 且 data-id 为 123 的 li 节点);//div[@id="main"]/ul/li[1] (匹配 ul 下的第 1 个 li 节点,索引从 1 开始) |
.. | 匹配当前节点的父节点(较少用,用于反向定位) | //span[@class="goods-price"]/.. (匹配 class 为 goods-price 的 span 节点的父节点) |
(2)Python 中使用 XPath
通过lxml.etree.HTML()
将 HTML 转为可解析的对象,再用xpath()
方法执行表达式:
from lxml import etree
tree = etree.HTML(html_text) # 初始化XPath解析对象
result = tree.xpath(xpath_expr) # 执行XPath表达式,返回列表(文本/属性值/节点)
4. 实战案例:用 XPath 提取电商商品数据
沿用上述电商商品列表 HTML,用 XPath 提取 “名称 + 价格 + 链接”(一行表达式对应一类数据,无需遍历多次):
from lxml import etree
import requests# 1. 获取页面HTML
url = "https://example.com/goods-list"
response = requests.get(url, headers={"User-Agent": "Mozilla/5.0..."})# 2. 初始化XPath解析对象
tree = etree.HTML(response.text)# 3. 用XPath提取数据(返回列表)
# 商品名称:所有li[goods-item]下的h3文本
names = tree.xpath('//li[@class="goods-item"]/h3[@class="goods-name"]/text()')
# 商品价格:所有li[goods-item]下的span[goods-price]文本
prices = tree.xpath('//li[@class="goods-item"]/span[@class="goods-price"]/text()')
# 商品链接:所有li[goods-item]下的a[goods-link]的href属性
links = tree.xpath('//li[@class="goods-item"]/a[@class="goods-link"]/@href')# 4. 打包输出(用zip关联三类数据)
for name, price, link in zip(names, prices, links):print(f"名称:{name.strip()} | 价格:{price.strip()} | 链接:https://example.com{link}")
四、Selenium —— 浏览器自动化工具
1. 核心含义
Selenium
是用于 Web 自动化测试的工具,需额外安装(pip install selenium
),支持控制 Chrome、Firefox 等真实浏览器,模拟人类操作(打开页面、点击按钮、输入文本、滚动页面)。在爬虫中,它主要解决 “requests 无法执行 JavaScript” 的问题 —— 针对动态渲染页面(如 Vue/React 项目、点击加载更多、登录后的数据),获取浏览器渲染后的完整 HTML。
2. 核心作用
解决 “动态页面数据提取” 问题 —— 当页面数据通过 JS 动态加载(如滚动到底部加载更多商品、点击 “展开” 显示详情),或数据在初始 HTML 中不存在(仅在 JS 执行后生成),requests 无法获取数据,此时用 Selenium 控制浏览器渲染页面,再提取数据。
3. 关键知识点(核心用法)
(1)环境依赖
- 浏览器驱动:需下载与浏览器版本匹配的驱动(如 Chrome 对应
chromedriver
,Firefox 对应geckodriver
),或用webdriver-manager
自动管理驱动(pip install webdriver-manager
,推荐); - 无头模式:通过配置
--headless=new
,可在无可视化界面的服务器上运行(节省资源,提升速度)。
(2)核心操作
操作 | 作用 | 示例 |
---|---|---|
启动浏览器 | 初始化浏览器对象(Chrome 为例) | from selenium.webdriver import Chrome; from selenium.webdriver.chrome.options import Options ;opts = Options(); opts.add_argument("--headless=new") ;driver = Chrome(options=opts) |
打开页面 | 访问目标 URL,等待页面加载 | driver.get("https://example.com/goods") |
定位元素 | 找到页面中的按钮、输入框等元素(支持 XPath、CSS 选择器等) | from selenium.webdriver.common.by import By ;load_btn = driver.find_element(By.XPATH, '//button[text()="加载更多"]') (用 XPath 找 “加载更多” 按钮) |
模拟操作 | 点击、输入、滚动等操作 | load_btn.click() (点击按钮);driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") (滚动到底部) |
提取渲染后 HTML | 获取浏览器渲染后的完整 HTML,交给 BS4/lxml 解析 | html = driver.page_source ;soup = BeautifulSoup(html, "lxml") |
关闭浏览器 | 释放资源(必须执行,避免内存泄漏) | driver.quit() |
4. 实战案例:爬取动态加载的商品列表
假设目标页面需 “点击 5 次加载更多” 才能显示所有商品,用 Selenium 模拟操作:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time# 1. 配置浏览器(无头模式)
opts = Options()
opts.add_argument("--headless=new") # 无界面运行
opts.add_argument("--user-agent=Mozilla/5.0...") # 模拟浏览器UA# 2. 启动浏览器
driver = webdriver.Chrome(options=opts)
try:# 3. 打开目标页面driver.get("https://example.com/goods")time.sleep(2) # 等待页面初始加载# 4. 模拟点击“加载更多”5次for _ in range(5):try:# 找到“加载更多”按钮并点击load_btn = driver.find_element(By.XPATH, '//button[text()="加载更多"]')load_btn.click()time.sleep(1.5) # 等待新数据加载(避免过快点击导致失败)except:break # 按钮消失(无更多数据),停止点击# 5. 获取渲染后的完整HTML,用BS4解析soup = BeautifulSoup(driver.page_source, "lxml")goods_items = soup.find_all("li", class_="goods-item")# 6. 提取并打印数据print(f"共找到 {len(goods_items)} 个商品:")for item in goods_items:name = item.find("h3", class_="goods-name").text.strip()price = item.find("span", class_="goods-price").text.strip()print(f"名称:{name} | 价格:{price}")
finally:driver.quit() # 确保关闭浏览器
五、工具选型对比(实战避坑指南)
工具 | 适用场景 | 优点 | 缺点 | 优先级(爬虫) |
---|---|---|---|---|
re | 非结构化文本(JS 变量、日志、纯文本) | 通用、灵活、内置无需安装 | 不适合解析 HTML(易因结构变化失效) | 仅用于文本匹配,不用于 HTML 解析 |
Beautiful Soup | 结构规整的静态 HTML、入门学习 | 语法友好、易上手、容错性强 | 速度慢、复杂层级定位繁琐 | 静态 HTML 入门首选,复杂场景用 XPath |
XPath | 复杂层级 HTML、精准定位、多条件筛选 | 速度快、表达式简洁、定位精准 | 语法需学习,依赖 lxml 库 | 静态 HTML 复杂场景首选 |
Selenium | 动态渲染页面(JS 加载、点击操作、登录) | 能处理所有页面(模拟真实浏览器) | 性能消耗大、速度慢、需浏览器环境 | 最后选择(优先找 API,无 API 再用 Selenium) |
六、总结
- 数据在静态 HTML 标签中:用
Beautiful Soup
(入门)或XPath
(复杂场景); - 数据在非标签文本中(JS / 日志):用
re
; - 数据需 JS 渲染(动态页面):用
Selenium
(先尝试找 API,无 API 再用)。
这四个工具不是互斥关系,而是 “互补组合”—— 比如 Selenium 获取渲染后的 HTML,再用 XPath 提取数据,最后用 re 清理文本格式,共同构成完整的爬虫数据提取链路。