JB的Python之旅-每句话背后的情绪值

栏目: Python · 发布时间: 5年前

内容简介:每个人相处都有一套生活方式,跟女人也不一样,不同的女人要用不同的逻辑思考,要琢磨不同语句背后的含义,生活,不容易;对于情场小白而言,最担心的就是女朋友不开心了,毕竟好不容易才从右手变成了实物,肯定是加倍爱惜的;但,你真的了解每一句话的情绪分析吗? 给一句话,能知道这句话的情绪占比吗?

每个人相处都有一套生活方式,跟女人也不一样,不同的女人要用不同的逻辑思考,要琢磨不同语句背后的含义,生活,不容易;

JB的 <a href='https://www.codercto.com/topics/20097.html'>Python</a> 之旅-每句话背后的情绪值

对于情场小白而言,最担心的就是女朋友不开心了,毕竟好不容易才从右手变成了实物,肯定是加倍爱惜的;

但,你真的了解每一句话的情绪分析吗? 给一句话,能知道这句话的情绪占比吗?

情绪分析

情绪分析关键的是 词典 ,网上找了下,大连理工情感词汇本体库比较有名,那就试试看;

下载地址:

链接:https://pan.baidu.com/s/18PeWl-9EjZ7O5Rdfejzgig     
提取码:qc3n 
复制代码

下载完后,看了下说明文档,了解下,词库里面的格式是这样的:

JB的Python之旅-每句话背后的情绪值

看起来好像不错,就试试看~

解压说,发现有这几个文件:

JB的Python之旅-每句话背后的情绪值

简单介绍下2个py文件:

  • evaluate.py,把情感词汇.xlsx转成情感词汇.csv
  • process.py

这里需要注意,使用evaluate.py时,有可能会报 UnicodeEncodeError 这个错;

JB的Python之旅-每句话背后的情绪值

解决也很简单,在原脚本的第11行,指定encoding用 utf-8 即可:

with open('情感词汇.csv', 'w',encoding='utf-8') as out_file:
复制代码

而执行evaluate.py时候,需要import docopy跟pandas两个库,自行安装吧;

pip install docopy

pandas的话,之前听说很多依赖,后来jb安装个anaconda就好了(全家桶);
复制代码

docopt

安装完两个库,因docopy这个库没了解过,因此上官网了解下:

docopt官网上的介绍是:

Command-line interface description language
docopt helps you:
define interface for your command-line app, and
automatically generate parser for it.
复制代码

从中可以看出docopt的两个主要功能:

  • 定义交互参数
  • 解析参数信息

再看下官网的例子:

Naval Fate.

Usage:
  naval_fate ship new <name>...
  naval_fate ship <name> move <x> <y> [--speed=<kn>]
  naval_fate ship shoot <x> <y>
  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
  naval_fate -h | --help
  naval_fate --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.
复制代码

在这个例子中, Naval Fate 是app名称, naval_fate 是命令行命令, shipnewmove 这些是可选的执行命令(commands), xyname 这些是位置参数(positional arguments), -h--help--speed 等这些是选项参数(options);

例子里面用

  • "[]"描述可选元素(optional)
  • "()"描述必要元素(required)
  • "|" 描述互斥元素(mutually exclusive)
  • "..."描述重复元素(repeating)

这些参数,前面加上naval_fate就形成了可用的命令,这些命令在Usage中介绍;

Usage下面的Options里罗列了选项(options)及其描述,它具体描述了

  • 选项是否有长/短形式,如-h, --help
  • 选项后面是否带参数,如--speed=
  • 选项是否有默认值,如[default: 10]

Usage和options里的内容就组成了帮助信息,当用户输入-h或--help参数时,命令行就会输出帮助信息。

docopt会抽取帮助信息里的内容,然后对命令行传入的参数进行解析。

实例

用实例来说明,创建一个test.py文档:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)
复制代码

执行命令:

python test.py ship new jb
复制代码

结果:

{'--drifting': False,
 '--help': False,
 '--moored': False,
 '--speed': '10',
 '--version': False,
 '<name>': ['jb'],
 '<x>': None,
 '<y>': None,
 'mine': False,
 'move': False,
 'new': True,
 'remove': False,
 'set': False,
 'ship': True,
 'shoot': False}
复制代码

然后再尝试一个Usage里没有的命令:

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version
复制代码

小小结

  • docopt( doc )这个函数根据帮助文档的说明解析命令行参数,然后将结果返回为一个字典;
  • 当用户使用不在Usage之内的命令,输出帮助文档;
  • 要使用的时候, from docopt import docopt 调用即可;
  • 必填参数, doc ,其他4个是可选( helpversionargvoptions_first );

evaluate

看回evaluate.py这个文件,顶部有这么一段:

__doc__ = '''
Usage:
    emotion WORD

With Python:
    EmotionDict() --> init
    EmotionDict.evaluate(word) --> tuple(词语(str), 情感分类(str), 强度(int), 极性(int)) or None
'''
复制代码

这里面也专门告诉py怎么用了,那新建个test.py试试:

from 情感词汇.evaluate import EmotionDict

test = EmotionDict()
print(test.evaluate(word="战祸"))
复制代码

直接运行,得到的输出:

('战祸', 'ND', 5, 2)
复制代码

对比了Excel的内容,内容是一样的;

JB的Python之旅-每句话背后的情绪值
  • ND代表憎恶;
  • 强度有1、3、5、7、9,9是最高,5则说明一般;
  • 极性有4类,0代表中性,1代表褒义,2代表贬义,3带边兼有褒贬两性;

其他的,请看 说明.doc ,都有说明;

因此,战祸这个词,用贬义的方式来表达内心的憎恶? 不知道为什么,总感觉怪怪的;

试试一句话

一个词就是上面的用法,那一段话呢?

就需要分词了,中文分词用的最多就是 jieba 库,不了解的同学,请移步此处;

某博直接找来一段话,结合分词,一起看看:

分词

seg_list = jieba.cut("带着立场看比赛注定是痛苦的,倒不如好好品品比赛中每一个精彩的瞬间!",cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))
复制代码

输出:

Default Mode: 带/ 着/ 立场/ 看/ 比赛/ 注定/ 是/ 痛苦/ 的/ ,/ 倒不如/ 好好/ 品品/ 比赛/ 中/ 每/ 一个/ 精彩/ 的/ 瞬间/ !
复制代码

组合

seg_list = jieba.cut("带着立场看比赛注定是痛苦的,倒不如好好品品比赛中每一个精彩的瞬间!",cut_all=False)
test = EmotionDict()
for i in seg_list:
    print(i)
    print(test.evaluate(word=i))
复制代码

输出:

带
None
着
None
立场
None
看
None
比赛
None
注定
None
是
None
痛苦
('痛苦', 'NB', 7, 0)
的
None
,
None
倒不如
None
好好
None
品品
None
比赛
None
中
None
每
None
一个
None
精彩
('精彩', 'PH', 7, 1)
的
None
瞬间
None
!
None
复制代码

标点符号没做过滤,不太影响; 简单看了下,那么多个词,只有 精彩、痛苦 是有返回内容的,也就说明,原来的词库远远不够;

而且要把对应的PH、数字对应起来,还需要单独写一个转换逻辑,还要过滤各种符号,这里面还是有很多小细节做的,到这里,效果实在太差了,主要是, 词库内容太少了,很多词语都没有,压根就没办法判断;

看看别人的

既然不自己造轮子,那就看看别人的吧,这种语境分析,第一时间就想起BAT了,那就一起看看BAT吧;

某度

直接某度搜索 某度自然语言处理 ,直接弹出某度AI开放平台,点击后看下产品服务,选择自然语言处理,就看到有提供 情感倾向分析 ,同时也有 对话情绪识别 两个服务,两者应该是共同原理,就看前者了;

JB的Python之旅-每句话背后的情绪值

点击后,登录,直接点击api文档,翻到情感倾向分析接口;

接口描述

对包含主观观点信息的文本进行情感极性类别(积极、消极、中性)的判断,并给出相应的置信度。

请求说明

请求示例

URL参数

参数
access_token 通过API Key和Secret Key获取的access_token,参考“Access Token获取”

Header如下

参数
Content-Type application/json

Body请求示例

{
    "text": "苹果是一家伟大的公司" 
}
复制代码

请求参数

参数 类型 描述
text string 文本内容(GBK编码),最大2048字节

返回说明

返回参数参数|说明|描述 --|--| log_id|uint64|请求唯一标识码 sentiment|int|表示情感极性分类结果,0:负向,1:中性,2:正向 confidence|float|表示分类的置信度,取值范围[0,1] positive_prob|float|表示属于积极类别的概率 ,取值范围[0,1] negative_prob|float|表示属于消极类别的概率,取值范围[0,1]

返回示例

{
    "text":"苹果是一家伟大的公司",
    "items":[
        {
            "sentiment":2,    //表示情感极性分类结果
            "confidence":0.40, //表示分类的置信度
            "positive_prob":0.73, //表示属于积极类别的概率
            "negative_prob":0.27  //表示属于消极类别的概率
        }
    ]
}
复制代码

Access Token获取

Access Token获取是通过API Key和Secret Key来获取的,那这两个怎么获取?

还记得情感倾向分析的主页吗?有个立即使用的按钮,要去创建应用;

点击创建应用,输入应用名称、描述,然后点击查看应用详情,这里面的API Key 跟Secret Key需要使用到;

JB的Python之旅-每句话背后的情绪值

来到access token获取网址,按照要求试试,官方给的是py2,用py3重弄下,代码如下:

import requests

url = 'https://aip.baidubce.com/oauth/2.0/token'

headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.32 Safari/537.36",
                "Content-Type":"application/json"
}

params = {
    "grant_type":"client_credentials",
    "client_id":你的API Key,
    "client_secret":你的Secret Key

}
response = requests.post(url,headers=headers,params=params)
text = response.json().get("access_token")
print(text)
复制代码

对应的结果就是access_token的值啦;

爽一把

这里遇到个坑,按照官方文档操作,用requests库,无论怎么调,最终都会报下面这个错;

{'log_id': 3838837857684473751, 'error_code': 282004, 'error_msg': 'invalid parameter(s)'}
复制代码

最后网上找了好久,改用urllib库就好了,一脸懵逼。。贴代码:

import json
import urllib

# 获取情绪内容
access_token=你的access_token值
url = 'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?access_token='+access_token

headers={'Content-Type':'application/json'}

post_data = {"text":"带着立场看比赛注定是痛苦的,倒不如好好品品比赛中每一个精彩的瞬间!"}
data=json.dumps(post_data).encode('GBK')

request = urllib.request.Request(url, data)
response = urllib.request.urlopen(request)
content = response.read()
content_str = str(content, encoding="gbk")
print(content_str)
复制代码

输出:

{"log_id": 830621152984506211, "text": "带着立场看比赛注定是痛苦的,倒不如好好品品比赛中每一个精彩的瞬间!", "items": [{"positive_prob": 0.521441, "confidence": 0.571177, "negative_prob": 0.478559, "sentiment": 1}]}
复制代码

根据官网文档,上面4个字段含义如下:

  • sentiment,表示情感极性分类结果,官方没具体说明,猜测是跟上面一样,即0代表中性,1代表褒义,2代表贬义,3带边兼有褒贬两性;
  • confidence,表示分类的置信度;
  • positive_prob,表示属于积极类别的概率
  • negative_prob,表示属于消极类别的概率

按照上面的结果,那这句话应该是属于中性词,偏积极;

某讯

直接找,会发现文智自然语言处理,产品介绍文档在这里,API指南在这里,官方提供demo,py的demo在 这里

download代码,github上说需要安全凭证,点击登录获取;

然后还要安装对应的依赖库,提供2种方式任君选择:

$ pip install qcloudapi-sdk-python

或者下载源码安装
$ git clone https://github.com/QcloudApi/qcloudapi-sdk-python
复制代码

pythonsetup.py install

然后打开tests下的demo.py ,修改模块、接口名、接口参数即可;

#!/usr/bin/python
# -*- coding: utf-8 -*-

# 引入云API入口模块
from QcloudApi.qcloudapi import QcloudApi

'''
module: 设置需要加载的模块
'''
module = 'wenzhi'

'''
action: 对应接口的接口名,请参考wiki文档上对应接口的接口名
'''
action = 'TextSentiment'

'''
config: 云API的公共参数
'''
config = {
    'Region': 'ap-guangzhou',
    'secretId': 'AKIDmmuRdgSV8sjR0eokVh2159Kp2OiyPHPQ',
    'secretKey': 'DNS9h6aBFLYo2BAEBPePI3d3IMGzb7ml',
}

# 接口参数
action_params = {
    "content":"带着立场看比赛注定是痛苦的,倒不如好好品品比赛中每一个精彩的瞬间!"
}

try:
    service = QcloudApi(module, config)
    print(service.generateUrl(action, action_params))
    print(service.call(action, action_params))
except Exception as e:
    import traceback
    print('traceback.format_exc():\n%s' % traceback.format_exc())
复制代码

输出:

b'{"code":0,"message":"","codeDesc":"Success","positive":0.58672362565994,"negative":0.41327640414238}'
复制代码
  • positive,积极
  • negative,负面

对了,某讯没有免费的体验,jb刚好是新人领了个免费礼包,如果不是新手,就要自己充钱的,很X讯;

JB的Python之旅-每句话背后的情绪值

某里

点击这里-情感分析,登录,点击开通,然后来到控制台;

点击基础版,api调试:

JB的Python之旅-每句话背后的情绪值

选择api,这里关于情感分析的,只有电商类的,其他都跟情感没啥关系:

JB的Python之旅-每句话背后的情绪值

按照要求,输入你的access key跟secret,点击调试即可:

JB的Python之旅-每句话背后的情绪值

关于响应的讲解,点击这里,可以看到polarity的参数值,因此,例子是负面的,很合理;

JB的Python之旅-每句话背后的情绪值

剩下的,就是购买了,270起,感兴趣的了解下,使用的话,就到这里了;

阿里提供在线调试,比较方便,但是类型太少了,而且不够详细,结果就是正面、负面、中性3选1,一旦哪天有Bug,就惨了;

定时爬取微博

这个章节不想讲述太多内容,之前思路都有讲过,只是把代码结合下而已,详情请参考下面两篇文章:

上面3个平台的结果很明显,只能用某度,毕竟,免费嘛;

push到微信用的是server酱,直接贴代码:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import re
from json import JSONDecodeError
import time
import requests
from apscheduler.schedulers.blocking import BlockingScheduler
import json
import urllib


wb_url = "https://m.weibo.cn/profile/info?uid=你要关注的微博用户id"
server_url = "http://sc.ftqq.com/你的server酱.send"

# 获取情绪内容
access_token='你的百度access_token值'
bd_url = 'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?access_token='+access_token

wb_headers = {
    "Host": "m.weibo.cn",
    "Referer": "https://m.weibo.cn/u/随便,一般是你要关注的微博用户id",
    "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) "
                  "Version/9.0 Mobile/13B143 Safari/601.1",
}

wb_params = {
    "text": "{text}",
    "desp": "{desp}"
}

statuses_id = ""
scheduler = BlockingScheduler()
page_size = 10


def get_time():
    """
    获取当前时间
    """
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())


def push_wx(text=None, desp=None):
    """
    推送消息到微信
    :param text: 标题
    :param desp: 内容
    :return:
    """
    wb_params['text'] = text
    wb_params['desp'] = desp

    response = requests.get(server_url, params=wb_params)
    json_data = response.json()

    if json_data['errno'] == 0:
        print(get_time() + " 推送成功。")
    else:
        print(json_data)
        print("{0} 推送失败:{1} \n {2}".format(get_time(), json_data['errno'], json_data['errmsg']))


def filter_emoji(text, replace=""):
    """
    过滤Emoji表情
    :param text: 原文
    :param replace: 将Emoji替换为此内容
    :return: 过滤后的内容
    """

    try:
        co = re.compile(u'[\U00010000-\U0010ffff]')
    except re.error:
        co = re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]')
    return co.sub(replace, text)


def get_desp(user, statuse):
    """
    获取微博内容
    """

    global text;
    global nick_name;

    # 个人信息
    avatar = user['profile_image_url']  # 头像
    nick_name = user['screen_name']  # 昵称
    follow_count = user['follow_count']  # 关注
    followers_count = user['followers_count']  # 粉丝
    description = user['description']  # 个性签名

    # 微博信息
    image = ""
    created_at = statuse['created_at']  # 时间
    source = statuse['source']  # 发送微博的设备


    # 微博内容
    if 'raw_text' in statuse:
        print(statuse)
        text = statuse['raw_text']
    else:
        text = statuse['text']

    text = filter_emoji(text, "[emoji]")

    # 获取图片
    if 'pics' in statuse:
        pics = statuse['pics']
        for pic in pics:
            image += "![]({0})\n\n".format(pic['url'])

    return "![]({0})\n\n### {1}\n\n关注:{2} and 粉丝:{3}\n\n签名:{4}\n\n发送时间:{5}\n\n设备:{6}\n\n微博内容:\n\n{7}\n\n{8}" \
        .format(avatar, nick_name, follow_count, followers_count, description, created_at, source, text, image)


def start_task():
    # print("执行查询任务")
    response = requests.get(wb_url, headers=wb_headers)

    try:
        json_data = response.json()
    except JSONDecodeError as e:
        print(get_time() + " Json解析异常, 跳过此次循环:" + str(e))
        return

    state = json_data['ok']

    if state != 1:
        push_wx(get_time() + " 你的女朋友又挂啦,状态码:" + str(state) + ",快去看看吧。", "")
        scheduler.remove_job('wb')
        return

    data = json_data['data']
    user = data['user']
    statuses = data['statuses']

    size = len(statuses)

    if size < page_size:
        print(get_time() + " 返回数据不正确,跳过本次循环。 size:" + str(size))
        return

    first_statuse = statuses[0]
    new_id = first_statuse['id']

    global statuses_id

    if new_id != statuses_id:
        print(get_time() + " 有新微博! id-> " + new_id)

        # 获取微博信息
        desp = get_desp(user, first_statuse)
        title = "女神更新微博啦"

        release_text = SentimentAnalysis()
        push_wx(title, release_text+desp + "\n\n[微博原文](https://m.weibo.cn/profile/2105667905)")

        statuses_id = new_id


def SentimentAnalysis():
    post_data = {"text": text}
    data = json.dumps(post_data).encode('GBK')

    request = urllib.request.Request(bd_url, data)
    response = urllib.request.urlopen(request)
    content = response.read()
    content_str = str(content, encoding="gbk")
    data = json.loads(content_str)

    # 积极、消极、可信度的概率
    positive_prob = '%.2f%%' % (data["items"][0]["positive_prob"] * 100)
    negative_prob = '%.2f%%' % (data["items"][0]["negative_prob"] * 100)
    confidence = '%.2f%%' % (data["items"][0]["confidence"] * 100)
    sentiment = data["items"][0]["sentiment"]

    if (positive_prob > negative_prob):
        prob = positive_prob

    elif (positive_prob < negative_prob):
        prob = negative_prob
    else:
        prob = positive_prob

    if (sentiment == 0 ):
        prob_text = "负面"
    elif (sentiment == 1 ):
        prob_text = "中性"
    elif (sentiment == 2):
        prob_text = "正向"


    analysis_text = "你女神博主:"+nick_name + ",发布了情绪值为"+prob+",疑似是"+prob_text+"情绪的微博,快来看看吧,可信度:"+confidence+",微博原文是:"+text
    return analysis_text


if __name__ == '__main__':
    print(get_time() + " 骚年,噩梦来袭!")
    scheduler.add_job(start_task, "interval", seconds=6, id="wb")
    scheduler.start()
复制代码

代码不能直接用,要手动输入几个值,微博用户id、某度access_token、server酱,完;

效果图

JB的Python之旅-每句话背后的情绪值
百分号 %

不知道为什么被过滤了,正常是XX%这样的格式,但是看着懂就好了,不纠结;

通过上面的推送信息,信息最大化,也得出对应的情绪值,但是,女人说的话,要视不同场景而决定其含义;

比如吵架时的分手,其实就是要你哄,要你抱;
比如成家后的不要,是不舍得,偷偷买吧;
复制代码

而这种含义,不结合语境是没法判断的;

而女人的心思,别猜,买/哄/舔就对了;

对了,前提是得有个男/女朋友,不然,还是买点护肤品慰劳下自己的右手吧;

小结

本文主要介绍了情绪分析的内容,有手动统计,也有利用BAT平台的接口,出了某度有免费接口提供外,其他都要收费,而且不低,用来调试或者内部用用,用某度的挺好的,量多可能会收费,但没找到具体文档,不纠结了;

同时学习了Py的docopt模块,会抽取帮助信息里的内容,然后对命令行传入的参数进行解析;

而在试用BAT平台时,会发现调用接口都需要安全凭证/授权校验,目的还是为了安全性,这块是值得学习的,回想下,内部接口是否无需校验就可直接调用?是否会被第三方利用的可能?

最好,祝有女朋友的,幸福美满,避开所有障碍,早日拉埋天窗; 没女朋友的,学会聊天,保持自信,别太死板,最重要是有上进心,阳光活力,换位思考,如果你是女生,你会喜欢自己吗?

最后,谢谢大家!

JB的Python之旅-每句话背后的情绪值

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails 4

Agile Web Development with Rails 4

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2013-10-11 / USD 43.95

Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details. Tens of thousands of deve......一起来看看 《Agile Web Development with Rails 4》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具