1. 爬虫基础与工具选型
爬虫本质上是一种自动化获取网页数据的技术。在Python生态中,Requests和BeautifulSoup这对黄金组合已经服务了无数开发者十余年。Requests负责网络通信,BeautifulSoup处理HTML解析,这种职责分离的设计让代码结构非常清晰。
我刚开始接触爬虫时也尝试过urllib标准库,但Requests的API设计确实更符合人类直觉。比如获取一个网页,用urllib需要7-8行代码处理异常和编码,而Requests只需要:
python复制response = requests.get('https://example.com')
response.encoding = 'utf-8'
BeautifulSoup的解析能力同样令人惊艳。它支持多种解析器:
- html.parser(内置无需安装)
- lxml(速度快但需要C库)
- html5lib(容错强但速度慢)
对于新手项目,我强烈建议先用html.parser。虽然速度不是最快,但避免了安装外部依赖可能带来的环境问题。等熟悉基础用法后,再考虑用lxml提升性能。
重要提示:正式爬取前务必检查网站的robots.txt文件(通常在域名后加/robots.txt)。有些网站明确禁止爬虫访问特定路径,遵守这些规则是开发者的基本素养。
2. 环境配置与请求发送
创建虚拟环境是Python项目的最佳实践:
bash复制python -m venv spider_env
source spider_env/bin/activate # Linux/Mac
spider_env\Scripts\activate # Windows
安装核心库:
bash复制pip install requests beautifulsoup4
发送GET请求时,这几个参数最常用:
python复制response = requests.get(
url='https://example.com/api',
params={'page': 1}, # 自动拼接查询参数
headers={'User-Agent': 'Mozilla/5.0'}, # 模拟浏览器
timeout=5 # 超时设置
)
处理响应时要注意:
- 状态码检查:
response.status_code == 200不总是代表成功,有些API错误也返回200 - 编码设置:中文网页常用
response.encoding = 'gbk'或'utf-8' - 内容类型:
response.headers['Content-Type']可以判断是HTML还是JSON
我常用的调试技巧:
python复制print(response.request.headers) # 查看实际发送的请求头
print(response.url) # 查看最终请求URL(含重定向)
3. HTML解析实战技巧
BeautifulSoup的基本使用模式:
python复制from bs4 import BeautifulSoup
soup = BeautifulSoup(html_text, 'html.parser')
title = soup.title.string # 获取标题文本
元素查找的三大方法:
find():返回第一个匹配元素find_all():返回所有匹配元素的列表- CSS选择器:
select()方法支持CSS语法
实际项目中,我总结出这些经验:
-
优先使用
class_参数而不是attrs,代码更简洁:python复制# 推荐 soup.find('div', class_='article') # 不推荐 soup.find('div', attrs={'class': 'article'}) -
处理相对链接时要用
urljoin:python复制from urllib.parse import urljoin absolute_url = urljoin(base_url, relative_path) -
文本提取时注意
string和get_text()的区别:python复制# 仅获取直接文本(可能为None) direct_text = element.string # 获取所有子节点文本(合并空白) full_text = element.get_text(strip=True)
4. 数据存储与反爬应对
最简单的存储方式是CSV:
python复制import csv
with open('data.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['标题', '链接']) # 表头
writer.writerow([title, url])
应对常见反爬措施:
- User-Agent轮换:准备多个浏览器UA随机使用
- 请求间隔:
time.sleep(random.uniform(1, 3)) - IP限制:使用免费代理(但稳定性差)或商业代理服务
- 验证码:考虑使用第三方打码平台
我常用的请求间隔方案:
python复制import random
import time
def random_delay():
delay = random.gauss(2, 0.5) # 均值2秒,标准差0.5
time.sleep(max(0, delay)) # 确保不小于0
5. 完整项目案例:图书信息抓取
以抓取豆瓣图书为例:
python复制import requests
from bs4 import BeautifulSoup
import csv
def scrape_douban_books():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
with open('books.csv', 'w', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['书名', '评分', '评价人数'])
for page in range(1, 6): # 抓取前5页
url = f'https://book.douban.com/top250?start={(page-1)*25}'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
for item in soup.select('tr.item'):
title = item.select_one('.pl2 a')['title']
rating = item.select_one('.rating_nums').text
votes = item.select_one('.pl').text.split()[-1]
writer.writerow([title, rating, votes])
time.sleep(2) # 礼貌性延迟
这个案例包含了:
- 分页处理
- CSS选择器使用
- 文本清洗(split取最后一段)
- 文件写入
- 基础反爬措施
6. 常见问题排查指南
Q1: 获取的内容是乱码怎么办?
A: 按顺序检查:
- 响应头中的charset:
response.encoding = response.apparent_encoding - 手动尝试常见编码:gbk、gb2312、utf-8
- 查看网页源码中的
<meta charset>标签
Q2: find_all返回空列表但网页明明有元素?
A: 可能原因:
- 元素是JavaScript动态加载的(需用Selenium)
- 使用了错误的解析器(尝试换lxml或html5lib)
- 有iframe嵌套(需要先定位iframe)
Q3: 遇到403 Forbidden错误?
A: 尝试:
- 添加完整的请求头(包括Referer、Cookie)
- 使用会话保持:
session = requests.Session() - 检查是否需要登录(模拟登录流程)
Q4: 如何抓取需要登录的网站?
A: 基本流程:
- 用浏览器登录后复制Cookie
- 在代码中添加Cookie头:
python复制headers = {'Cookie': 'your_cookie_string'} - 或者使用requests的Session对象自动管理
最后分享一个实用技巧:用prettify()方法可以格式化输出HTML,调试时非常有用:
python复制print(soup.prettify()) # 格式化打印整个文档
print(soup.find('div').prettify()) # 格式化打印特定元素