目录

  • 一、数据爬取
    • 准备
    • 网页结构分析
    • 完成爬取
    • 导出数据
  • 二、数据清洗
    • 数据预处理
    • 数据可视化
  • 三、数据存储
  • 验证
      • 分析总结:

一、数据爬取

准备

1.在进行数据爬取之前我们需要用到两个库:

  • requests
  • lxml

安装:
lxml解析库

pip install lxml

HTTP 请求库

pip install requests

在这里插入图片描述
这里是在AnacondaPowerShell里安装好了

网页结构分析

  1. 导入模块
# 导入模块
import requests
from lxml import etree
  1. 存储目标url和headers请求头
    打开豆瓣电影top250网址:https://movie.douban.com/top250?start=0&filter=
    在这里插入图片描述
    按键盘F12或鼠标右键检查打开网页开发者工具
    在这里插入图片描述
    headers 作用是设置合适的请求头信息来模拟真实浏览器行为,避过一些简单的反爬虫信息
# 目标url
url = 'https://movie.douban.com/top250?start=0&filter='
# headers
headers = {
	'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
}

注意: headers要用字典形式存储

  1. 对目标网址发送请求并获取返回结果的页面解析
# 发送请求
html = requests.get('https://movie.douban.com/top250?start=1&filter=', headers=headers)
# 将网页内容实例化
tree = etree.HTML(x.text)
  1. 使用xpath语法选择指定html标签在这里插入图片描述
    通过审查元素可以看到
    的标签是整块信息的父级元素
# 用xpath表达式查询所有 class属性为 info 的div元素
info = tree.xpath('//div[@class="info"]')

在这里插入图片描述通过print(info) 打印我们发现他返回的结果是一个列表的形式

  1. 通过循环遍历的方式将info里面的每个子类的查找出来
for item in info:
    # 电影名称
    name = item.xpath('./div[@class="hd"]/a/span/text()')[0]
    # 导演
    director = item.xpath('./div[@class="bd"]/p/text()')[0]
    # 演员
    act = item.xpath('./div[@class="bd"]/p/text()')
    print(name)
    print(director)
    print(act)
    break

item.xpath('./div[@class="hd"]/a/span/text()') 查找info下的div=hd的元素里子标签a下的span标签在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
此处打印出来的结果仍是一个列表形式,可以用下标的形式选取第一个元素即电影名称,但可以看到导演与演员信息是在同一个p标签里的。我们用split字符串方法将导演与演员信息分割开来

  1. 获取电影名称、导演、主演、上映年份、国籍、类型、评分、评价人数
for item in info:
    # 电影名称
    name = item.xpath('./div[@class="hd"]/a/span/text()')[0]
    # 导演
    director = item.xpath('./div[@class="bd"]/p/text()')[0].split('导演:')[1].split('主演:')[0]
    # 主演
    act = item.xpath('./div[@class="bd"]/p/text()')[0].split('导演:')[1].split('主演:')[1]
    # 上映年份
    year = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[0]
    # 国籍
    nationality = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[1]
    # 类型
    genre = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[2]
    # 评分
    score = item.xpath('./div[@class="bd"]/div/span[2]/text()')[0]
    # 评价人数
    num_score = item.xpath('./div[@class="bd"]/div/span[4]/text()')[0]
    # print(name)
    # print(director)
    print(year)
    print(nationality)
    print(genre)
    print(act)
    print(score)
    print(num_score)

在这里插入图片描述
以上我们打算把整页面的所以电影信息获取下来,但出现了一个列表超出索引长度的报错
IndexError: list index out of range

通过查看网页结构发现有时候会没有主演信息
在这里插入图片描述
我们给获取主演的代码添加异常处理代码块try语句

# 主演
    try:
        act = item.xpath('./div[@class="bd"]/p/text()')[0].split('导演:')[1].split('主演:')[1]
    # IndexError捕获当列表或序列超出索引范围时,抛出err异常
    except IndexError as err:
        print('无主演信息')

在这里插入图片描述至此我们获取到了第一页的电影排行数据,那如何获取到剩下的24页呢?
通过翻页对比url地址发现他的页数与地址中的start有关,(当前页 -1) 25*
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
可以使用遍历10次总共的250部电影数据

完成爬取

# 导入模块
import requests
from lxml import etree
import pandas as pd

# 定义一个列表存储排行榜信息
movies_top250 = []

# 遍历10次,从第1页开始,到第10页结束
for i in range(1, 11):
    # 目标url
    url = f'https://movie.douban.com/top250?start={(i - 1) * 25}&filter='
    # 添加浏览器请求头信息,避过简单的反爬措施
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
    }

    # 发送请求信息,将返回内容存储到html变量
    html = requests.get(url, headers=headers)
    # 将html解析为etree._Element对象
    tree = etree.HTML(html.text)

    # 用xpath表达式查询所有 class属性为 info 的div元素
    divs = tree.xpath('//div[@class="info"]')

    # 爬取操作
    for item in divs:
        # 定义一个字典存取电影字段与对应的数值
        dic = {}
        # 电影名称
        name = item.xpath('./div[@class="hd"]/a/span/text()')[0]
        # 存放电影名称
        dic['电影名称'] = name
        # 导演
        director = item.xpath('./div[@class="bd"]/p/text()')[0].split('导演:')[1].split('主演:')[0]
        dic['导演'] = director
        # 主演
        try:
            act = item.xpath('./div[@class="bd"]/p/text()')[0].split('导演:')[1].split('主演:')[1]
            dic['主演'] = act
        # IndexError捕获当列表或序列超出索引范围时,抛出err异常
        except IndexError as err:
            print('无主演信息')
        # 上映年份
        year = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[0]
        dic['上映年份'] = year
        # 国籍
        nationality = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[1]
        dic['国籍'] = nationality
        # 类型
        genre = item.xpath('./div[@class="bd"]/p/text()')[1].split('/')[2]
        dic['类型'] = genre
        # 评分
        score = item.xpath('./div[@class="bd"]/div/span[2]/text()')[0]
        dic['评分'] = director
        # 评价人数
        num_score = item.xpath('./div[@class="bd"]/div/span[4]/text()')[0]
        dic['评价人数'] = num_score

        # 最后把 dic 字典数据添加到电影列表movies_top250
        movies_top250.append(dic)

导出数据

# 将 movies_top250 转换成表格型数据结果
df = pd.DataFrame(movies_top250)
# 将表格导出到当前目录下,豆瓣电影Top250.xlsx
df.to_excel('豆瓣电影Top250.xlsx', index=False)  # index=False 不保存行索引

运行无报错
在这里插入图片描述
在python文件目录下可以看到我们已经成功导出数据,打开查看数据并无缺少
在这里插入图片描述
在这里插入图片描述
注:数据导出成Excel表格形式需要用到pandas模块

二、数据清洗

数据清洗部分此处用Jupyter编写,打开Jupyter

  1. 导入库并对pyplo设置合适字体
# 导入库
import pandas as pd
import matplotlib.pyplot as plt
from pymongo import MongoClient
# 设置pyplot的rc参数
plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置字体

如果运行报错
在这里插入图片描述
附几个库安装命令:
1.pandas安装

pip install pandas

2.matolotlib安装

pip install matolotlib

3.pymongo安装

pip install pymongo

在这里插入图片描述
安装完成
注:安装完成后需重启一遍内核

数据预处理

1.读取数据

# 读取数据
data = pd.read_excel('./豆瓣电影Top250.xlsx')
# 查看头3行
data.head(3)

查看头3行发现, 上映年份类型列有爬取不干净的无意义字符存在
在这里插入图片描述
查看数据原文件发现大量数据前后存在空格
在这里插入图片描述
2.处理前后空格和换行符

# 替换 上映年份 列和 类型 列的换行符\n
data['上映年份'] = data['上映年份'].str.replace('\n', '') # 用str.replace()方法查找并替换为空
data['类型'] = data['类型'].str.replace('\n', '')

# 删除 导演,主演,上映年份,国籍,类型 列的前后空格
data['导演'] = data['导演'].str.strip() # 用str.strip()方法删除前后空格
data['主演'] = data['主演'].str.strip()
data['上映年份'] = data['上映年份'].str.strip()
data['国籍'] = data['国籍'].str.strip()
data['类型'] = data['类型'].str.strip()

3.查找并替换缺失值
查看缺失值数量并求和

# 查看缺失值数量
data.isnull().sum()

在这里插入图片描述
以上可以看到主演列总共有12项缺失值

填充缺失值为"无主演信息"

# 填充缺失值
data['主演'] = data['主演'].fillna("无主演信息")
# 查看填充情况
data[data['主演'] == '无主演信息']

在这里插入图片描述
成功替换缺失值

4.导出处理完后的正常数据

# 导出清洗过后的数据
data.to_excel('./豆瓣电影Top250_2.xlsx',index=False)

在这里插入图片描述

数据可视化

1.查看上映年份列

data['上映年份'].values

在这里插入图片描述
发现有几个年份不是纯数字

2.对上映年份列进行数值处理

# 把年份列转出int类型,并修改异常值1982(中国大陆)为常规年份
for i in data['上映年份'].index:
    data['上映年份'][i] = int(data['上映年份'][i].split('(')[0]) # 遍历整列数据进行替换,用str.split()方法对括号(切割成列表取索引0第一个。对每条数据转成int型

3.将上映年份分组聚合

# 将上映年份分组
bins = [1900,1990,2000,2010,2024] # 按'1900-1990','1991-2000','2001-2010','2011-2024' 切片
labels = ['1900-1990','1991-2000','2001-2010','2011-2024'] # 按 labels 作字段名
data_1 = data['上映年份'].groupby(pd.cut(data['上映年份'],bins = bins,labels=labels)).count() # 对切片数据分组并对分组结果进行 计次

在这里插入图片描述
4.画折线图

# 基于分组年份与电影上映数量画折线图
plt.figure(figsize=(12,6),dpi=980)
# 标题
plt.title('历年高分电影上映趋势图')
# x轴标签
plt.xlabel('上映年份')
# y轴标签
plt.ylabel('电影数量')

# 添加数据标注
for i in range(len(data_1)):
    plt.text(data_1.index[i],data_1[i] * 1.01,data_1[i],c='green')
plt.plot(data_1, marker='o',c='red')

# 保存图表到当前目录下
plt.savefig('1.png')
# 显示图表
plt.show()

在这里插入图片描述

三、数据存储

# 创建client客户端,连接到MongoDB,使用本地连接,默认端口27017
client = MongoClient('localhost',27017)
# 连接到或创建一个  movies 数据库
db = client['movies']
# 连接到或创建一个 top250 集合
collection = db['top250']
# 向集合 top250 插入数据
docs = data.to_dict(orient='records') # orient='records' 值是包含每行数据的字典,字典的键是列名。
collection.insert_many(docs)

在这里插入图片描述
存储完成

验证

打开MongoDB
查看数据库

show dbs

在这里插入图片描述

切换数据库

use movies

查看集合

show collections

在这里插入图片描述

查看集合内容头5行

db.top250.find().pretty().limit(5)

在这里插入图片描述
可以看到已经成功写入到MongoDB数据库了

分析总结:

读下图得知,从90年到2010年前的高质量电影上榜率一直是水平上升的,直到2010年后到至今开始直线下滑。
在这里插入图片描述

参考

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐