在这篇文章中,我们将通过Python爬虫技术从The Movie Database (TMDb)网站上抓取电影数据,并对这些数据进行分析。我们将使用到一些流行的Python库,比如requests
、lxml
、pandas
以及matplotlib
来帮助我们完成任务。
目标网站
1. 引言
在开始之前,请确保你已经安装了所有必需的Python库。你可以使用pip命令来安装它们:
pip install requests lxml pandas matplotlib DrissionPage DataRecorder fake_useragent
接下来,让我们一步步地构建我们的项目。
2. 导入所需库
首先,我们需要导入项目中需要用到的各种库。
import json
import os
import random
import re
from DrissionPage import ChromiumPage
from DataRecorder import Recorder
import time
import requests
from lxml import etree
from fake_useragent import UserAgent
import pandas as pd
import matplotlib.pyplot as plt
3. 创建数据记录器实例
为了保存抓取到的数据,我们创建一个DataRecorder
实例,并初始化CSV文件的列名。
recorder = Recorder(path=r"data.csv", cache_size=500)
recorder.add_data(
['Title', 'Year', 'Director', 'Screenplay', 'Type', 'Description', 'User Score', 'Reviews', 'Revenue', 'Budget',
'Keywords'])
4. 加载网页并抓取电影链接
我们使用ChromiumPage
加载TMDb的电影列表页面,并循环抓取多页的电影详情页链接。
page = ChromiumPage()
page.get('https://www.themoviedb.org/movie')
page.wait.load_start()
i = 0
set_links = set()
while True:
items = page.eles('.card style_1')
for item in items:
link = item.ele('x:./div[1]/div[1]/a').attr('href')
set_links.add(link)
print(len(set_links))
if page.ele("x://p[@class='load_more']"):
page.ele("x://p[@class:='load_more']").click()
page.wait.load_start()
i += 1
print(f"第{
i}页")
else:
page.scroll.to_bottom()
page.wait.load_start()
time.sleep(random.uniform(2, 5))
if len(set_links) >= 210:
break
list_links = list(set_links)
好的,我们将继续接下来的部分。
5. 设置会话和代理
为了发送HTTP请求并可能绕过网站的反爬虫机制,我们创建一个requests.Session()
对象,并设置随机用户代理。此外,我们还会读取代理池中的代理列表。
session = requests.Session()
with open(r"/代理池/proxies.txt", 'r') as file:
proxies = [line.strip() for line in file]
headers = {
'User-Agent': UserAgent().random}
请注意,使用代理时需要确保你有合法权限去访问这些代理服务器,并且要遵守目标网站的服务条款。
6. 遍历电影链接并抓取信息
对于每个电影链接,我们将获取页面内容,并解析出我们需要的信息,如标题、年份、导演等。
for link in list_links:
res = session.get(url=link, headers=headers, timeout=10)
tree = etree.HTML(res.text)
# 解析电影标题和年份
Title_with_year = tree.xpath('//title/text()')[0]
Title_pattern = re.compile(r'([^(]+)\s*\(\d{4}\)\s*—.*')
Title_match = Title_pattern.search(Title_with_year)
Year_match = re.search(r'\((\d{4})\)', Title_with_year)
Title = Title_match.group(1).strip() if Title_match else ''
Year = Year_match.group(1) if Year_match else ''
# 解析导演、编剧等信息
Director = tree.xpath('//ol[@class="people no_image"]/li[@class="profile"]/p[1]/a/text()')[0]
Screenplay = tree.xpath('//li[@class="profile" and contains(p[@class="character"], "Director")]/p/a/text()')[0]
Type = tree.xpath('//span[@class="genres"]/a/text()')
Description = tree.xpath("//div[@class='overview']/p/text()")
User_Score = re.search(r'icon-r(\d+)', res.text).group(1) if re.search(r'icon-r(\d+)', res.text) else ""
Reviews = tree.xpath("//a[@id='reviews']/span/text()")
Revenue = tree.xpath("//p[strong/bdi='票房']/text()")
Budget = tree.xpath("//p[strong/bdi='预算']/text()")
Keywords = tree.xpath("//section[@class='keywords right_column']//ul/li/a/text()")
movie_data = {
'Title': Title,
'Year': Year,
'Director': Director,
'Screenplay': Screenplay,
'Type': Type,
'Description': Description,
'User Score': User_Score,
'Reviews': Reviews,
'Revenue': Revenue,
'Budget': Budget,
'Keywords': Keywords
}
recorder.add_data(movie_data)
print(movie_data)
recorder.record()
7. 数据清洗与分析
在数据被保存到CSV文件后,我们将对它进行一些清理工作,并绘制图表来展示数据的一些特征。
清理数据
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('data.csv')
def clean_list_column(column):
if isinstance(column, str) and column.startswith("[") and column.endswith("]"):
column = column[1:-1].strip().replace("'", "").replace(", ", ",")
return column
def clean_amount(amount_str):
if isinstance(amount_str, str):
amount_str = amount_str.strip("[]' ")
if amount_str == '-':
return 0
amount_str = amount_str.replace("$", "").replace(",", "")
return float(amount_str)
return 0
df['Description'] = df['Description'].apply(clean_list_column)
df['Type'] = df['Type'].apply(clean_list_column)
df['Keywords'] = df['Keywords'].apply(clean_list_column)
df['Reviews'] = df['Reviews'].apply(clean_list_column)
df['Revenue'] = df['Revenue'].apply(clean_amount)
df['Budget'] = df['Budget'].apply(clean_amount)
print(df[['Title', 'Budget']])
df.to_csv('cleaned_data.csv', index=False)
绘制图表
# 电影预算分布直方图
plt.figure(figsize=(12, 6))
plt.hist(df['Budget'], bins=30, alpha=0.75, color='blue', edgecolor='black')
plt.title('Distribution of Movie Budgets')
plt.xlabel('Budget (in millions)')
plt.ylabel('Number of Movies')
plt.grid(True)
plt.show()
# 电影收入分布直方图
plt.figure(figsize=(12, 6))
plt.hist(df['Revenue'], bins=30, alpha=0.75, color='green', edgecolor='black')
plt.title('Distribution of Movie Revenues')
plt.xlabel('Revenue (in millions)')
plt.ylabel('Number of Movies')
plt.grid(True)
plt.show()
# 预算与收入之间的关系散点图
plt.figure(figsize=(12, 6))
plt.scatter(df['Budget'], df['Revenue'], alpha=0.5, color='purple')
plt.title('Relationship between Budget and Revenue')
plt.xlabel('Budget (in millions)')
plt.ylabel('Revenue (in millions)')
plt.grid(True)
plt.show()
运行结果
在这里插入图片描述
总结
以上就是从网页上爬取电影数据并进行简单数据分析的全过程。希望这篇教程对你有所帮助!
希望合法使用爬虫,避免对服务器造成过大负担。
本代码仅用于学习和研究目的,不得用于商业用途或其他非法活动。
使用者自行承担因不当使用代码而产生的任何法律责任
提示
如果有爬虫的需求的话可以到【某鱼】找我,「我在某鱼发布了【python爬虫 国内网站(网页):文档、图片等数据抓取,一】」
点击链接直接打开