爬取豆瓣电影信息,再将豆瓣信息写入csv文件和mongodb数据库,再进行数据分析

爬取豆瓣电影信息

分析网站

首先我们先进入到电影网站首页https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0

但是这不是我所要的网址,我想要获得电影信息的网址,按f12看到动态网页代码,
我进行网页分析,得出,这个才是我想要的网址,我在把这个网址复制一个新的网页上查看
在这里插入图片描述
这里可以看到20条信息,但是有些看起来有点乱,可以用python来读取,就可以看到详细的信息

import requests
import json
url = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0'
request = requests.get(url=url).text
js = json.loads(request)
print(js)

在这里插入图片描述
通过这串代码就可以看到网址的信息,这里的信息我想获得的有评分、电影名、电影链接、图片链接、电影id,但是这里只有20条电影信息,如果想要获取全部,只要把链接https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0的page_limit=20改成2000就行了。

获取每个电影的网址,进而获取剩余信息

因为上面已经获得了电影网站,所以就进去查看网页源代码

可以看到这里有我想要获得的信息,导演、演员、上映时间、电影时长、电影类型、生产的国家,但是有些信息还是获取不到,比如说生产电影的国家,还有些电影的电影时长还是获取不到,这都是我不断尝试之后发现的

我发现了这里的网址https://movie.douban.com/j/subject_abstract?subject_id=33384987,有我们所要获取的电影信息
在这里插入图片描述
比如说导演、演员、电影时长、生产国家,然后我知道这些信息在哪里,就可以进入正题了。

访问电影总网址

import requests
from bs4 import BeautifulSoup
import re
import json
import pandas as pd
from pymongo import MongoClient
class Douban(object):
    #首先定义一个init方法,用来访问电影的主网址
    def __init__(self):
        url = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=time&page_limit=2000&page_start=0"
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
        movie_url = requests.get(url=url, headers=headers).text`
		self.js = json.loads(movie_url)

这里用面向对象的方式编写,也可以不用,但是面向对象编写代码可以更容易修改

获取剩余电影信息

    def movie_data(self):
        movie_data = []
        for i in self.js['subjects']:
            movie_dict = {}
            url = i['url']
            movie_dict["movie_url"] = url
            movie_dict["title"] = i['title']
            print(i['title'])
            movie_dict["score"] = i['rate']
            movie_dict["img"] = i['cover']
            movie_dict["movie_id"] = i['id']
            #调用下面的方法,来获取电影部分信息,然后在加入电影总的信息当中
            movie_dict_2 = self.movie_url(url,i['id'])
            movie_dict.update(movie_dict_2)
            #再把这些信息加入一个全新列表当中
            movie_data.append(movie_dict)

首先定义一个空字典,用于存取电影信息,然后定义一个空列表,把这些电影信息的字典写入列表中,为的是以后更容易把数据写入csv文件和mongodb数据库。
这里有一个调用方法,就是调用self.movie_url(url,i[‘id’]),因为这里数据还没全,所以要访问每个电影的网址来获取剩余的信息,然后把剩余的信息加入电影总信息中,也就是movie_dict字典中,然后再植入movie_data列表中

    def movie_url(self,url,movie_id):
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
        movie_url = requests.get(url=url, headers=headers).text
        soup = BeautifulSoup(movie_url)
        info_list = soup.find('div', id='info')
        type = info_list.find_all('span', property="v:genre")
        #先定义一个空字典
        movie_dict = {}
        type_list = []
        for j in type:
            type_list.append(j.text)
        #把电影类型加入字典中
        movie_dict['type'] = "、".join(type_list)
        #因为有些电影的源代码有些不同,所以用异常处理来pass这些电影,这种电影极少出现
        try:
            #获取电影的上映时间
            relerse_time = info_list.find('span', property="v:initialReleaseDate").text
            release_time = re.findall(r"\d+\.?\d*", relerse_time)
            movie_dict['release_time'] = "-".join(release_time)
            country_url = "https://movie.douban.com/j/subject_abstract?subject_id={}".format(movie_id)
            get_country = requests.get(url=country_url).text
            js_country = json.loads(get_country)
            #获取电影的制作国家
            movie_dict['country'] = js_country['subject']['region']
            play_time = country_url['subject']['duration']
            play_time = re.findall(r"\d+\.?\d*", play_time)
            #获取电影的播放时间
            movie_dict['play_time'] = int("".join(play_time))
            data = info_list.find_all('span')
            result = [span.get_text() for span in data]
            #获取电影的导演和演员
            movie_dict['director'] = result[2]
            movie_dict['actor'] = result[8]
        except:
            pass
        #然后返回这些字典信息
        return movie_dict

这里的方法有两个参数,一个是电影网站和电影id,电影网站是用来获取电影类型、电影上映时间、电影生产国家,用电影id结合上面所说的网址https://movie.douban.com/j/subject_abstract?subject_id=33384987来获取演员、导演、电影时长。
用电影网站获取是用bs4,而另外一个是用json库的方法获取。然后返回这些信息字典,上面调用这个方法就可以获取剩余的电影信息,然后在结合成一个字典再加入列表中。
这里用异常处理,防止部分电影的网站结构不同,虽然极少,也有可能会出问题,而这些出问题的电影就不录入了。

写入csv文件

    def csv_write(self):
        data = self.movie_dataframe()
        pd.DataFrame.to_csv(data,"I:/crack/DATA/movie_data.csv",encoding="utf_8_sig")
        print("写入成功")

我先把总数据列表转化成dataframe数据类型,然后再写入csv文件,这里用的编码格式是utf_8_sig,这个编码格式可以更好的转化中文字符。

写入mongodb数据库

    def mongodb_write(self):
        data = self.movie_dataframe()
        data_columns = list(data.columns)
        # 首先连接数据库
        client = MongoClient(host="127.0.0.1", port=27017)
        # 连接数据库中的某个集合,这里如果原本没有这个数据库或者是集合,就会自动创建
        collection = client['test_python']['movie_data']
        i = 0
        for j in list(data.values):
            l = list(j)
            data_list = {"_id":i,data_columns[0]: l[0], data_columns[1]: l[1], data_columns[2]: l[2], data_columns[3]: l[3],
                         data_columns[4]: l[4], data_columns[5]: l[5], data_columns[6]: l[6],data_columns[7]:l[7]}
            collection.insert_one(data_list)
            i +=1
        print("写入成功")

这里用的写入mongodb数据库的方法有些复杂,如果嫌麻烦也可以用导入csv文件的方式导入数据库

调用类对象

Movie = Douban()
Movie.csv_write()
Movie.mongodb_write()

源代码

'''
豆瓣信息爬虫,将爬取的信息写入mongodb和csv文件中
'''
import requests
from bs4 import BeautifulSoup
import re
import json
import pandas as pd
from pymongo import MongoClient
#用面向对象的方式编写
class Douban(object):
    #首先定义一个init方法,用来访问电影的主网址
    def __init__(self):
        url = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=time&page_limit=2000&page_start=0"
        url_2 = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E6%9C%80%E6%96%B0&page_limit=2000&page_start=0"
        url_3 = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%BB%8F%E5%85%B8&sort=time&page_limit=2000&page_start=0"
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
        movie_url = requests.get(url=url, headers=headers).text
        movie_url_2 = requests.get(url=url_2,headers=headers).text
        movie_url_3 = requests.get(url=url_3,headers=headers).text
        print(movie_url_3)
        self.js_3 = json.loads(movie_url_3)
        self.js_2 = json.loads(movie_url_2)
        self.js = json.loads(movie_url)
    #再定义一个方法用来获取电影的数据
    def movie_data(self):
        movie_data = []
        for i in self.js['subjects']:
            movie_dict = {}
            url = i['url']
            movie_dict["movie_url"] = url
            movie_dict["title"] = i['title']
            print(i['title'])
            movie_dict["score"] = i['rate']
            movie_dict["img"] = i['cover']
            movie_dict["movie_id"] = i['id']
            #调用下面的方法,来获取电影部分信息,然后在加入电影总的信息当中
            movie_dict_2 = self.movie_url(url,i['id'])
            movie_dict.update(movie_dict_2)
            #再把这些信息加入一个全新列表当中
            movie_data.append(movie_dict)
        for j in self.js_2['subjects']:
            movie_dict_3 = {}
            movie_dict_3["movie_url"] = j['url']
            movie_dict_3["title"] = j['title']
            print(j['title'])
            movie_dict_3["score"] = j['rate']
            movie_dict_3["img"] = j['cover']
            movie_dict_3["movie_id"] = j['id']
            # 调用下面的方法,来获取电影部分信息,然后在加入电影总的信息当中
            movie_dict_4 = self.movie_url(j['url'], j['id'])
            movie_dict_3.update(movie_dict_4)
            if movie_dict_3 in movie_data:
                print("已有这个数据")
            else:
                movie_data.append(movie_dict_3)
        for z in self.js_3['subjects']:
            movie_dict_5 = {}
            movie_dict_5["movie_url"] = z['url']
            movie_dict_5["title"] = z['title']
            print(z['title'])
            movie_dict_5["score"] = z['rate']
            movie_dict_5["img"] = z['cover']
            movie_dict_5["movie_id"] = z['id']
            # 调用下面的方法,来获取电影部分信息,然后在加入电影总的信息当中
            movie_dict_6 = self.movie_url(z['url'], z['id'])
            movie_dict_5.update(movie_dict_6)
            if movie_dict_5 in movie_data:
                print("已有这个数据")
            else:
                movie_data.append(movie_dict_5)

        return movie_data
    #定义一个方法来获取电影URL,然后在获取剩下的电影信息
    def movie_url(self,url,movie_id):
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
        movie_url = requests.get(url=url, headers=headers).text
        soup = BeautifulSoup(movie_url)
        info_list = soup.find('div', id='info')
        type = info_list.find_all('span', property="v:genre")
        #先定义一个空字典
        movie_dict = {}
        type_list = []
        for j in type:
            type_list.append(j.text)
        #把电影类型加入字典中
        movie_dict['type'] = "、".join(type_list)
        #因为有些电影的源代码有些不同,所以用异常处理来pass这些电影,这种电影极少出现
        try:
            #获取电影的上映时间
            relerse_time = info_list.find('span', property="v:initialReleaseDate").text
            release_time = re.findall(r"\d+\.?\d*", relerse_time)
            movie_dict['release_time'] = "-".join(release_time)
            country_url = "https://movie.douban.com/j/subject_abstract?subject_id={}".format(movie_id)
            get_country = requests.get(url=country_url).text
            js_country = json.loads(get_country)
            #获取电影的制作国家
            movie_dict['country'] = js_country['subject']['region']
            play_time = country_url['subject']['duration']
            play_time = re.findall(r"\d+\.?\d*", play_time)
            #获取电影的播放时间
            movie_dict['play_time'] = int("".join(play_time))
            data = info_list.find_all('span')
            result = [span.get_text() for span in data]
            #获取电影的导演和演员
            movie_dict['director'] = result[2]
            movie_dict['actor'] = result[8]
        except:
            pass
        #然后返回这些字典信息
        return movie_dict
    #定义一个方法来把这些数据转化成DataFrame数据类型
    def movie_dataframe(self):
        movie_data = self.movie_data()
        movie_dataframe = pd.DataFrame(movie_data)
        movie_dataframe.index.name = "id"
        return movie_dataframe
    #定义一个方法来写入csv文件
    def csv_write(self):
        data = self.movie_dataframe()
        pd.DataFrame.to_csv(data,"I:/crack/DATA/movie_data.csv",encoding="utf_8_sig")
        print("写入成功")
        return data
    #定义一个方法来写入mongodb数据库
    def mongodb_write(self):
        data = self.movie_dataframe()
        data_columns = list(data.columns)
        # 首先连接数据库
        client = MongoClient(host="127.0.0.1", port=27017)
        # 连接数据库中的某个集合,这里如果原本没有这个数据库或者是集合,就会自动创建
        collection = client['test_python']['movie_data']
        i = 0
        for j in list(data.values):
            l = list(j)
            data_list = {"_id":i,data_columns[0]: l[0], data_columns[1]: l[1], data_columns[2]: l[2], data_columns[3]: l[3],
                         data_columns[4]: l[4], data_columns[5]: l[5], data_columns[6]: l[6],data_columns[7]:l[7]}
            collection.insert_one(data_list)
            i +=1
        print("写入成功")
Movie = Douban()
Movie.csv_write()
Movie.mongodb_write()

这里的源代码有我上面所说的有些不同,因为这里用了三个网站的电影数量来写入的,所以有些复杂。

数据分析

这里所要说的是读取mongodb数据库的内容,然后再进行数据分析

读取数据库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pymongo import MongoClient

pd.set_option('display.max_columns', 10000)
pd.set_option('display.width', 200)
pd.set_option('display.max_colwidth', 1000)
#连接数据库,读取数据
class Douban(object):
    def __init__(self):
        client = MongoClient(host='localhost',port=27017)
        self.collection = client['test_python']['movie_data']
        data = self.collection.find()
        movie_data = pd.DataFrame(data)
        self.movie_data=movie_data.set_index("_id")

set_option方法是用来更好的显现数据的,里面的值可以修改然后达到你最想要的效果
这里还是用面向对象的方式编写的,我获得了数据,然后把_id字段的内容设置为索引了。

统计每个季度上映电影数量的变化情况

    def release_date(self):
        movie_data = self.movie_data
        release_date = movie_data['release_time']
        #将上映时间转化为时间序列,再进行重采样
        movie_data['release_date'] = release_date = pd.to_datetime(release_date)
        movie_data = movie_data.set_index("release_date")
        #对时间进行降采样,再进行求和,统计每个季度电影上映的数量
        movie_data = movie_data.resample('Q',closed='right',label='right').count().to_period('M')
        #绘制折线图显示
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=80)
        x = movie_data.index
        y = movie_data['img'].tolist()
        plt.plot(range(len(x)),y)
        plt.title("近年来每个季度电影上映的数量统计")
        gird_list = [i*10 for i in range((max(movie_data['img'].tolist()) - min(movie_data['img'].tolist()))//9)]
        plt.grid()
        plt.yticks(gird_list)
        plt.xticks(range(len(x)),x)
        plt.savefig("I:/crack/img/近年来每个季度电影上映的数量统计.png")
        plt.show()

因为要用到时间,所以就要用pandas的时间序列。
首先把上映时间那一列提取出来,然后转化为时间序列,然后在设为索引,然后再进行重采样,只显示年月。
然后就可以进行画图了,如果不懂matplotlib就上matplotlib官网查看怎么写。

注意:图片存储地址,要选择好,不然会出错
在这里插入图片描述

不同类型的电影统计

这里要分析不同种类的电影数量,因为很多电影的类型不只一个,但是我们要把每个电影的每种类型都分出来,这里的数据出来处决于你上面存储的电影类型的数据格式是什么,如果是列表,就要用到mongodb的unwind方法,这里我存储的类型是字符串,所以我不是使用unwind方法。

    def movie_type(self):
        type = self.movie_data['type']
        type_list = type.tolist()
        type_list_2 = []
        for i in type_list:
            list = i.split("、")
            for j in list:
                type_list_2.append(j)
        type_array = pd.DataFrame(type_list_2,columns=['type'])
        type_count = type_array['type'].value_counts()
        y = type_count.values[:-1]
        x = type_count.index[:-1]
        #绘图
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=100)
        rect = plt.bar(range(len(x)),y)
        plt.xticks(range(len(x)),x)
        plt.title("不同类型的电影分类统计")
        plt.grid()
        for r in rect:
            height = r.get_height()
            plt.text(r.get_x() + r.get_width()/2,1.02*height,height,fontsize=18,ha='center')
        plt.savefig("I:/crack/img/不同类型的电影分类统计.png")
        plt.show()

这里我是用split的方法把字符串转化为列表,然后定义一个空列表,把所有类型都存储在一个列表中,然后再转化为dataframe数据类型,再用分类汇总的方法,就可以开始画图了,如果不懂画柱状图就参看我前面的博客,我前面有一篇是专门讲柱状图的。
在这里插入图片描述
注意:图片存储地址,要选择好,不然会出错

统计每个国家生产的电影数量

    def movie_country(self):
        data = self.movie_data
        country = data['country'].value_counts()
        x = country.index
        y = country.values
        #绘图
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=100)
        rect = plt.bar(range(len(x)),y)
        plt.xticks(range(len(x)),x,rotation=45)
        plt.title("不同国家生产的电影汇总")
        for rects in rect:
            height = rects.get_height()
            plt.text(rects.get_x() + rects.get_width()/2,1.02*height,height,fontsize=18,ha='center')
        plt.savefig("I:/crack/img/不同国家生产的电影汇总.png")
        plt.show()

这里的方法很简单就不细讲了。

源代码

'''
从mongodb数据库中读取豆瓣数据,进行数据分析
creat on May 15,2019
@Athor 小明
'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pymongo import MongoClient

pd.set_option('display.max_columns', 10000)
pd.set_option('display.width', 200)
pd.set_option('display.max_colwidth', 1000)
#连接数据库,读取数据
class Douban(object):
    def __init__(self):
        client = MongoClient(host='localhost',port=27017)
        self.collection = client['test_python']['movie_data']
        data = self.collection.find()
        movie_data = pd.DataFrame(data)
        self.movie_data=movie_data.set_index("_id")
    def release_date(self):
        movie_data = self.movie_data
        release_date = movie_data['release_time']
        #将上映时间转化为时间序列,再进行重采样
        movie_data['release_date'] = release_date = pd.to_datetime(release_date)
        movie_data = movie_data.set_index("release_date")
        #对时间进行降采样,再进行求和,统计每个季度电影上映的数量
        movie_data = movie_data.resample('Q',closed='right',label='right').count().to_period('M')
        #绘制折线图显示
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=80)
        x = movie_data.index
        y = movie_data['img'].tolist()
        plt.plot(range(len(x)),y)
        plt.title("近年来每个季度电影上映的数量统计")
        gird_list = [i*10 for i in range((max(movie_data['img'].tolist()) - min(movie_data['img'].tolist()))//9)]
        plt.grid()
        plt.yticks(gird_list)
        plt.xticks(range(len(x)),x)
        # plt.savefig("I:/crack/img/近年来每个季度电影上映的数量统计.png")
        # plt.show()
    def movie_type(self):
        type = self.movie_data['type']
        type_list = type.tolist()
        type_list_2 = []
        for i in type_list:
            list = i.split("、")
            for j in list:
                type_list_2.append(j)
        type_array = pd.DataFrame(type_list_2,columns=['type'])
        type_count = type_array['type'].value_counts()
        y = type_count.values[:-1]
        x = type_count.index[:-1]
        #绘图
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=100)
        rect = plt.bar(range(len(x)),y)
        plt.xticks(range(len(x)),x)
        plt.title("不同类型的电影分类统计")
        plt.grid()
        for r in rect:
            height = r.get_height()
            plt.text(r.get_x() + r.get_width()/2,1.02*height,height,fontsize=18,ha='center')
        # plt.savefig("I:/crack/img/不同类型的电影分类统计.png")
        # plt.show()
    def movie_country(self):
        data = self.movie_data
        country = data['country'].value_counts()
        x = country.index
        y = country.values
        #绘图
        plt.rcParams['font.family'] = 'SimHei'
        plt.figure(figsize=(20,10),dpi=100)
        rect = plt.bar(range(len(x)),y)
        plt.xticks(range(len(x)),x,rotation=45)
        plt.title("不同国家生产的电影汇总")
        for rects in rect:
            height = rects.get_height()
            plt.text(rects.get_x() + rects.get_width()/2,1.02*height,height,fontsize=18,ha='center')
        plt.savefig("I:/crack/img/不同国家生产的电影汇总.png")
        plt.show()
movie = Douban()
movie.movie_country()

这篇博客还有什么不懂的地方,可以添加我的QQ:1693490575

发布了28 篇原创文章 · 获赞 14 · 访问量 6786

猜你喜欢

转载自blog.csdn.net/weixin_42304193/article/details/90273678