人人都会AI编程

21.1 基础爬虫:requests + BeautifulSoup /lxml 页面解析

更新时间:2026-07-12

基础爬虫的核心流程只有三步:发送请求 → 解析页面 → 提取数据。只要掌握了 requestsBeautifulSoup(或 lxml),你就可以应对绝大多数静态网页的数据采集需求。

第一步:发送请求,获取页面内容

requests 是目前最人性化的 HTTP 库,几行代码就能完成 GET、POST 请求,自动处理 cookies、 headers、编码等问题。

import requests

url = 'https://example.com'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.get(url, headers=headers, timeout=10)

# 检查状态码,确保请求成功
if response.status_code == 200:
    # 自动推断编码,防止乱码
    response.encoding = response.apparent_encoding
    html = response.text
else:
    print(f'请求失败,状态码:{response.status_code}')

必须养成的习惯

  • 设置 headers 中的 User-Agent,模拟浏览器访问,否则很多网站会直接拒绝。
  • 添加 timeout 参数,防止请求卡死导致程序永久等待。
  • 永远先检查状态码,不要盲目解析响应内容。

第二步:解析 HTML,定位数据

拿到 HTML 字符串后,需要用解析器把它变成能搜索、能提取数据的结构化对象。两种主流选择:

  • BeautifulSoup:易学易用,容错性强,适合初学者和页面结构较乱的网站。
  • lxml:速度更快,支持 XPath,更符合一些老手或 Scrapy 用户的使用习惯。
使用 BeautifulSoup 解析
from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')  # 或 'lxml',需要安装 lxml 库

# 根据标签、class、id 选取元素
title = soup.title.string  # 获取 <title> 标签的文本
all_links = soup.find_all('a')  # 所有链接

# 更精准的查找——组合条件
items = soup.find_all('div', class_='product-item')
for item in items:
    name = item.find('h2', class_='title').text
    price = item.find('span', class_='price').text
    print(name, price)

常用选取方法

  • find() / find_all():通过标签名、属性、文本等精确查找。
  • select():支持 CSS 选择器,写法更直观,如 soup.select('div.product-item h2.title')
使用 lxml 和 XPath 解析
from lxml import etree

tree = etree.HTML(html)

# 使用 XPath 提取
titles = tree.xpath('//div[@class="product-item"]/h2/text()')
prices = tree.xpath('//div[@class="product-item"]//span[@class="price"]/text()')

for title, price in zip(titles, prices):
    print(title.strip(), price.strip())

lxml 的优点:XPath 表达式在处理复杂嵌套结构时非常强大,而且 lxml 解析速度远快于 BeautifulSoup(使用 html.parser 时)。但如果页面结构很差(如标签不闭合),BeautifulSoup 的容错性会更友好。

第三步:数据清洗与存储

提取出来的文本常常带有空格、换行符等无用字符,需要简单清洗。

# 去除首尾空白字符
text = element.text.strip()
# 去掉多余换行
text = ' '.join(text.split())

清洗后的数据可以写入 CSV、JSON 或数据库。最方便的是用 Python 内置的 csv 模块。

import csv

with open('products.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['名称', '价格'])
    for name, price in zip(names, prices):
        writer.writerow([name.strip(), price.strip()])

完整示例:抓取某个列表页的数据

import requests
from bs4 import BeautifulSoup
import csv

headers = {'User-Agent': 'Mozilla/5.0 ...'}
url = 'https://example.com/products'

response = requests.get(url, headers=headers, timeout=10)
response.encoding = response.apparent_encoding

soup = BeautifulSoup(response.text, 'lxml')
items = soup.select('div.product')

results = []
for item in items:
    title = item.select_one('.title').text.strip()
    price = item.select_one('.price').text.strip()
    results.append([title, price])

# 保存
with open('data.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['产品名', '价格'])
    writer.writerows(results)

print(f'共抓取 {len(results)} 条数据')

常见坑点与解决方法

  1. 乱码问题

response.encoding = response.apparent_encoding 可自动解决 90% 的编码问题。如果仍然乱码,再手动尝试 'utf-8''gbk' 等。

  1. 被网站反爬
  • 确保 User-Agent 真实。
  • 不要频繁请求,加 time.sleep(1) 暂停。
  • 如果被封 IP,考虑使用代理(后面章节会介绍)。
  1. 动态加载页面(数据通过 JS 加载)

基础爬虫只能获取静态 HTML。遇到这种情况,改用 SeleniumPlaywright 或直接分析 Ajax 接口。

掌握了 requests + BeautifulSoup/lxml 这套组合,你已经能独立完成 80% 的日常爬虫任务。下一步是应对分页、登录、反爬等进阶场景,这些将在本章后续节中展开。