基础爬虫实战:抓取猫眼电影票房排行榜全流程解析
在互联网数据采集领域,爬虫技术是获取公开信息的核心工具。本文以猫眼电影票房排行榜为例,通过Python实现一个基础爬虫项目,详细讲解从环境搭建到数据存储的全流程。整个过程无需复杂框架,适合初学者快速上手。
一、项目准备:工具与环境配置
1.1 开发工具选择
- 编程语言:Python 3.8+(推荐Anaconda管理环境)
- 核心库:
requests(HTTP请求)、BeautifulSoup(HTML解析)、pandas(数据存储) - 辅助工具:Chrome开发者工具(分析网页结构)
1.2 环境安装
通过pip安装必要库:
pip install requests beautifulsoup4 pandas
建议使用虚拟环境隔离项目依赖:
python -m venv maoyan_spider
source maoyan_spider/bin/activate # Linux/Mac
maoyan_spider\Scripts\activate # Windows
1.3 目标网址分析
访问猫眼电影票房榜(https://piaofang.****.com/dashboard),通过Chrome开发者工具的Network面板观察:
- 数据加载方式:Ajax动态请求
- 关键接口:
/dashboard/getDailyBoxOfficeList - 请求参数:日期(
date)、城市等级(cityLevel)
二、爬虫核心实现:三步完成数据采集
2.1 模拟HTTP请求
使用requests库构造GET请求,重点处理请求头和参数:
import requests
from datetime import datetime, timedelta
def get_boxoffice_data(date_str):
url = "https://piaofang.***.com/dashboard/getDailyBoxOfficeList"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...",
"Referer": "https://piaofang.maoyan.com/dashboard"
}
params = {
"date": date_str,
"cityLevel": -1 # -1表示全国数据
}
try:
response = requests.get(url, headers=headers, params=params, timeout=10)
response.raise_for_status() # 检查请求是否成功
return response.json()
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
2.2 解析JSON数据
猫眼返回的数据是结构化JSON,直接提取关键字段:
def parse_data(json_data):
if not json_data or "data" not in json_data:
return []
movies = []
for item in json_data["data"]["list"]:
movie = {
"排名": item["rank"],
"影片名": item["movieName"],
"当日票房(万)": item["boxInfo"],
"累计票房(万)": item["sumBoxInfo"],
"票房占比": item["boxRate"],
"排片占比": item["showRate"]
}
movies.append(movie)
return movies
2.3 数据存储与可视化
使用pandas将数据保存为CSV,并生成简单图表:
import pandas as pd
import matplotlib.pyplot as plt
def save_and_plot(movies, date_str):
df = pd.DataFrame(movies)
# 保存为CSV
filename = f"maoyan_boxoffice_{date_str}.csv"
df.to_csv(filename, index=False, encoding="utf_8_sig")
print(f"数据已保存至 {filename}")
# 绘制票房TOP5柱状图
if len(df) >= 5:
top5 = df.head(5)
plt.figure(figsize=(10, 6))
plt.barh(top5["影片名"], top5["当日票房(万)"].str.replace(",", "").astype(float))
plt.xlabel("当日票房(万)")
plt.title(f"猫眼电影票房榜TOP5 ({date_str})")
plt.gca().invert_yaxis() # 反转Y轴使排名从上到下
plt.savefig(f"top5_{date_str}.png")
plt.close()
三、完整流程整合
将上述模块组合成可执行脚本:
def main():
# 获取昨日日期(猫眼数据通常次日更新)
today = datetime.now()
yesterday = (today - timedelta(days=1)).strftime("%Y-%m-%d")
# 获取并解析数据
json_data = get_boxoffice_data(yesterday)
if json_data:
movies = parse_data(json_data)
if movies:
save_and_plot(movies, yesterday)
else:
print("未获取到有效数据")
if __name__ == "__main__":
main()
四、反爬策略与应对方案
4.1 常见反爬机制
- User-Agent检测:识别非浏览器请求
- 请求频率限制:单位时间内请求过多
- IP封禁:同一IP短时间大量请求
- 验证码:触发人机验证
4.2 基础应对措施
-
请求头伪装
在headers中添加完整的浏览器信息:headers = { "User-Agent": "Mozilla/5.0...", "Accept-Language": "zh-CN,zh;q=0.9", "X-Requested-With": "XMLHttpRequest" # 标识Ajax请求 } -
请求间隔控制
使用time.sleep()避免高频请求:import time time.sleep(2) # 每次请求间隔2秒 -
代理IP池
当被封IP时,切换代理:proxies = { "http": "http://123.123.123.123:8080", "https": "https://123.123.123.123:8080" } response = requests.get(url, headers=headers, proxies=proxies)
五、代码优化与扩展
5.1 多日期数据采集
修改主函数支持日期范围输入:
def main(start_date, end_date):
current_date = datetime.strptime(start_date, "%Y-%m-%d")
end_date = datetime.strptime(end_date, "%Y-%m-%d")
while current_date <= end_date:
date_str = current_date.strftime("%Y-%m-%d")
json_data = get_boxoffice_data(date_str)
# ...后续处理逻辑
current_date += timedelta(days=1)
5.2 异常处理增强
添加重试机制:
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session():
session = requests.Session()
retries = Retry(total=3, backoff_factor=1)
session.mount("http://", HTTPAdapter(max_retries=retries))
session.mount("https://", HTTPAdapter(max_retries=retries))
return session
# 使用时替换requests.get为session.get
六、常见问题Q&A
Q1:被网站封IP怎么办?
A:立即启用备用代理池,建议使用住宅代理(如站大爷IP代理),配合每请求更换IP策略。免费代理可通过proxy-pool项目维护,但稳定性较差。
Q2:如何获取历史票房数据?
A:猫眼接口支持日期参数,修改getDailyBoxOfficeList的date字段即可。注意猫眼通常只保留近3个月数据,更早数据需通过第三方数据平台获取。
Q3:返回的数据是乱码怎么办?
A:检查响应编码,强制指定UTF-8:
response.encoding = "utf-8" # 在response.json()前添加
Q4:爬虫速度太慢如何优化?
A:采用多线程/异步请求,示例使用concurrent.futures:
from concurrent.futures import ThreadPoolExecutor
def fetch_data(date):
# 单日期采集逻辑
pass
dates = ["2023-01-01", "2023-01-02"]
with ThreadPoolExecutor(max_workers=5) as executor:
executor.map(fetch_data, dates)
Q5:数据与网页显示不一致?
A:可能原因:
- 接口参数错误(如城市等级)
- 数据未实时更新(猫眼票房数据约每日10点更新)
- 字段解析错误(检查JSON结构是否变化)
建议通过Chrome开发者工具对比Network请求参数与返回数据。
七、总结与建议
本项目通过40行核心代码实现了猫眼票房数据的自动化采集,关键点在于:
- 准确分析目标接口
- 合理处理请求与响应
- 完善的数据存储与可视化
进阶方向:
- 部署为定时任务(如Windows任务计划/Linux crontab)
- 集成数据库存储(MySQL/MongoDB)
- 添加邮件报警机制(当数据异常时通知)
爬虫开发需遵守robots.txt协议及目标网站的使用条款,仅采集公开数据并控制请求频率,避免对服务器造成压力。