JB的Python之旅-每句話背後的情緒值

前言

每一個人相處都有一套生活方式,跟女人也不同,不一樣的女人要用不一樣的邏輯思考,要琢磨不一樣語句背後的含義,生活,不容易; html

image.png-47.7kB

對於情場小白而言,最擔憂的就是女友不開心了,畢竟好不容易纔從右手變成了實物,確定是加倍愛惜的;python

但,你真的瞭解每一句話的情緒分析嗎? 給一句話,能知道這句話的情緒佔比嗎?git

情緒分析

情緒分析關鍵的是詞典,網上找了下,大連理工情感詞彙本體庫比較有名,那就試試看;github

下載地址:json

連接:https://pan.baidu.com/s/18PeWl-9EjZ7O5Rdfejzgig     
提取碼:qc3n 
複製代碼

下載完後,看了下說明文檔,瞭解下,詞庫裏面的格式是這樣的: api

image.png-13.4kB

看起來好像不錯,就試試看~安全

解壓說,發現有這幾個文件: bash

image.png-40.2kB

簡單介紹下2個py文件:微信

這裏須要注意,使用evaluate.py時,有可能會報UnicodeEncodeError這個錯; app

image.png-18.6kB

解決也很簡單,在原腳本的第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的內容,內容是同樣的;

image.png-48.8kBimage.png-48.8kB

  • ND表明憎惡;
  • 強度有一、三、五、七、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開放平臺,點擊後看下產品服務,選擇天然語言處理,就看到有提供情感傾向分析,同時也有對話情緒識別兩個服務,二者應該是共同原理,就看前者了;

image.png-198.1kB

點擊後,登陸,直接點擊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須要使用到;

image.png-27.3kB

來到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
複製代碼

cd qcloudapi-sdk-python python setup.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訊;

image.png-24kB

某裏

點擊這裏-情感分析,登陸,點擊開通,而後來到控制檯;

點擊基礎版,api調試:

image.png-20.4kB

選擇api,這裏關於情感分析的,只有電商類的,其餘都跟情感沒啥關係:

image.png-52.6kB

按照要求,輸入你的access key跟secret,點擊調試便可:

image.png-44.8kB

關於響應的講解,點擊這裏,能夠看到polarity的參數值,所以,例子是負面的,很合理;

image.png-22.1kB

剩下的,就是購買了,270起,感興趣的瞭解下,使用的話,就到這裏了;

阿里提供在線調試,比較方便,可是類型太少了,並且不夠詳細,結果就是正面、負面、中性3選1,一旦哪天有Bug,就慘了;

定時爬取微博

這個章節不想講述太多內容,以前思路都有講過,只是把代碼結合下而已,詳情請參考下面兩篇文章:

JB的Python之旅-豆瓣自動頂貼功能
JB的Python之旅-爬蟲篇-新浪微博內容爬取

上面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醬,完;

效果圖

image.png-25.5kB
百分號 %不知道爲何被過濾了,正常是XX%這樣的格式,可是看着懂就行了,不糾結;

經過上面的推送信息,信息最大化,也得出對應的情緒值,可是,女人說的話,要視不一樣場景而決定其含義;

好比吵架時的分手,其實就是要你哄,要你抱;
好比成家後的不要,是不捨得,偷偷買吧;
複製代碼

而這種含義,不結合語境是無法判斷的;

而女人的心思,別猜,買/哄/舔就對了;

對了,前提是得有個男/女友,否則,仍是買點護膚品慰勞下本身的右手吧;

小結

本文主要介紹了情緒分析的內容,有手動統計,也有利用BAT平臺的接口,出了某度有免費接口提供外,其餘都要收費,並且不低,用來調試或者內部用用,用某度的挺好的,量多可能會收費,但沒找到具體文檔,不糾結了;

同時學習了Py的docopt模塊,會抽取幫助信息裏的內容,而後對命令行傳入的參數進行解析;

而在試用BAT平臺時,會發現調用接口都須要安全憑證/受權校驗,目的仍是爲了安全性,這塊是值得學習的,回想下,內部接口是否無需校驗就可直接調用?是否會被第三方利用的可能?

最好,祝有女友的,幸福美滿,避開全部障礙,早日拉埋天窗; 沒女友的,學會聊天,保持自信,別太死板,最重要是有上進心,陽光活力,換位思考,若是你是女生,你會喜歡本身嗎?

最後,謝謝你們!

1-140R3154U8.jpg-9kB
相關文章
相關標籤/搜索