最近在整理Python爬虫的教学资料,发现很多初学者对数据采集的基础流程掌握不够扎实。今天我就以豆瓣读书Top250为例,手把手带大家走一遍完整的网页数据采集流程。这个案例涵盖了从网页分析、请求发送、数据解析到存储的完整环节,非常适合刚入门爬虫的朋友练手。
豆瓣读书Top250页面结构清晰,数据量适中(共250条记录),且不需要处理复杂的登录验证,是学习基础爬虫技术的理想对象。通过这个案例,你将掌握如何用Python的requests库发送HTTP请求,用BeautifulSoup解析HTML,以及如何将采集到的数据保存为JSON格式。
注意:爬取数据时请遵守网站的robots.txt协议,控制请求频率,避免对目标服务器造成过大压力。
在开始之前,我们需要安装三个核心Python库:
bash复制pip install requests beautifulsoup4 lxml
现代浏览器都内置了开发者工具(按F12或右键"检查"打开),这是我们分析网页结构的利器。重点关注以下几个功能:
在Network面板中,我们可以找到关键的请求头信息,比如User-Agent,这是模拟浏览器行为的重要参数。
打开豆瓣读书Top250页面(https://book.douban.com/top250),观察页面布局:
<tr>标签内<td>标签的不同位置通过查看网页源代码,我们发现分页是通过URL参数start控制的,例如:
为了避免被网站识别为爬虫,我们需要设置合理的请求头。最关键的是User-Agent,它告诉服务器我们使用的是哪种浏览器:
python复制headers = {
"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"
}
发送请求的完整代码:
python复制import requests
url = "https://book.douban.com/top250"
params = {"start": 0} # 第一页
response = requests.get(url, headers=headers, params=params)
print(response.status_code) # 应该返回200
提示:实际项目中应该添加异常处理,考虑网络超时、服务器错误等情况。
BeautifulSoup将HTML文档转换为一个复杂的树形结构,我们可以通过各种方法查询和提取数据:
python复制from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, "lxml")
books = soup.select("tr.item") # 选择所有书籍行
每本书的信息分布在多个<td>标签中,我们需要仔细分析DOM结构:
python复制for book in books:
# 书名在第一个td的div > a标签内
title = book.select_one("td:nth-of-type(2) div a")["title"]
# 作者、出版社等信息在p标签内
info = book.select_one("td:nth-of-type(2) p").get_text(strip=True)
# 评分在span class="rating_nums"内
rating = book.select_one("span.rating_nums").get_text(strip=True)
# 评价人数在span class="pl"内
rating_count = book.select_one("span.pl").get_text(strip=True)[1:-1] # 去掉括号
网页文本中常包含多余的空格、换行符等,需要清理:
python复制def clean_text(text):
return " ".join(text.split()).strip() # 合并多个空格为一个
将重复代码封装成函数,使逻辑更清晰:
python复制def get_page(page_num):
"""获取指定页码的HTML内容"""
params = {"start": (page_num - 1) * 25}
response = requests.get(url, headers=headers, params=params)
return response.text if response.status_code == 200 else None
def parse_page(html):
"""解析HTML页面,提取书籍信息"""
soup = BeautifulSoup(html, "lxml")
books = []
for item in soup.select("tr.item"):
book = {
"title": clean_text(item.select_one("div.pl2 a")["title"]),
"info": clean_text(item.select_one("p.pl").get_text()),
"rating": item.select_one("span.rating_nums").get_text(),
"rating_count": clean_text(item.select_one("span.pl").get_text())[1:-1]
}
books.append(book)
return books
使用循环爬取所有页面:
python复制all_books = []
for page in range(1, 11): # 豆瓣Top250共10页
html = get_page(page)
if html:
all_books.extend(parse_page(html))
time.sleep(2) # 礼貌性延迟,避免请求过于频繁
将采集到的数据保存为JSON文件:
python复制import json
import os
def save_to_json(data, filename, path="data"):
"""保存数据到JSON文件"""
if not os.path.exists(path):
os.makedirs(path)
filepath = os.path.join(path, filename)
with open(filepath, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
采集完成后可能需要对数据进行清洗:
python复制# 去除重复数据(基于书名)
unique_books = {book["title"]: book for book in all_books}.values()
# 转换评分和评价人数为数值类型
for book in unique_books:
book["rating"] = float(book["rating"])
book["rating_count"] = int(book["rating_count"].replace(",", ""))
可能原因及解决方案:
调试技巧:
处理中文编码:
python复制response.encoding = "utf-8" # 确保正确解码
掌握了基础爬虫技术后,你可以尝试以下扩展:
在实际项目中,我还发现豆瓣的页面结构偶尔会有小的调整,所以健壮的爬虫应该:
爬虫开发最重要的是耐心和细心,遇到问题时多分析网页源代码,逐步调试每个环节。这个豆瓣Top250的案例虽然简单,但涵盖了爬虫开发的核心技术栈,是很好的练手项目。