大佬用python写了个豆瓣短评爬虫,来试试你喜欢的电影吧

前言

本篇主要实现的是对任意一部电影短评(热门)的抓取以及可视化分析。也就是你只要提供链接和一些基本信息,他就可以

分析

对于豆瓣爬虫,what shold we 考虑?怎么分析呢?豆瓣电影首页

这个首先的话尝试就可以啦,打开任意一部电影,这里以姜子牙为例。打开姜子牙你就会发现它是非动态渲染的页面,也就是传统的渲染方式,直接请求这个url即可获取数据。但是翻着翻着页面你就会发现:未登录用户只能访问优先的界面,登录的用户才能有权限去访问后面的页面。

所以这个流程应该是登录——> 爬虫——>存储——>可视化分析

这里提一下环境和所需要的安装,环境为python3,代码在win和linux可成功跑,如果mac和linux不能跑友字体乱码问题还请私我。其中pip用到包如下,直接用清华 镜像下载不然很慢很慢(够贴心不)。如果大家在学习中遇到困难,想找一个python学习交流环境,可以加入我们的python圈,裙号930900780,可领取python学习资料,会节约很多时间,减少很多遇到的难题。

pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install xlrd -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install bs4 -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install wordcloud -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple

复制代码

登录

豆瓣的登录地址

进去后有个密码登录栏,我们要分析在登录的途中发生了啥,打开F12控制台是不够的,我们还要使用Fidder抓包。

打开F12控制台然后点击登录,多次试探之后发现登录接口也很简单:

查看请求的参数发现就是普通请求,无加密,当然这里可以用fidder进行抓包,这里我简单测试了一下用错误密码进行测试。如果失败的小伙伴可以尝试手动登陆再退出这样再跑程序。

这样编写登录模块的代码:

url='https://accounts.douban.com/j/mobile/login/basic'

header={'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',

'Referer': 'https://accounts.douban.com/passport/login_popup?login_source=anony',

        'Origin': 'https://accounts.douban.com',

'content-Type':'application/x-www-form-urlencoded',

'x-requested-with':'XMLHttpRequest',

'accept':'application/json',

'accept-encoding':'gzip, deflate, br',

'accept-language':'zh-CN,zh;q=0.9',

'connection': 'keep-alive'

,'Host': 'accounts.douban.com'

}

data={

    'ck':'',

    'name':'',

    'password':'',

    'remember':'false',

    'ticket':''

}

def login(username,password):

    global  data

    data['name']=username

    data['password']=password

    data=urllib.parse.urlencode(data)

    print(data)

    req=requests.post(url,headers=header,data=data,verify=False)

    cookies = requests.utils.dict_from_cookiejar(req.cookies)

    print(cookies)

    return cookies

复制代码

这块高清之后,整个执行流程大概为:

爬取

成功登录之后,我们就可以携带登录的信息访问网站为所欲为的爬取信息了。虽然它是传统交互方式,但是每当你切换页面时候会发现有个ajax请求。

这部分接口我们可以直接拿到评论部分的数据,就不需要请求整个页面然后提取这部分的内容了。而这部分的url规律和之前分析的也是一样,只有一个start表示当前的条数在变化,所以直接拼凑url就行。

也就是用逻辑拼凑url一直到不能正确操作为止。

https://movie.douban.com/subject/25907124/comments?percent_type=&start=0&其他参数省略

https://movie.douban.com/subject/25907124/comments?percent_type=&start=20&其他参数省略

https://movie.douban.com/subject/25907124/comments?percent_type=&start=40&其他参数省略

复制代码

对于每个url访问之后如何提取信息呢? 我们根据css选择器进行筛选数据,因为每个评论他们的样式相同,在html中就很像一个列表中的元素一样。

再观察我们刚刚那个ajax接口返回的数据刚好是下面红色区域块,所以我们直接根据class搜素分成若干小组进行操作就可以。

在具体的实现上,我们使用requests发送请求获取结果,使用BeautifulSoup去解析html格式文件。 而我们所需要的数据也很容易分析对应部分。

实现的代码为:

import requests

from  bs4 import BeautifulSoup

url='https://movie.douban.com/subject/25907124/comments?percent_type=&start=0&limit=20&status=P&sort=new_score&comments_only=1&ck=C7di'

header = {

    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',

}

req = requests.get(url,headers=header,verify=False)

res = req.json() # 返回的结果是一个json

res = res['html']

soup = BeautifulSoup(res, 'lxml')

node = soup.select('.comment-item')

for va in node:

    name = va.a.get('title')

    star = va.select_one('.comment-info').select('span')[1].get('class')[0][-2]

    comment = va.select_one('.short').text

    votes=va.select_one('.votes').text

    print(name, star,votes, comment)

复制代码

这个测试的执行结果为:

储存

数据爬取完就要考虑存储,我们将数据储存到cvs中。

使用xlwt将数据写入excel文件中,xlwt基本应用实例:

import xlwt

#创建可写的workbook对象

workbook = xlwt.Workbook(encoding='utf-8')

#创建工作表sheet

worksheet = workbook.add_sheet('sheet1')

#往表中写内容,第一个参数 行,第二个参数列,第三个参数内容

worksheet.write(0, 0, 'bigsai')

#保存表为test.xlsx

workbook.save('test.xlsx')

复制代码

使用xlrd读取excel文件中,本案例xlrd基本应用实例:

import xlrd

#读取名称为test.xls文件

workbook = xlrd.open_workbook('test.xls')

# 获取第一张表

table =  workbook.sheets()[0]  # 打开第1张表

# 每一行是个元组

nrows = table.nrows

for i in range(nrows):

    print(table.row_values(i))#输出每一行

复制代码

到这里,我们对登录模块+爬取模块+存储模块就可把数据存到本地了,具体整合的代码为:

import requests

from bs4 import BeautifulSoup

import urllib.parse

import xlwt

import xlrd

# 账号密码

def login(username, password):

    url = 'https://accounts.douban.com/j/mobile/login/basic'

    header = {

        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',

        'Referer': 'https://accounts.douban.com/passport/login_popup?login_source=anony',

        'Origin': 'https://accounts.douban.com',

        'content-Type': 'application/x-www-form-urlencoded',

        'x-requested-with': 'XMLHttpRequest',

        'accept': 'application/json',

        'accept-encoding': 'gzip, deflate, br',

        'accept-language': 'zh-CN,zh;q=0.9',

        'connection': 'keep-alive'

        , 'Host': 'accounts.douban.com'

    }

    # 登陆需要携带的参数

    data = {

        'ck' : '',

        'name': '',

        'password': '',

        'remember': 'false',

        'ticket': ''

    }

    data['name'] = username

    data['password'] = password

    data = urllib.parse.urlencode(data)

    print(data)

    req = requests.post(url, headers=header, data=data, verify=False)

    cookies = requests.utils.dict_from_cookiejar(req.cookies)

    print(cookies)

    return cookies

def getcomment(cookies, mvid):  # 参数为登录成功的cookies(后台可通过cookies识别用户,电影的id)

    start = 0

    w = xlwt.Workbook(encoding='ascii')  # #创建可写的workbook对象

    ws = w.add_sheet('sheet1')  # 创建工作表sheet

    index = 1  # 表示行的意思,在xls文件中写入对应的行数

    while True:

        # 模拟浏览器头发送请求

        header = {

            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',

        }

        # try catch 尝试,一旦有错误说明执行完成,没错误继续进行

        try:

            # 拼凑url 每次star加20

            url = 'https://movie.douban.com/subject/' + str(mvid) + '/comments?start=' + str(

                start) + '&limit=20&sort=new_score&status=P&comments_only=1'

            start += 20

            # 发送请求

            req = requests.get(url, cookies=cookies, headers=header)

            # 返回的结果是个json字符串 通过req.json()方法获取数据

            res = req.json()

            res = res['html']  # 需要的数据在`html`键下

            soup = BeautifulSoup(res, 'lxml')  # 把这个结构化html创建一个BeautifulSoup对象用来提取信息

            node = soup.select('.comment-item')  # 每组class 均为comment-item  这样分成20条记录(每个url有20个评论)

            for va in node:  # 遍历评论

                name = va.a.get('title')  # 获取评论者名称

                star = va.select_one('.comment-info').select('span')[1].get('class')[0][-2]  # 星数好评

                votes = va.select_one('.votes').text  # 投票数

                comment = va.select_one('.short').text  # 评论文本

                print(name, star, votes, comment)

                ws.write(index, 0, index)  # 第index行,第0列写入 index

                ws.write(index, 1, name)  # 第index行,第1列写入 评论者

                ws.write(index, 2, star)  # 第index行,第2列写入 评星

                ws.write(index, 3, votes)  # 第index行,第3列写入 投票数

                ws.write(index, 4, comment)  # 第index行,第4列写入 评论内容

                index += 1

        except Exception as e:  # 有异常退出

            print(e)

            break

    w.save('test.xls')  # 保存为test.xls文件

if __name__ == '__main__':

    username = input('输入账号:')

    password = input('输入密码:')

    cookies = login(username, password)

    mvid = input('电影的id为:')

    getcomment(cookies, mvid)

复制代码

执行之后成功存储数据:

可视化分析

我们要对评分进行统计、词频统计。还有就是生成词云展示。而对应的就是matplotlib、WordCloud库。

实现的逻辑思路:读取xls的文件,将评论使用分词处理统计词频,统计出现最多的词语制作成直方图和词语。将评星数量做成饼图展示一下,主要代码均有注释,具体的代码为:

其中代码为:

import matplotlib.pyplot as plt

import matplotlib

import jieba

import jieba.analyse

import xlwt

import xlrd

from wordcloud import WordCloud

import numpy as np

from collections import Counter

# 设置字体 有的linux字体有问题

matplotlib.rcParams['font.sans-serif'] = ['SimHei']

matplotlib.rcParams['axes.unicode_minus'] = False

# 类似comment 为评论的一些数据 [  ['1','名称','star星','赞同数','评论内容']  ,['2','名称','star星','赞同数','评论内容'] ]元组

def anylasescore(comment):

    score = [0, 0, 0, 0, 0, 0]  # 分别对应0 1 2 3 4 5分出现的次数

    count = 0  # 评分总次数

    for va in comment:  # 遍历每条评论的数据  ['1','名称','star星','赞同数','评论内容']

        try:

            score[int(va[2])] += 1  # 第3列 为star星 要强制转换成int格式

            count += 1

        except Exception as e:

            continue

    print(score)

    label = '1分', '2分', '3分', '4分', '5分'

    color = 'blue', 'orange', 'yellow', 'green', 'red'  # 各类别颜色

    size = [0, 0, 0, 0, 0]  # 一个百分比数字 合起来为100

    explode = [0, 0, 0, 0, 0]  # explode :(每一块)离开中心距离;

    for i in range(1, 5):  # 计算

        size[i] = score[i] * 100 / count

        explode[i] = score[i] / count / 10

    pie = plt.pie(size, colors=color, explode=explode, labels=label, shadow=True, autopct='%1.1f%%')

    for font in pie[1]:

        font.set_size(8)

    for digit in pie[2]:

        digit.set_size(8)

    plt.axis('equal')  # 该行代码使饼图长宽相等

    plt.title(u'各个评分占比', fontsize=12)  # 标题

    plt.legend(loc=0, bbox_to_anchor=(0.82, 1))  # 图例

    # 设置legend的字体大小

    leg = plt.gca().get_legend()

    ltext = leg.get_texts()

    plt.setp(ltext, fontsize=6)

    plt.savefig("score.png")

    # 显示图

    plt.show()

def getzhifang(map):  # 直方图二维,需要x和y两个坐标

    x = []

    y = []

    for k, v in map.most_common(15):  # 获取前15个最大数值

        x.append(k)

        y.append(v)

    Xi = np.array(x)  # 转成numpy的坐标

    Yi = np.array(y)

    width = 0.6

    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签

    plt.figure(figsize=(8, 6))  # 指定图像比例: 8:6

    plt.bar(Xi, Yi, width, color='blue', label='热门词频统计', alpha=0.8, )

    plt.xlabel("词频")

    plt.ylabel("次数")

    plt.savefig('zhifang.png')

    plt.show()

    return

def getciyun_most(map):  # 获取词云

    # 一个存对应中文单词,一个存对应次数

    x = []

    y = []

    for k, v in map.most_common(300):  # 在前300个常用词语中

        x.append(k)

        y.append(v)

    xi = x[0:150]  # 截取前150个

    xi = ' '.join(xi)  # 以空格 ` `将其分割为固定格式(词云需要)

    print(xi)

    # backgroud_Image = plt.imread('')  # 如果需要个性化词云

    # 词云大小,字体等基本设置

    wc = WordCloud(background_color="white",

                  width=1500, height=1200,

                  # min_font_size=40,

                  # mask=backgroud_Image,

                  font_path="simhei.ttf",

                  max_font_size=150,  # 设置字体最大值

                  random_state=50,  # 设置有多少种随机生成状态,即有多少种配色方案

                  )  # 字体这里有个坑,一定要设这个参数。否则会显示一堆小方框wc.font_path="simhei.ttf"  # 黑体

    # wc.font_path="simhei.ttf"

    my_wordcloud = wc.generate(xi)  #需要放入词云的单词 ,这里前150个单词

    plt.imshow(my_wordcloud)  # 展示

    my_wordcloud.to_file("img.jpg")  # 保存

    xi = ' '.join(x[150:300])  # 再次获取后150个单词再保存一张词云

    my_wordcloud = wc.generate(xi)

    my_wordcloud.to_file("img2.jpg")

    plt.axis("off")

def anylaseword(comment):

    # 这个过滤词,有些词语没意义需要过滤掉

    list = ['这个', '一个', '不少', '起来', '没有', '就是', '不是', '那个', '还是', '剧情', '这样', '那样', '这种', '那种', '故事', '人物', '什么']

    print(list)

    commnetstr = ''  # 评论的字符串

    c = Counter()  # python一种数据集合,用来存储字典

    index = 0

    for va in comment:

        seg_list = jieba.cut(va[4], cut_all=False)  ## jieba分词

        index += 1

        for x in seg_list:

            if len(x) > 1 and x != '\r\n':  # 不是单个字 并且不是特殊符号

                try:

                    c[x] += 1  # 这个单词的次数加一

                except:

                    continue

        commnetstr += va[4]

    for (k, v) in c.most_common():  # 过滤掉次数小于5的单词

        if v < 5 or k in list:

            c.pop(k)

            continue

        # print(k,v)

    print(len(c), c)

    getzhifang(c)  # 用这个数据进行画直方图

    getciyun_most(c)  # 词云

    # print(commnetstr)

def anylase():

    data = xlrd.open_workbook('test.xls')  # 打开xls文件

    table = data.sheets()[0]  # 打开第i张表

    nrows = table.nrows  # 若干列的一个集合

    comment = []

    for i in range(nrows):

        comment.append(table.row_values(i))  # 将该列数据添加到元组中

    # print(comment)

    anylasescore(comment)

    anylaseword(comment)

if __name__ == '__main__':

    anylase()

复制代码

我们再来查看一下执行的效果:

这里我选了姜子牙和千与千寻 电影的一些数据,两个电影评分比例对比为:

从评分可以看出明显千与千寻好评度更高,大部分人愿意给他五分。基本算是最好看的动漫之一了,再来看看直方图的词谱:

很明显千与千寻的作者更出名,并且有很大的影响力,以至于大家纷纷提起他。再看看两者词云图:

宫崎骏、白龙、婆婆,真的是满满的回忆,好了不说了,有啥想说的欢迎讨论!

最后多说一句,想学习Python可联系小编,这里有我自己整理的整套python学习资料和路线,想要这些资料的都可以进q裙930900780领取。

本文章素材来源于网络,如有侵权请联系删除。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342