去年春节档电影市场异常火爆,每天都有新片上映,各种影评铺天盖地。作为一个电影爱好者,我发现自己经常陷入这样的困境:想找部好电影看,却被海量信息淹没;看到朋友推荐的电影,却记不住片名;好不容易决定看某部电影,又找不到靠谱的影评参考。
这个痛点促使我思考:能不能用技术手段打造一个私人影评助手?它应该具备以下能力:
经过调研,我选择了QClaw这个轻量级爬虫框架来实现这个想法。QClaw基于Python开发,学习曲线平缓,特别适合处理网页数据抓取任务。最重要的是,它内置了反反爬机制,可以轻松应对大多数网站的防护措施。
选择QClaw主要基于以下几个考量点:
python复制from qclaw import Spider
spider = Spider()
response = spider.get('https://example.com')
python复制# XPath方式
titles = response.xpath('//h2[@class="title"]/text()').extract()
# CSS选择器方式
ratings = response.css('.rating::text').extract()
扩展性:内置Middleware机制,可以方便地添加代理、UserAgent轮换等功能。
性能:基于异步IO设计,单机就能实现较高的并发抓取效率。
除了QClaw主体框架,还需要准备以下工具:
安装这些依赖只需一条命令:
bash复制pip install qclaw pandas pyecharts flask
以豆瓣电影春节档榜单为例,我们来看具体实现步骤:
<div class="item">中,每个项目包含:python复制from qclaw import Spider
import pandas as pd
class DoubanSpider(Spider):
def start_requests(self):
urls = [
'https://movie.douban.com/SpringFestival2023'
]
for url in urls:
yield self.Request(url, callback=self.parse)
def parse(self, response):
items = []
for movie in response.css('.item'):
item = {
'title': movie.css('.title::text').get(),
'rating': movie.css('.rating_num::text').get(),
'comments': movie.css('.comment::text').get()
}
items.append(item)
return pd.DataFrame(items)
注意:实际使用中请遵守网站的robots.txt规则,控制请求频率,避免给服务器造成负担。
原始数据通常需要经过以下处理:
python复制# 转换评分格式
df['rating'] = df['rating'].astype(float)
# 提取评论数字
df['comment_count'] = df['comments'].str.extract('(\d+)').astype(int)
python复制# 去除无评分的电影
df = df[df['rating'] > 0]
# 按评分排序
df = df.sort_values('rating', ascending=False)
python复制# 保存为CSV
df.to_csv('movies.csv', index=False)
# 也可以存入SQLite
import sqlite3
conn = sqlite3.connect('movies.db')
df.to_sql('movies', conn, if_exists='replace')
使用Pyecharts生成交互式图表:
python复制from pyecharts.charts import Bar
from pyecharts import options as opts
bar = (
Bar()
.add_xaxis(df['title'].tolist())
.add_yaxis("评分", df['rating'].round(1).tolist())
.set_global_opts(
title_opts=opts.TitleOpts(title="春节档电影评分榜"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-45))
)
)
bar.render("rating_bar.html")
python复制from pyecharts.charts import WordCloud
from collections import Counter
# 假设我们已经获取了评论关键词列表
word_counts = Counter(keywords)
wordcloud = (
WordCloud()
.add("", list(word_counts.items()), word_size_range=[20, 100])
.set_global_opts(title_opts=opts.TitleOpts(title="影评关键词云"))
)
wordcloud.render("wordcloud.html")
使用Flask构建简易网页应用:
python复制from flask import Flask, render_template
import pandas as pd
app = Flask(__name__)
@app.route('/')
def index():
df = pd.read_csv('movies.csv')
movies = df.to_dict('records')
return render_template('index.html', movies=movies)
if __name__ == '__main__':
app.run(debug=True)
对应的HTML模板(templates/index.html):
html复制<!DOCTYPE html>
<html>
<head>
<title>我的电影助手</title>
<style>
.movie-card {
border: 1px solid #ddd;
padding: 15px;
margin: 10px;
border-radius: 5px;
}
.high-rating {
background-color: #f8f9fa;
}
</style>
</head>
<body>
<h1>春节档电影推荐</h1>
{% for movie in movies %}
<div class="movie-card {% if movie.rating >= 8.0 %}high-rating{% endif %}">
<h2>{{ movie.title }}</h2>
<p>评分:{{ movie.rating }}</p>
<p>评论数:{{ movie.comment_count }}</p>
</div>
{% endfor %}
</body>
</html>
使用Docker容器化部署:
dockerfile复制FROM python:3.9-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py"]
bash复制docker build -t movie-assistant .
docker run -d -p 5000:5000 movie-assistant
python复制from flask_caching import Cache
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
cache.init_app(app)
@app.route('/')
@cache.cached(timeout=3600) # 缓存1小时
def index():
# ...
javascript复制fetch('/api/movies')
.then(response => response.json())
.then(data => {
// 动态渲染电影列表
});
python复制from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.add_job(fetch_movies, 'interval', hours=6)
scheduler.start()
问题现象:返回空数据或403错误
排查步骤:
解决方案:
python复制# 添加完整请求头
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'
}
response = spider.get(url, headers=headers)
问题现象:图表显示不全或错位
可能原因:
修复方法:
python复制# 清洗数据
df = df.dropna() # 去除空值
df['title'] = df['title'].str.strip() # 去除空格
df['rating'] = pd.to_numeric(df['rating'], errors='coerce') # 强制转换数字
python复制# 基于用户历史记录推荐
user_history = ['电影A', '电影B']
similar_movies = find_similar(user_history)
python复制# 同时抓取多个来源
sources = [
{'name': '豆瓣', 'url': '...'},
{'name': '猫眼', 'url': '...'}
]
html复制<meta name="viewport" content="width=device-width, initial-scale=1.0">
这个项目从构思到实现总共花了约6小时,其中:
几个关键收获:
如果重做这个项目,我会:
这个项目的代码已经开源在GitHub上,包含完整的中文文档和示例数据,欢迎有兴趣的朋友一起完善。对于想快速搭建类似应用的朋友,我的建议是:先从最小可行产品做起,逐步迭代,不要一开始就追求完美。