1. 项目概述与背景
最近在做一个电影数据分析项目,需要获取豆瓣TOP250电影的评论数据。传统爬虫对豆瓣这种动态加载内容的网站效果不佳,经过多次尝试,最终选择了Scrapy框架结合Selenium的方案。这个组合既能利用Scrapy强大的爬取和数据处理能力,又能通过Selenium解决JavaScript渲染问题。
在实际操作中,我发现这个方案有几个明显优势:
- 可以完整获取到页面动态加载的评论内容
- 能够模拟真实用户行为,降低被封风险
- 数据处理流程规范,便于后续分析
- 扩展性强,可以方便地添加各种中间件和管道
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目搭建
2.1 基础环境配置
首先需要准备好Python环境,建议使用Python 3.7+版本。我使用的是Python 3.8.5,这个版本对各种库的兼容性都很好。
创建虚拟环境是个好习惯:
bash复制python -m venv douban_env
source douban_env/bin/activate # Linux/Mac
douban_env\Scripts\activate # Windows
2.2 安装必要依赖
在项目根目录创建requirements.txt文件,内容如下:
code复制scrapy>=2.5.0
selenium>=4.0.0
webdriver-manager>=3.5.0
pymongo>=3.12.0 # 如果需要存储到MongoDB
安装依赖:
bash复制pip install -r requirements.txt
注意:webdriver-manager会自动管理浏览器驱动版本,省去了手动下载和配置的麻烦,强烈推荐使用。
2.3 创建Scrapy项目
使用Scrapy命令行工具创建项目:
bash复制scrapy startproject douban_comments
cd douban_comments
这会产生标准的Scrapy项目结构,我们需要在此基础上进行修改和扩展。
3. 核心代码实现详解
3.1 数据模型定义(items.py)
在items.py中定义我们要爬取的数据结构:
python复制import scrapy
class DoubanCommentsItem(scrapy.Item):
movie_name = scrapy.Field() # 电影名称
comment_user = scrapy.Field() # 评论用户
comment_time = scrapy.Field() # 评论时间
comment_content = scrapy.Field() # 评论内容
comment_votes = scrapy.Field() # 有用数
comment_rating = scrapy.Field() # 用户评分(新增字段)
user_location = scrapy.Field() # 用户所在地(新增字段)
我后来在实际使用中增加了comment_rating和user_location两个字段,因为发现这些信息对分析很有价值。Scrapy的Item设计非常灵活,可以根据需要随时扩展。
3.2 Selenium中间件配置(middlewares.py)
这是整个项目的核心之一,负责处理动态页面加载:
python复制from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from scrapy.http import HtmlResponse
import time
class SeleniumMiddleware:
def __init__(self):
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--window-size=1920,1080')
# 设置中文编码
chrome_options.add_argument('lang=zh_CN.UTF-8')
# 禁用图片加载提升速度
chrome_options.add_experimental_option(
"prefs", {"profile.managed_default_content_settings.images": 2}
)
self.driver = webdriver.Chrome(
ChromeDriverManager().install(),
options=chrome_options
)
self.driver.implicitly_wait(10) # 隐式等待
def process_request(self, request, spider):
try:
self.driver.get(request.url)
# 显式等待关键元素加载
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '.comment-item'))
)
# 模拟滚动加载更多评论
for _ in range(3): # 滚动3次加载更多评论
self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 等待加载
return HtmlResponse(
url=self.driver.curren
