python系列之(4)豆瓣图书《平凡的世界》书评及情感分析

摘要:
本文主要捕捉和分析豆瓣《平凡的世界》一书的短评,并使用snowNLP分析其情感。p=“+strprinthttp=urllib3.PoolManager()time.sleetry:r=http.requestplain_text=r.data.decode()printexceptExceptionase:printscontinuesoup=BeautifulSoupligroup=sound.find_allforiteminligroup:try:comment=item.find.a.getspanlists=listwhile”“inspanlists:spanlists.remove(”“)if:stars=spanlist[1].getstars=switch_casecommenttime=spanlists[2]。strillerse:stars=0commenttime=spanlists[1].stringcontent=项查找。get_text()add_commentexceptExceptionase:print_continuepage_num+=1ifpage_num˃999:breakdefswitch_Case:switcher={“建议”:5,“推荐”:4,“不坏”:3,“差”:2,“非常坏”:1}returnswitcher。getdefadd_comment:conn=sqlite3.connectcursor=conn.cursor()游标。execute(“插入注释值(null,?)”,)cursor.close()连接commit()连接。在close()获取之后,您可以在表中看到数据sqlite˃selectcountfromcomment;8302sqlite˃selectstar,从commentgroupystar开始计数;0 | 13591 | 582 | 1333 | 6434 | 18755 | 4234sqlite˃从评论者中选择*,按iddeslimit5;8302|斯坦利|4|2014-11-19|经典中的经典8301|这里的杰瑞|4|2016-03-08|非凡的8300|麦田里的沉睡者|5|2012-08-12|这本小说是我在大学里读的第一本,它给我带来了无与伦比的震撼。它把我从高中时读的那些yy小说中彻底唤醒了。

本篇主要是通过对豆瓣图书《平凡的世界》短评进行抓取并进行分析,并用snowNLP对其进行情感分析。

用到的模块有snowNLP,是一个python库,用来进行情感分析。

1.抓取数据

我们把抓取到的数据存储到sqlite,先建表,结构如下:

CREATE TABLE comment(
   id  integer PRIMARY KEY autoincrement     NOT NULL,
   commentator             VARCHAR(50)    NOT NULL,
   star           INTEGER   NOT NULL,
   time          VARCHAR(50)    NOT NULL,
   content       TEXT NOT NULL
   );

然后写python代码进行抓取,如下:

import sys
from os import path
import time
import urllib3
import requests
import numpy as np
import sqlite3
from bs4 import BeautifulSoup
from urllib import parse
from snownlp import SnowNLP
import matplotlib.pyplot as plt
import jieba
from wordcloud import WordCloud
from PIL import Image

headers=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},
{'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}]

def get_comment():
    page_num = 0;
    total_num = 0;
    while(1):
        page_num +=1
        url = "https://book.douban.com/subject/1200840/comments/hot?p="+str(page_num)
        print(url)
        http = urllib3.PoolManager()
        time.sleep(np.random.rand()*5)
        try:
            r = http.request("GET", url, headers=headers[page_num%len(headers)])
            plain_text = r.data.decode()
            print(plain_text)
        except Exception as e:
            print(e)
            continue
 
        soup = BeautifulSoup(plain_text, features="lxml")
        ligroup = soup.find_all("li", class_="comment-item")

        for item in ligroup:
            try:
                commentator = item.find("div", class_="avatar").a.get("title")
                spanlists = list(item.find("div", class_="comment").find("span", class_="comment-info"))
                while "
" in spanlists:
                    spanlists.remove("
")
                
                if (len(spanlists) == 3) :
                    stars = spanlists[1].get("title")
                    stars = switch_case(stars)
                    commenttime = spanlists[2].string
                else:
                    stars = 0
                    commenttime = spanlists[1].string

                content = item.find("span", class_="short").get_text()
                add_comment(commentator, stars, commenttime, content)
            except Exception as e:
                print(e)
                continue
        page_num+=1
        if page_num > 999:
            break

def switch_case(value):
    switcher = {
        "力荐":5,
        "推荐":4,
        "还行":3,
        "较差":2,
        "很差":1
    }
    return switcher.get(value, 0)

def add_comment(commentator, star, time, content):
    conn = sqlite3.connect("spider.db")
    cursor = conn.cursor()
    cursor.execute("insert into comment values (null, ?, ?, ?, ?)", (commentator, star, time, content))
    cursor.close()
    conn.commit()
    conn.close()

抓取完之后可以在表中看到数据

sqlite> select count(1) from comment;
8302
sqlite> select star,count(1) from comment group by star;
0|1359
1|58
2|133
3|643
4|1875
5|4234
sqlite> select * from comment order by id desc limit 5;
8302|燊栎|4|2014-11-19|经典中的经典
8301|Jerryhere|4|2016-03-08|平凡中的不平凡
8300|麦田睡觉者|5|2012-08-12|这部小说是我上大学看的第一本小说,它带给我的震撼是无与伦比的。彻底将我从高中时看的那些yy小说里震醒。同时,它真的是一部非常好看的小说,平凡的世界里不平凡的人生,生命总是充满苦痛伤悲,这些苦难让生命愈发的沉重厚实
8299|朔望|0|2013-07-29|人生就是如此平凡
8298|mindinthesky|0|2012-09-17|不错,中国就是这样子

2.简单分析

数据抓取完了之后我们进行简单分析,看下各个星的占比

python系列之(4)豆瓣图书《平凡的世界》书评及情感分析第1张

然后在把所有的comment导到文件中,进行词云分析

导出如下:

>sqlite3 -header -csv spider.db "select content from comment;" > commentall.csv

完了就会在当前目录下生成一个commentall.csv的文件

然后可以对其词云分析,代码如下:

def make_cloud():
    text = open('commentall.txt', 'r', encoding='utf-8').read()
    cut_text = jieba.cut(text)
    result = " ".join(cut_text)
    wc = WordCloud(
        font_path='Deng.ttf',     #字体路劲
        background_color='white',   #背景颜色
        width=2000,
        height=1200,
        max_font_size=100,            #字体大小
        min_font_size=10,
        mask=plt.imread('timg.jpeg'),  #背景图片
        max_words=1000
    )
    wc.generate(result)
    wc.to_file('jielun.png')    #图片保存

    plt.figure('jielun')   #图片显示的名字
    plt.imshow(wc)
    plt.axis('off')        #关闭坐标
    plt.show() 

分析完之后的图片输出是下图:

python系列之(4)豆瓣图书《平凡的世界》书评及情感分析第2张

3.情感分析

我们从打的五星和一星能清楚的看到情感,但是对零星的就不太好判断,现在主要是用snowNLP对零星的做情感分析。要想分析,就先得训练,因为目前的是针对电商的评论,不适合现在的场景,怎么训练呢?

首先,我们把5颗星的评论导出存为pos.txt,作为积极的评论,把1颗星的评论导出存为neg.txt作为消极的评论;

然后,利用pos.txt和neg.txt进行训练

最后,在利用训练完的模型对0颗星的进行分析

好了,开始吧

首先导出

>sqlite3 -header -csv spider.db "select conent from comment where star = 5 limit 100;" > pos.csv

>sqlite3 -header -csv spider.db "select conent from comment  where star = 1 limit 100;" > neg.csv

 然后找到snownlp的安装路径,如下方法:

kumufengchunMacBook-Pro:douban kumufengchun$ python
Python 3.6.4 (default, Jun  6 2019, 17:59:50)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.44.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import snownlp
>>> snownlp
<module 'snownlp' from '/Users/kumufengchun/.pyenv/versions/3.6.4/lib/python3.6/site-packages/snownlp/__init__.py'>

找到了之后,把刚才的pos.scv和neg.csv拷贝到

/Users/kumufengchun/.pyenv/versions/3.6.4/lib/python3.6/site-packages/snownlp/sentiment/下边的pos.txt和neg.txt,为了保持名字一致,我们可以把之前的csv后缀的改为txt
然后开始用刚才导出的数据进行训练,训练完之后的输出保存为commentsentiment.marshal
from snownlp import sentiment
sentiment.train('neg.txt', 'pos.txt')
sentiment.save('commentsentiment.marshal')

然后把训练完输出的文件,在init文件中修改,文件训练完之后输出的是commentsentiment.marshal.3,后缀3是版本的意思,不用管他,在引用的时候不要加3,否则会报错,修改代码如下:

/Users/kumufengchun/.pyenv/versions/3.6.4/lib/python3.6/site-packages/snownlp/sentiment/__init__.py

data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                         'commentsentiment.marshal')

  

好了,训练完之后,我们可以进行简单的测试

from snownlp import SnowNLP

str = "好很好"
s = SnowNLP(str)
print(s.words)
print(s.tags)
print(s.sentiments)

输出如下:

['', '', '']
<zip object at 0x124963588>
0.6088772592136402

4.用训练的模型进行情感分析

代码如下:

def get_comment_bypage(offset, limit):
    conn = sqlite3.connect("spider.db")
    cursor = conn.cursor()
    cursor.execute('select content from comment where star=0 limit ?,?', (offset, limit))
    values = cursor.fetchall()
    cursor.close()
    conn.close()
    return values


def analyse_sentiment():
    offset = 0
    limit = 50
    commentcounts = {}
    while (offset < 1400):
        comments = get_comment_bypage(offset, limit)
        for comment in comments:
            s = SnowNLP(''.join(comment))
            print(s.sentiments)
            sentiment = round(s.sentiments, 2)
            if sentiment in commentcounts:
                commentcounts[sentiment] += 1 
            else:
                commentcounts[sentiment] = 1
        offset+=limit
    print(commentcounts)
    return commentcounts

然后我们把所有的输出做个图如下:

python系列之(4)豆瓣图书《平凡的世界》书评及情感分析第3张 

可以看到每个输出所占的数量,如何判断是积极还是消极呢,一般采取0.3,大于0.3的为积极,否则为消极,也可以把之前的数据都跑一遍,定义个区间。

完整的代码如下:

import sys
from os import path
import time
import urllib3
import requests
import numpy as np
import sqlite3
from bs4 import BeautifulSoup
from urllib import parse
from snownlp import SnowNLP
import matplotlib.pyplot as plt
import jieba
from wordcloud import WordCloud
from PIL import Image

headers=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},
{'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}]

def get_comment():
    page_num = 0;
    total_num = 0;
    while(1):
        page_num +=1
        url = "https://book.douban.com/subject/1200840/comments/hot?p="+str(page_num)
        print(url)
        http = urllib3.PoolManager()
        time.sleep(np.random.rand()*5)
        try:
            r = http.request("GET", url, headers=headers[page_num%len(headers)])
            plain_text = r.data.decode()
            print(plain_text)
        except Exception as e:
            print(e)
            continue
 
        soup = BeautifulSoup(plain_text, features="lxml")
        ligroup = soup.find_all("li", class_="comment-item")

        for item in ligroup:
            try:
                commentator = item.find("div", class_="avatar").a.get("title")
                spanlists = list(item.find("div", class_="comment").find("span", class_="comment-info"))
                while "
" in spanlists:
                    spanlists.remove("
")
                
                if (len(spanlists) == 3) :
                    stars = spanlists[1].get("title")
                    stars = switch_case(stars)
                    commenttime = spanlists[2].string
                else:
                    stars = 0
                    commenttime = spanlists[1].string

                content = item.find("span", class_="short").get_text()
                add_comment(commentator, stars, commenttime, content)
            except Exception as e:
                print(e)
                continue
        page_num+=1
        if page_num > 999:
            break

def switch_case(value):
    switcher = {
        "力荐":5,
        "推荐":4,
        "还行":3,
        "较差":2,
        "很差":1
    }
    return switcher.get(value, 0)

def add_comment(commentator, star, time, content):
    conn = sqlite3.connect("spider.db")
    cursor = conn.cursor()
    cursor.execute("insert into comment values (null, ?, ?, ?, ?)", (commentator, star, time, content))
    cursor.close()
    conn.commit()
    conn.close()


def get_comment_bypage(offset, limit):
    conn = sqlite3.connect("spider.db")
    cursor = conn.cursor()
    cursor.execute('select content from comment where star=0 limit ?,?', (offset, limit))
    values = cursor.fetchall()
    cursor.close()
    conn.close()
    return values


def analyse_sentiment():
    offset = 0
    limit = 50
    commentcounts = {}
    while (offset < 1400):
        comments = get_comment_bypage(offset, limit)
        for comment in comments:
            s = SnowNLP(''.join(comment))
            print(s.sentiments)
            sentiment = round(s.sentiments, 2)
            if sentiment in commentcounts:
                commentcounts[sentiment] += 1 
            else:
                commentcounts[sentiment] = 1
        offset+=limit
    print(commentcounts)
    return commentcounts


def make_cloud():
    text = open('commentall.txt', 'r', encoding='utf-8').read()
    cut_text = jieba.cut(text)
    result = " ".join(cut_text)
    wc = WordCloud(
        font_path='Deng.ttf',     #字体路劲
        background_color='white',   #背景颜色
        width=2000,
        height=1200,
        max_font_size=100,            #字体大小
        min_font_size=10,
        mask=plt.imread('timg.jpeg'),  #背景图片
        max_words=1000
    )
    wc.generate(result)
    wc.to_file('jielun.png')    #图片保存

    plt.figure('jielun')   #图片显示的名字
    plt.imshow(wc)
    plt.axis('off')        #关闭坐标
    plt.show() 
    

if __name__=='__main__':
    get_comment()
    analyse_sentiment()
    make_cloud()

参考资料:

https://github.com/isnowfy/snownlp

https://www.cnblogs.com/mylovelulu/p/9511369.html

https://blog.csdn.net/oYeZhou/article/details/82868683

https://blog.csdn.net/hzp666/article/details/78969150

https://www.cnblogs.com/derek1184405959/p/9440526.html

免责声明:文章转载自《python系列之(4)豆瓣图书《平凡的世界》书评及情感分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇XAMPP phpmind Agileone 环境搭建及遇到问题的解决方法P4行为模型BMV2安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

任务备忘(已经完成):用python写一个格式化xml字符串的程序

功能: 1.将xml中多余的空格,换行符去掉,让xml字符串变成一行。 2.将xml中添加缩进,使用print能正确打印添加缩进后的字符串。 思路: 采用正则表达式来判断xml中字符串的类型: 1.文件头 2.判断元素的种类:带有属性的标签,没有属性的标签,标签内结束的标签,只含有文本的标签,不含有文本的标签。 3.根据标签的级别添加换行符后面的空格 '...

Python GUI工具Tkinter以及拖拉工具Page安装

如果使用Tkinter作为Python GUI工具,我们需要安装Tkinter,这个使用conda或者pip即可:  conda install -c anaconda tk  为了提高界面编写效率,可以使用拖拉工具Page: 下载地址:https://sourceforge.net/projects/page/ 安装完成后可能会遇到can't find...

第三方库requests详解

Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的一点是它支持 Pytho...

实验1:SDN拓扑实践

实验1:SDN拓扑实践 一、实验目的 能够使用源码安装Mininet; 能够使用Mininet的可视化工具生成拓扑; 能够使用Mininet的命令行生成特定拓扑; 能够使用Mininet交互界面管理SDN拓扑; 能够使用Python脚本构建SDN拓扑。 二、实验环境 下载虚拟机软件Oracle VisualBox 或 VMware; 在虚拟机中安装U...

[Python]IO密集型任务 VS 计算密集型任务

所谓IO密集型任务,是指磁盘IO、网络IO占主要的任务,计算量很小。比如请求网页、读写文件等。当然我们在Python中可以利用sleep达到IO密集型任务的目的。 所谓计算密集型任务,是指CPU计算占主要的任务,CPU一直处于满负荷状态。比如在一个很大的列表中查找元素(当然这不合理),复杂的加减乘除等。 多线程即在一个进程中启动多个线程执行任务。一般来...

python购物车程序

购物车程序主要实现的功能如下      1. 启动程序后,用户通过账号密码登录,然后打印商品列表。 2. 允许用户根据商品编号购买商品。 3. 用户选择商品后,检测余额是否足够,够就直接扣款,不够就提醒充值。 4. 可随时退出,退出时,打印已购买的商品和余额。 插入一张图,这是理想的功能,下面的代码并没有实现这么多功能,需要加上登陆小程序。以后有时间我会实...