ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python爬虫实战:豆瓣电影评论数据采集与分析

Python爬虫实战:豆瓣电影评论数据采集与分析

1. 项目概述:爬取豆瓣电影评论的实用价值

爬取豆瓣电影评论是Python学习者最常接触的实战项目之一。作为国内最具影响力的影视评分平台,豆瓣积累了海量真实用户生成的影评数据。这些数据对电影市场分析、观众情感倾向研究、影视推荐算法优化都具有重要价值。

我最初接触这个项目是在2016年,当时需要为某影视公司做市场调研。手动收集数据效率太低,于是开始研究用Python自动化获取评论。经过多次迭代,现在这套方法已经相当成熟,可以帮助你快速获取结构化评论数据。

这个项目适合:

  • Python初学者想通过实战巩固requests、BeautifulSoup等库的使用
  • 数据分析师需要获取原始评论数据进行情感分析
  • 影视从业者希望了解观众对某部电影的真实反馈
  • 任何对网络数据采集感兴趣的学习者

2. 技术选型与工具准备

2.1 为什么选择Python做爬虫?

Python在爬虫领域有不可替代的优势:

  1. 丰富的库生态:requests、BeautifulSoup、Scrapy等成熟工具链
  2. 简洁的语法:相比Java等语言,代码更易写易读
  3. 强大的数据处理能力:获取的数据可直接用pandas等库分析

我尝试过用Node.js和Go写爬虫,但最终都回归Python,因为调试和修改效率更高。特别是处理反爬机制时,Python可以快速调整策略。

2.2 核心工具安装

pip install requests beautifulsoup4 pandas
  • requests:比urllib更人性化的HTTP库
  • BeautifulSoup4:HTML解析神器
  • pandas:数据清洗和存储的瑞士军刀

注意:建议使用Python 3.7+版本,避免某些库的兼容性问题。我曾在3.5环境遇到bs4的解析异常,升级后解决。

2.3 开发环境配置

推荐使用VS Code + Python插件:

  1. 安装Python扩展
  2. 创建虚拟环境:python -m venv venv
  3. 激活环境后安装上述依赖

我习惯用Jupyter Notebook做初步测试,确认爬取逻辑无误后再移植到.py文件。这样比直接写脚本效率更高。

3. 豆瓣网页结构分析

3.1 评论页面URL规律

以《流浪地球2》为例:

https://movie.douban.com/subject/35267208/comments?start=0&limit=20&status=P&sort=new_score

关键参数:

  • start:分页起始位置
  • limit:每页显示条数(最大100)
  • sort:排序方式(new_score最新热门)

通过修改start值即可翻页:

  • 第1页:start=0
  • 第2页:start=20
  • ...

3.2 HTML标签结构

使用Chrome开发者工具(F12)检查元素:

  • 每条评论包裹在<div class="comment-item">
  • 用户名在<span class="comment-info">下的a标签
  • 评分藏在<span class="rating"的title属性
  • 评论内容在<span class="short">

这种结构相对规整,比某些动态渲染的网站容易抓取。但要注意豆瓣偶尔会调整页面结构,需要定期检查选择器是否仍然有效。

4. 爬虫核心代码实现

4.1 基础爬取函数

import requests from bs4 import BeautifulSoup import time import random def fetch_comments(movie_id, page=1): url = f"https://movie.douban.com/subject/{movie_id}/comments" params = { "start": (page-1)*20, "limit": 20, "sort": "new_score" } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..." } try: response = requests.get(url, params=params, headers=headers) response.raise_for_status() return response.text except Exception as e: print(f"请求失败: {e}") return None

关键点:

  1. 必须设置User-Agent模拟浏览器
  2. 使用try-except捕获网络异常
  3. 通过params参数构造查询字符串

4.2 评论数据解析

def parse_comments(html): soup = BeautifulSoup(html, 'html.parser') comments = [] for item in soup.select('div.comment-item'): try: user = item.select_one('span.comment-info > a').text.strip() rating = item.select_one('span.rating')['title'] if item.select_one('span.rating') else '无评分' content = item.select_one('span.short').text.strip() date = item.select_one('span.comment-time')['title'] comments.append({ "user": user, "rating": rating, "content": content, "date": date }) except Exception as e: print(f"解析异常: {e}") continue return comments

解析技巧:

  1. 使用CSS选择器比find_all更简洁
  2. 每个字段都做strip()处理去除空白字符
  3. 对可能不存在的元素(如评分)做判空处理

4.3 分页爬取与数据存储

def crawl_douban_comments(movie_id, max_page=5): all_comments = [] for page in range(1, max_page+1): print(f"正在爬取第{page}页...") html = fetch_comments(movie_id, page) if html: comments = parse_comments(html) all_comments.extend(comments) # 随机延迟防止被封 time.sleep(random.uniform(1, 3)) # 保存为CSV df = pd.DataFrame(all_comments) df.to_csv(f'douban_comments_{movie_id}.csv', index=False) return df

注意事项:

  1. 设置合理的爬取间隔(1-3秒)
  2. 使用random增加请求间隔的随机性
  3. 及时保存数据防止意外中断丢失

5. 反爬机制应对策略

5.1 常见反爬手段

豆瓣会检测以下异常行为:

  • 高频请求(每分钟超过30次)
  • 无User-Agent或使用明显爬虫UA
  • 请求参数异常
  • 来自同一IP的持续访问

我曾在测试时连续爬取50页,结果IP被暂时封禁2小时。后来调整策略后基本没再遇到问题。

5.2 实战应对方案

  1. 请求头完善:
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...", "Referer": "https://movie.douban.com/", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive" }
  1. 代理IP池方案(需自行搭建或购买服务):
proxies = { "http": "http://user:pass@ip:port", "https": "http://user:pass@ip:port" } response = requests.get(url, proxies=proxies)
  1. 自动化Cookies管理:
session = requests.Session() # 先访问一次首页获取cookies session.get("https://www.douban.com") # 后续请求自动携带cookies response = session.get(comment_url)

6. 数据清洗与分析示例

6.1 常见数据问题

原始数据可能存在:

  • HTML实体编码(如 &)
  • 特殊表情符号/颜文字
  • 无意义的换行和空格
  • 评分为文字描述("力荐"、"推荐"等)

6.2 清洗代码示例

import pandas as pd import html def clean_data(df): # 转换HTML实体 df['content'] = df['content'].apply(html.unescape) # 评分文字转数字 rating_map = { '力荐': 5, '推荐': 4, '还行': 3, '较差': 2, '很差': 1, '无评分': None } df['rating_num'] = df['rating'].map(rating_map) # 去除首尾空白 df['user'] = df['user'].str.strip() return df

6.3 简单分析示例

# 评分分布 rating_dist = df['rating_num'].value_counts().sort_index() # 词云生成 from wordcloud import WordCloud text = ' '.join(df['content'].tolist()) wordcloud = WordCloud(font_path='msyh.ttc').generate(text)

7. 项目优化方向

7.1 异步爬取加速

使用aiohttp替代requests:

import aiohttp import asyncio async def fetch_page(session, url): async with session.get(url) as response: return await response.text() async def main(urls): async with aiohttp.ClientSession() as session: tasks = [fetch_page(session, url) for url in urls] return await asyncio.gather(*tasks)

实测异步方式能提升3-5倍效率,但要注意控制并发量避免被封。

7.2 数据持久化方案

除了CSV,还可以考虑:

  1. MongoDB:适合非结构化数据
  2. MySQL:便于复杂查询
  3. Elasticsearch:支持全文检索

我通常根据后续使用场景选择:

  • 简单分析用CSV
  • 长期存储用MySQL
  • 文本搜索用Elasticsearch

7.3 定时增量爬取

使用APScheduler实现定时任务:

from apscheduler.schedulers.blocking import BlockingScheduler def job(): # 获取上次最后一条评论的时间 last_date = get_last_comment_date() # 只爬取新评论 crawl_new_comments(since=last_date) scheduler = BlockingScheduler() scheduler.add_job(job, 'interval', hours=6) scheduler.start()

8. 法律与道德注意事项

  1. 遵守robots.txt协议:

    • 豆瓣的robots.txt对部分目录有限制
    • 建议设置合理的爬取间隔
  2. 数据使用限制:

    • 禁止商业化使用(除非获得授权)
    • 学术研究需注明数据来源
  3. 个人隐私保护:

    • 不要公开用户个人信息
    • 对敏感内容做脱敏处理

我在实际项目中会严格控制爬取量,通常单次不超过1000条评论,且数据仅用于分析统计,从不存储用户个人信息。

9. 常见问题与解决方案

9.1 返回403错误

可能原因:

  • 请求头不完整
  • Cookies验证失败
  • IP被暂时封禁

解决方案:

  1. 检查User-Agent是否设置
  2. 添加Referer等头部信息
  3. 更换IP或等待1-2小时

9.2 数据解析为空

可能原因:

  • 页面结构已更新
  • 触发反爬返回验证页
  • 网络问题导致HTML不完整

调试步骤:

  1. 保存原始HTML检查结构
  2. 测试CSS选择器是否有效
  3. 检查是否出现验证码

9.3 编码问题

常见错误:

  • 'gbk' codec can't encode character...
  • 中文显示为乱码

解决方法:

# 设置正确编码 response.encoding = 'utf-8' # 或者手动处理 html = response.content.decode('utf-8')

10. 个人实战经验分享

  1. 关于爬取频率:

    • 工作日白天可以稍快(2-3秒/次)
    • 晚上和周末建议放慢(5-10秒/次)
    • 遇到验证码立即暂停1小时
  2. 数据存储技巧:

    • 每爬取50条就写入文件一次
    • 使用pickle保存中间状态
    • 文件名包含爬取时间戳
  3. 调试建议:

    • 先用单页测试解析逻辑
    • 保存异常页面供后期分析
    • 使用logging记录运行日志

我维护的这个爬虫已经稳定运行3年,核心经验就是:慢就是快。与其追求速度被ban,不如稳定获取数据。最近一次升级是添加了自动识别验证码的功能,发现验证码就自动切换代理并降低频率。

返回列表