在當今高度數據驅動的影視行業,精準把握地區票房表現是制片方、宣發團隊和影院經理做出關鍵決策的基礎。一部電影在北上廣深的表現與二三線城市有何差異?哪種類型的電影在特定區域更受歡迎?回答這些問題,不能再依賴“拍腦袋”和經驗主義,而需要真實、及時、細粒度的數據支撐。
貓眼專業版(piaofang.maoyan.com)和燈塔專業版(box.taobao.com)作為國內最權威的票房數據平臺,每日發布包括全國、省、市乃至單個影院的多維度票房數據。這些數據是進行深度市場分析的寶藏。本文將詳細介紹如何利用Python爬蟲技術,自動化地從這些平臺抓取各地區票房數據,并完成一次小規模的分析實踐。
一、技術選型與思路分析
在開始編寫代碼之前,我們需要對目標和數據獲取方式進行一番偵察。
- 目標網站分析:貓眼和燈塔專業版的數據部分為公開數據(如首頁榜單)和非公開的詳細數據(需登錄賬號)。本文將以貓眼專業版的日票房排行榜及其背后的單日影片地區票房明細作為抓取目標。這類數據通常通過XHR(Ajax)請求動態加載,而非直接渲染在HTML中,這決定了我們的技術路線。
- 反爬策略考慮:專業數據平臺通常沒有較強的反爬機制,如貓眼專業版,但我們會遵循道德爬蟲的準則。燈塔作為阿里系產品,反爬機制可能更為嚴格(需要更復雜的請求頭模擬、Cookie處理等),本文為簡化流程,將以貓眼為例。
- 技術棧:
- 請求庫:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">requests</font>**
,用于發送HTTP請求,簡單易用。 - 解析庫:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">json</font>**
,因為數據接口返回的是JSON格式,直接解析即可,無需HTML解析器。 - 數據存儲:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">pandas</font>**
和**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">csv</font>**
,用于將爬取的數據結構化并存儲到CSV文件中,方便后續分析。 - 可視化:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">pyecharts</font>**
,一個非常強大的可視化庫,可以生成交互式的、美觀的圖表。
- 請求庫:
核心思路:
- 打開瀏覽器開發者工具(F12),切換到“網絡(Network)”面板。
- 刷新貓眼專業版頁面,篩選XHR請求。
- 逐個查看請求,找到返回票房數據的API接口。
- 分析該接口的URL、請求頭(Headers)和請求參數(Payload)。
- 在Python代碼中模擬這個請求,獲取返回的JSON數據。
- 從JSON數據中提取我們需要的信息(日期、影片名、總票房、地區、地區票房等)。
- 將數據存儲到CSV文件或數據庫中。
- 利用
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">pandas</font>**
進行數據清洗和初步分析,并用**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">pyecharts</font>**
進行可視化。
二、代碼實現過程
下面我們以抓取貓眼專業版某一天的影片地區票房明細為例。
步驟1:分析API接口
通過瀏覽器開發者工具分析,我們找到了獲取地區票房數據的接口(注:接口地址和參數可能隨時間變化,請以實際分析為準)。
一個典型的接口URL可能類似于:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">https://piaofang.maoyan.com/movie/1281575/regionbox?date=2023-10-01</font>**
其中:
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">1281575</font>**
是影片的唯一ID(例如《志愿軍:雄兵出擊》)。**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">date=2023-10-01</font>**
指定了要查詢的日期。
請求這個URL,服務器會返回一個JSON對象,其中**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">data</font>**
字段下的**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">list</font>**
包含了各個地區的詳細票房數據。
步驟2:編寫爬蟲代碼
首先,安裝必要的庫(如果尚未安裝):
然后,開始編寫代碼:
import requests
import pandas as pd
from pyecharts.charts import Bar, Map
from pyecharts import options as opts
from pyecharts.globals import ThemeType
import json
import time
import csv# 代理配置信息
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"# 代理服務器
proxyMeta = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"proxies = {"http": proxyMeta,"https": proxyMeta,
}# 定義一個請求頭,模擬瀏覽器行為,避免被簡單的反爬機制攔截
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36','Accept': 'application/json, text/plain, */*','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8','Connection': 'keep-alive',# 'Cookie': '你的Cookie(如果需要的話)', # 貓眼這個接口通常不需要Cookie'Referer': 'https://piaofang.maoyan.com/'
}def fetch_movie_list(date):"""獲取某一天的票房排行榜,從而得到電影ID列表"""# 這是一個獲取單日大盤數據的接口,返回榜單url = f"https://piaofang.maoyan.com/box-office?date={date}&type=1"try:response = requests.get(url, headers=headers, proxies=proxies, timeout=15)response.raise_for_status() # 如果狀態碼不是200,拋出異常data = response.json()# 解析JSON,獲取電影列表# 實際路徑需要根據返回的JSON結構調整movie_list = data['data']['list']print(f"成功獲取{date}日票房榜單,共{len(movie_list)}部電影")return movie_listexcept requests.exceptions.ProxyError as e:print(f"代理連接失敗: {e}")return []except requests.exceptions.RequestException as e:print(f"請求電影列表失敗: {e}")return []except json.JSONDecodeError as e:print(f"解析電影列表JSON失敗: {e}")return []def fetch_movie_region_boxoffice(movie_id, movie_name, date):"""獲取單一電影在指定日期的地區票房明細"""url = f"https://piaofang.maoyan.com/movie/{movie_id}/regionbox?date={date}"try:response = requests.get(url, headers=headers, proxies=proxies, timeout=15)response.raise_for_status()data = response.json()region_list = data['data']['list']data_to_save = []for region in region_list:# 提取每個地區的信息region_data = {'date': date,'movie_id': movie_id,'movie_name': movie_name,'region': region.get('regionName'),'box_office': region.get('boxInfo'), # 票房,單位通常是萬元'box_office_ratio': region.get('boxRate'), # 票房占比'avg_price': region.get('avgViewBox'), # 平均票價'attendance': region.get('attendance'), # 場均人次}data_to_save.append(region_data)print(f"成功獲取電影《{movie_name}》在{date}的地區票房數據,共{len(region_list)}個地區")return data_to_saveexcept requests.exceptions.ProxyError as e:print(f"代理連接失敗(電影《{movie_name}》): {e}")return []except requests.exceptions.RequestException as e:print(f"請求電影《{movie_name}》的地區票房失敗: {e}")return []except json.JSONDecodeError as e:print(f"解析電影《{movie_name}》的地區票房JSON失敗: {e}")return []except KeyError as e:print(f"JSON數據結構異常(電影《{movie_name}》): {e}")return []def main():target_date = "2023-10-05" # 指定要抓取的日期all_region_data = [] # 存儲所有電影的地區數據# 測試代理連接try:test_response = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)print(f"代理連接測試成功,當前IP: {test_response.json()['origin']}")except Exception as e:print(f"代理連接測試失敗: {e}")print("請檢查代理配置信息是否正確,網絡是否通暢")return# 1. 獲取當天的電影排行榜movies = fetch_movie_list(target_date)if not movies:print("未獲取到電影列表,程序退出")return# 2. 遍歷榜單中的每一部電影,獲取其地區明細for movie in movies:movie_id = movie.get('movieId')movie_name = movie.get('movieName')if not movie_id:continue# 暫停一小段時間,避免請求過于頻繁time.sleep(1.5) # 稍微延長等待時間,避免觸發反爬single_movie_data = fetch_movie_region_boxoffice(movie_id, movie_name, target_date)if single_movie_data:all_region_data.extend(single_movie_data)# 3. 將所有數據保存到CSV文件if all_region_data:df = pd.DataFrame(all_region_data)filename = f'maoyan_region_boxoffice_{target_date}.csv'df.to_csv(filename, index=False, encoding='utf-8-sig') # utf-8-sig支持Excel直接打開顯示中文print(f"所有數據已保存到文件: {filename}")print(f"共爬取{len(all_region_data)}條地區票房記錄")# 這里可以調用數據分析函數# analyze_data(df, target_date)else:print("未獲取到任何地區票房數據")if __name__ == '__main__':main()
步驟3:數據清洗與存儲
上述代碼已經將數據存儲為CSV文件。**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">pandas</font>**
庫使得數據清洗變得非常簡單。例如,票房數據可能是字符串“12.3萬”,我們需要將其轉換為浮點數**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">123000.0</font>**
以便于計算。
# 在analyze_data函數或單獨進行數據清洗
def clean_data(df):# 示例:清洗票房數據(假設原始數據是'1.2萬'的形式)def convert_box_office(val):if '萬' in val:return float(val.replace('萬', '')) * 10000else:return float(val)df['box_office_clean'] = df['box_office'].apply(convert_box_office)# 類似地,可以清洗其他列...return df
三、數據分析與可視化示例
數據抓取和清洗完成后,我們就可以進行分析了。假設我們想分析《志愿軍:雄兵出擊》在2023年國慶檔期間在全國各省的票房分布。
def analyze_data(df, date):# 假設我們只分析一部特定的電影target_movie = "志愿軍:雄兵出擊"df_movie = df[df['movie_name'] == target_movie].copy()if df_movie.empty:print(f"未找到電影《{target_movie}》的數據")return# 1. 繪制全國票房分布地圖# 準備地圖數據:列表,元素為[省份名稱,票房值] map_data = [[row['region'], row['box_office_clean']] for _, row in df_movie.iterrows()]map_chart = (Map(init_opts=opts.InitOpts(theme=ThemeType.ROMA, width="1200px", height="600px")).add(series_name="票房",data_pair=map_data,maptype="china",is_map_symbol_show=False,).set_global_opts(title_opts=opts.TitleOpts(title=f"{target_movie} {date} 全國各省票房分布(元)"),visualmap_opts=opts.VisualMapOpts(max_=max(df_movie['box_office_clean']), # 視覺映射的最大值is_piecewise=False, # 是否為分段型range_text=['高', '低'],),).set_series_opts(label_opts=opts.LabelOpts(is_show=True)) # 顯示省份名稱)map_chart.render(f"{target_movie}_{date}_票房地圖.html")# 2. 繪制票房TOP10省份柱狀圖df_sorted = df_movie.sort_values(by='box_office_clean', ascending=False).head(10)regions = df_sorted['region'].tolist()box_offices = df_sorted['box_office_clean'].tolist()bar_chart = (Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT)).add_xaxis(regions).add_yaxis("票房(元)", box_offices).set_global_opts(title_opts=opts.TitleOpts(title=f"{target_movie} {date} 省份票房TOP10"),xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)), # 旋轉x軸標簽避免重疊yaxis_opts=opts.AxisOpts(name="票房"),))bar_chart.render(f"{target_movie}_{date}_票房TOP10.html")print(f"可視化圖表已生成完畢。")
運行上述代碼后,將會生成兩個交互式的HTML圖表文件:一個是中國地圖,顏色深淺代表票房高低;另一個是柱狀圖,直觀展示票房最高的10個省份。
四、總結與展望
通過本文的技術講解和代碼實現,我們成功地構建了一個可以自動抓取、解析、存儲和分析貓眼專業版地區票房數據的Python爬蟲。這套方法不僅可以用于單日分析,稍加改造(如循環日期)即可用于分析時間序列數據,研究電影票房在不同地區的生命周期和走勢。