在数据驱动的时代,网络爬虫已成为获取公开信息的重要工具。本文将通过完整源码示例,详细讲解如何使用Python的requests库实现HTTP请求,结合BeautifulSoup进行HTML解析,帮助开发者掌握基础爬虫开发技能。
一、环境准备与基础概念
1.1 核心库安装
bash
1pip install requests beautifulsoup4 lxml
2
requests:轻量级HTTP请求库,支持GET/POST等协议BeautifulSoup:HTML/XML解析库,提供DOM树遍历接口lxml:高性能解析器(比内置html.parser快5-10倍)
1.2 爬虫工作原理
- 请求阶段:模拟浏览器发送HTTP请求
- 解析阶段:将HTML转换为可操作的数据结构
- 提取阶段:定位目标数据并提取
- 存储阶段:将结果保存到文件或数据库
二、基础爬虫实现
2.1 豆瓣电影Top250爬取示例
python
1import requests
2from bs4 import BeautifulSoup
3import csv
4
5# 请求头配置
6headers = {
7 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
8}
9
10# 发送请求
11def fetch_page(url):
12 try:
13 response = requests.get(url, headers=headers, timeout=10)
14 response.raise_for_status()
15 response.encoding = response.apparent_encoding
16 return response.text
17 except Exception as e:
18 print(f"请求失败: {e}")
19 return None
20
21# 解析页面
22def parse_html(html):
23 soup = BeautifulSoup(html, 'lxml')
24 items = soup.find_all('div', class_='item')
25
26 results = []
27 for item in items:
28 rank = item.find('em').text
29 title = item.find('span', class_='title').text
30 rating = item.find('span', class_='rating_num').text
31 num_reviews = item.find('div', class_='star').find_all('span')[-1].text.strip('人评价')
32
33 quote_tag = item.find('span', class_='inq')
34 quote = quote_tag.text if quote_tag else '无简介'
35
36 results.append({
37 '排名': rank,
38 '电影名称': title,
39 '评分': rating,
40 '评价人数': num_reviews,
41 '简介': quote
42 })
43 return results
44
45# 主程序
46if __name__ == '__main__':
47 base_url = 'https://movie.douban.com/top250?start={}'
48 all_data = []
49
50 for page in range(0, 250, 25):
51 url = base_url.format(page)
52 html = fetch_page(url)
53 if html:
54 page_data = parse_html(html)
55 all_data.extend(page_data)
56 print(f"已抓取第{page//25 + 1}页数据")
57
58 # 保存CSV
59 with open('douban_top250.csv', 'w', newline='', encoding='utf-8-sig') as f:
60 writer = csv.DictWriter(f, fieldnames=all_data[0].keys())
61 writer.writeheader()
62 writer.writerows(all_data)
63 print("数据保存完成")
64
2.2 代码解析要点
- 请求头设置:通过
User-Agent模拟浏览器访问 - 异常处理:使用
try-except捕获网络请求异常 - 编码处理:
response.apparent_encoding自动检测编码 - DOM解析:
find_all():批量查找元素class_参数:注意末尾下划线(避免与Python关键字冲突)- 链式调用:
item.find().find()逐级定位
- 数据存储:使用
csv.DictWriter实现字典写入
三、进阶技巧
3.1 动态参数处理
当目标URL包含动态参数时(如分页的start=25),可通过字符串格式化实现:
python
1# 分页参数处理示例
2for page in range(0, 250, 25):
3 url = f'https://movie.douban.com/top250?start={page}'
4
3.2 复杂选择器应用
python
1# 使用CSS选择器定位元素
2soup.select('div.item > div.pic > a > img') # 层级选择
3soup.select('a[href^="https"]') # 属性选择(href以https开头)
4soup.select('span.inq:contains("人生")') # 文本内容选择(需配合其他库实现)
5
3.3 反爬策略应对
- IP限制:
- 使用代理IP池(如
proxies={'http':'120.194.55.139:6969'}) - 控制请求频率(
time.sleep(2))
- 使用代理IP池(如
- 验证码识别:
- 结合
pytesseract进行图形验证码识别 - 使用
selenium模拟人工操作
- 结合
- Cookie管理:
python
1# 维持会话示例
2session = requests.Session()
3session.get('https://www.douban.com') # 先访问登录页
4response = session.get('https://movie.douban.com/top250') # 后续请求携带Cookie
5
四、最佳实践
- 遵守robots协议:
- 访问
https://target.com/robots.txt查看爬取规则 - 避免高频请求(建议间隔3-5秒)
- 访问
- 数据清洗:
python
1# 去除空白字符
2title = item.find('span', class_='title').text.strip()
3
4# 处理异常值
5num_reviews = item.find('div', class_='star').find_all('span')[-1].text
6num_reviews = num_reviews.replace('人评价', '').strip() if '人评价' in num_reviews else '0'
7
- 日志记录:
python
1import logging
2
3logging.basicConfig(
4 filename='spider.log',
5 level=logging.INFO,
6 format='%(asctime)s - %(levelname)s - %(message)s'
7)
8
9logging.info(f"成功抓取第{page}页数据")
10
五、常见问题解决方案
5.1 编码乱码问题
python
1# 强制指定编码(当自动检测失效时)
2response.encoding = 'utf-8' # 或 'gbk'/'gb2312'
3
5.2 元素定位失败
- 使用浏览器开发者工具(F12)检查元素实际结构
- 尝试多种选择器组合:
python
1# 备用定位方案
2title = item.find('span', attrs={'class': 'title'}).text
3title = item.select_one('span.title').text
4
5.3 网络请求失败
- 检查目标网站是否启用反爬机制
- 增加重试机制:
python
1from requests.adapters import HTTPAdapter
2from urllib3.util.retry import Retry
3
4session = requests.Session()
5retries = Retry(total=3, backoff_factor=1)
6session.mount('http://', HTTPAdapter(max_retries=retries))
7session.mount('https://', HTTPAdapter(max_retries=retries))
8
9response = session.get(url)
10
六、总结
本文通过完整案例展示了Python爬虫开发的核心流程:
- 使用
requests实现稳定网络请求 - 通过
BeautifulSoup进行高效DOM解析 - 结合CSV模块实现结构化数据存储
- 介绍反爬策略应对方案
建议开发者在实际项目中:
- 优先使用官方API获取数据
- 严格控制爬取频率
- 做好异常处理和日志记录
- 定期更新User-Agent池
完整源码已通过Python 3.8+环境测试,可根据实际需求调整选择器逻辑和存储方式。掌握这些基础技能后,可进一步学习Scrapy框架或Selenium自动化测试工具,应对更复杂的爬取场景。