基础爬虫实战:抓取猫眼电影票房排行榜全流程解析

169 阅读5分钟

基础爬虫实战:抓取猫眼电影票房排行榜全流程解析

在互联网数据采集领域,爬虫技术是获取公开信息的核心工具。本文以猫眼电影票房排行榜为例,通过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 基础应对措施

  1. 请求头伪装
    在headers中添加完整的浏览器信息:

    headers = {
        "User-Agent": "Mozilla/5.0...",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "X-Requested-With": "XMLHttpRequest"  # 标识Ajax请求
    }
    

  2. 请求间隔控制
    使用time.sleep()避免高频请求:

    import time
    time.sleep(2) # 每次请求间隔2

  3. 代理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:猫眼接口支持日期参数,修改getDailyBoxOfficeListdate字段即可。注意猫眼通常只保留近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:可能原因:

  1. 接口参数错误(如城市等级)
  2. 数据未实时更新(猫眼票房数据约每日10点更新)
  3. 字段解析错误(检查JSON结构是否变化)

建议通过Chrome开发者工具对比Network请求参数与返回数据。

七、总结与建议

本项目通过40行核心代码实现了猫眼票房数据的自动化采集,关键点在于:

  1. 准确分析目标接口
  2. 合理处理请求与响应
  3. 完善的数据存储与可视化

进阶方向:

  • 部署为定时任务(如Windows任务计划/Linux crontab)
  • 集成数据库存储(MySQL/MongoDB)
  • 添加邮件报警机制(当数据异常时通知)

爬虫开发需遵守robots.txt协议及目标网站的使用条款,仅采集公开数据并控制请求频率,避免对服务器造成压力。