Python爬虫实战,pyecharts模块,Python实

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」。

前言

利用Python实现大江大河评论数据可视化。废话不多说。

让我们愉快地开始吧~

开发工具

Python版本: 3.6.4

相关模块:

requests模块

proxy2808

pandas模块

pyecharts模块;

以及一些Python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

因为豆瓣反爬还是比较严重的

反爬

2808PROXY提供的代理服务

2808PROXY提供的代理服务

没有用代理的话基本就没戏了

分析网页

虽然评论有两万多条,但是豆瓣在登陆的情况下,也只是放出500条数据。

本次只获取全部评论以及差评评论标签页下的数据,合计约为900多条。

网页分析

然后便是获取用户的注册时间。

900多个用户,900多个请求。

我相信不用代理,绝对Game Over。

4.jpg

获取数据

评论及用户信息获取的代码

import time
import requests
import proxy2808
from bs4 import BeautifulSoup

USERNAME = '用户名'
PASSWORD = '密码'

headers = {
    'Cookie': '你的Cookie值',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}


def get_comments(page, proxy_url_secured):
    """
    评论获取
    """
    # 热门评论获取
    url = 'https://movie.douban.com/subject/26797690/comments?start=' + str(page) + '&limit=20&sort=new_score&status=P'
    # 好评获取
    # url = 'https://movie.douban.com/subject/26797690/comments?start=' + str(page) + '&limit=20&sort=new_score&status=P&percent_type=h'
    # 一般评论获取
    # url = 'https://movie.douban.com/subject/26797690/comments?start=' + str(page) + '&limit=20&sort=new_score&status=P&percent_type=m'
    # 差评获取
    # url = 'https://movie.douban.com/subject/26797690/comments?start=' + str(page) + '&limit=20&sort=new_score&status=P&percent_type=l'
    # 使用2808proxy代理
    response = requests.get(url=url, headers=headers, proxies={'http': proxy_url_secured, 'https': proxy_url_secured})
    soup = BeautifulSoup(response.text, 'html.parser')
    for div in soup.find_all(class_='comment-item'):
        time.sleep(3)
        # 评论信息
        comment_info = div.find(class_='comment-info')
        # 用户名
        user_name = comment_info.find('a').get_text()
        print(user_name)
        # 用户主页地址
        user_url = comment_info.find('a').attrs['href']
        print(user_url)
        # 获取用户注册时间,看水军必备
        registered_time = get_user(user_url, proxy_url_secured)
        print(registered_time)
        # 用户评分
        score = comment_info.find_all('span')[1].attrs['class'][0][-2:-1]
        print(score)
        # 用户评价
        eva = comment_info.find_all('span')[1].attrs['title']
        print(eva)
        # 有用数
        useful_num = div.find(class_='votes').get_text()
        print(useful_num)
        # 评价日期
        date = comment_info.find(class_='comment-time ').attrs['title'].split(' ')[0]
        print(date)
        # 评价时间
        comment_time = comment_info.find(class_='comment-time ').attrs['title'].split(' ')[1]
        print(comment_time)
        # 用户评论
        comment = div.find(class_='short').get_text().replace('\n', '').strip().replace(',', ',').replace(' ', '')
        print(comment)
        # 写入csv文件
        with open('comments_douban_l.csv', 'a', encoding='utf-8-sig') as f:
            f.write(user_name + ',' + user_url + ',' + registered_time + ',' + score + ',' + date + ',' + comment_time + ',' + useful_num + ',' + comment + '\n')
        f.close()


def get_user(user_url, proxy_url_secured):
    """
    获取用户注册时间
    """
    # 使用2808proxy代理
    response = requests.get(url=user_url, headers=headers, proxies={'http': proxy_url_secured, 'https': proxy_url_secured})
    soup = BeautifulSoup(response.text, 'html.parser')
    user_message = soup.find(class_='basic-info')
    # 获取用户注册时间
    try:
        user_registered = user_message.find(class_='pl')
        registered_time = user_registered.get_text().split('  ')[1].replace('加入', '')
    except:
        registered_time = 'unknow'
    return registered_time


def main():
    num = 0
    for i in range(0, 500, 20):
        cli = proxy2808.Client(username=USERNAME, password=PASSWORD)
        cli.release_all()
        p = cli.get_proxies(amount=1, expire_seconds=300)[0]
        proxy_url_secured = "%s://%s:%s@%s:%d" % ('http', USERNAME, PASSWORD, p['ip'], p['http_port_secured'])
        print(proxy_url_secured)
        get_comments(i, proxy_url_secured)
        num += 1


if __name__ == '__main__':
    main()
复制代码

获取全部评论标签页下的数据(500条)。

数据1

红框部分为用户的注册时间。

假设我能爬取所有评论,那么水军估计要被我逮到了。

个人理解,水军就是过多的新注册用户...

然而豆瓣并没有给我们这个机会。

获取差评标签页的数据(482条)。

数据2

看看给差评的用户注册时间。

相较好评的用户注册时间,有那么点意思了。

注册时间相对都比较晚。

分析情感

评论的情感分析使用百度的自然语言处理。

情感分析

下面利用网站做个示例。

示例

具体的可以去官网看文档,这里只是简述一番。

通过你的百度账号登陆百度的AI开发平台,新建自然语言处理项目。

获取「API Key」及「Secret Key」后。

调用情感倾向分析接口,得到情感结果。

import urllib.request
import pandas
import json
import time


def get_access_token():
    """
    获取百度AI平台的Access Token
    """
    # 使用你的API Key及Secret Key
    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=[API Key]&client_secret=[Secret Key]'
    request = urllib.request.Request(host)
    request.add_header('Content-Type', 'application/json; charset=UTF-8')
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    rdata = json.loads(content)
    return rdata['access_token']


def sentiment_classify(text, acc):
    """
    获取文本的感情偏向(消极 or 积极 or 中立)
    参数:
    text:str 本文
    """
    raw = {"text":"内容"}
    raw['text'] = text
    data = json.dumps(raw).encode('utf-8')
    # 情感倾向分析接口
    host = "https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?charset=UTF-8&access_token=" + acc
    request = urllib.request.Request(url=host, data=data)
    request.add_header('Content-Type', 'application/json')
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    rdata = json.loads(content)
    return rdata


# 获取access_token
access_token = get_access_token()
# 差评标签
df = pandas.read_csv('comments_douban_l.csv', header=None, names=['user_name', 'user_url', 'registered_time', 'score', 'date', 'comment_time', 'useful_num', 'comment'])
# 好评标签
# df = pandas.read_csv('comments_douban_a.csv', header=None, names=['user_name', 'user_url', 'registered_time', 'score', 'date', 'comment_time', 'useful_num', 'comment'])

# 输出情感极性分类结果,0:负向,1:中性,2:正向
sentiments = []
for text in df['comment']:
    time.sleep(1)
    result = sentiment_classify(str(text), access_token)
    value = result['items'][0]['sentiment']
    sentiments.append(value)
    # print(result)
    print(result['items'][0]['sentiment'], text)

# 添加评分列及情感列
df['score1'] = df['score']
df['emotional'] = sentiments
# 差评标签
df.to_csv('comments_douban_ll.csv', header=0, index=False, encoding='utf-8-sig')
# 好评标签
# df.to_csv('comments_douban_al.csv', header=0, index=False, encoding='utf-8-sig')
复制代码

情感分析结果如下。

9.jpg

总的来说5星评分的结果多为正向(2)的。

当然也出现了一些负向(0)的结果。

不过还是在可接受范围内。

结果

1星评分的评论情感倾向多为负向。

这里把正向的用红框圈出来了,大家可以自行体会。

毕竟机器的识别水平有限,想达到100%识别,可能性几乎为0。

数据可视化

评论日期分布情况

全部短评-500评论日期分布

全部差评-500评论日期分布

热评随着电视剧的开播,便慢慢没有什么变化。

而差评却在后头有一些波动。

评论时间分布情况

全部短评-500评论日间分布

全部差评-500评论日间分布

大部分评论都是在晚上评论的,符合常态。

评论评分情况

全部短评-500评论评分情况

全部差评-500评论日间分布

全部短评的5星评分占大头。

全部差评的1星和2星占大头。

评论情感分析情况

全部短评-500评论情感分析情况

全部差评-500评论情感分析

其中「2」代表积极的,「1」代表中性的,「-2」代表消极的。

全部短评的正向结果占大头。

全部短评的排序是基于点赞数而来的。

所以对于整部剧,大家还是比较认可的。

评论用户注册时间

全部短评-用户注册时间分布

全部差评-用户注册时间分布

生成评论词云

好评词云

好评词云

差评词云

差评词云