晉江文學城爬取小說評論情感分析
- 1. 收集資料
- 1.1 爬取晉江文學城收藏排行榜前50頁的小說資訊
- 2. 資料加載和預處理
- 2.1 格式轉化
- 2.2 資料去重
- 2.3 短評去重
- 2.4 添加情緒標簽
- 2.5 去除停用詞和分詞
- 2.6 短評可視化
- 3. 訓練模型
- 3.1 建立訓練資料集和測驗資料集
- 3.2 使用 sklearn 包中的 TfidfVectorizer 方法進行特征提取,
- 3.3 用樸素貝葉斯完成中文文本分類器
- 3.4 用邏輯回歸完成中文文本分類
- 4. 結果分析
1. 收集資料
1.1 爬取晉江文學城收藏排行榜前50頁的小說資訊
獲取收藏榜前50頁的小說串列,第一頁網址為 ‘http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&xx2=2&mainview0=0&sd0=0&lx0=0&fg0=0&sortType=0&isfinish=0&collectiontypes=ors&searchkeywords=&page=1’ , 第二頁網址中page=2,以此類推,直到第50頁中page=50,爬取每個小說的ID,小說名字,小說作者,將爬取到的資訊存盤到晉江排行榜【按收藏數】.txt檔案中,
import requests
from bs4 import BeautifulSoup
import bs4
import re
import csv
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import jieba
import seaborn as sns
import xlrd
from xlutils.copy import copy
# 一些魔法命令,使得matplotlib畫圖時嵌入單元中而不是新開一個視窗
%matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
%load_ext autoreload
%autoreload 2
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
from sklearn.model_selection import train_test_split
- 爬取小說基本資訊 ,主要思路:
- 找到需要爬取的所有資訊主體tbody;
- 分別找到每個資訊對應的小標簽td(a),數清楚在所有標簽中的順序;
- 存進txt檔案時按順序存盤,
headers = {"User-Agent": "Mozilla/5.0"}
for n in range(1,50):
url = 'http://www.jjwxc.net/bookbase.php?fw0=0&fbsj=0&ycx0=0&xx2=2&mainview0=0&sd0=0&lx0=0&fg0=0&sortType=0&isfinish=0&collectiontypes=ors&searchkeywords=&page={}'.format(n)
html = requests.get(url,headers=headers)
html.encoding = html.apparent_encoding
soup = BeautifulSoup(html.text, 'html.parser')
for tr in soup.find_all('tbody'):
tds=tr('td')
a = tr('a')
count=0
id=[]
for u in tr.find_all('a'):
count=count+1
book_url=u.get('href') # 獲取小說主頁的url
p = re.compile(r'\d+')
book_id = p.findall(book_url)[0] # 獲取小說ID
if(count%2==0):
id.append(book_id)
for n in range(0,100):
with open('./data/晉江排行榜【按收藏數】.txt','a+',encoding='utf-8') as f:
print("{0}\t{1}\t{2}".format(id[n],a[n*2+1].string,a[n*2].string),file=f) # 序號 書名 作者
- 查看爬蟲結果 ,分別查看前8部小說的ID和名字
# 查看收藏榜前8部小說的ID
with open('./data/晉江排行榜【按收藏數】.txt','r',encoding='utf-8',errors='ignore') as f:
book_list = f.readlines()
id_list = [item.split('\t')[0] for item in book_list]
print(id_list[:8])
# 查看收藏榜前8部小說的名字
name_list = [item.split('\t')[1] for item in book_list]
print(name_list[:8])

3. ** 爬取每部小說的評論** ,找到小說的評論區,第一部小說《天官賜福》的第一頁評論網址為 ‘http://www.jjwxc.net/comment.php?novelid=3200611&huati=1’ ,3200611是小說ID,1是評論頁數,這部小說第二頁網址為’http://www.jjwxc.net/comment.php?novelid=3200611&huati=2’ ,下一部小說《撒野》的ID是2956313,它的第一頁評論網址為’http://www.jjwxc.net/comment.php?novelid=2956313&huati=1’ ,以此類推,爬取所有小說的評論和打分,為了避免有一些小說評論數不夠多,自己設定每部小說只爬取5頁的評論,
爬取思路與爬取小說資訊大致相同,不同的是將爬取到的資訊存盤到xls檔案中,
headers = {"User-Agent": "Mozilla/5.0"}
with open('./data/晉江排行榜【按收藏數】.txt','r',encoding='utf-8') as f:
book_list = f.readlines()
id_list = [item.split('\t')[0] for item in book_list]
for book_id in id_list:
for page in range(1,6):
url="http://www.jjwxc.net/comment.php?novelid={}&huati=1&page={}".format(book_id,page)
html = requests.get(url,headers=headers)
html.encoding = html.apparent_encoding
soup = BeautifulSoup(html.text, 'html.parser')
scores=[]
comments=[]
for item1 in soup.find_all('span',"coltext"):
score=item1('span')
scores.append(score[2].string)
for item2 in soup.find_all('div',"readbody"):
comment=item2('span')
comments.append(comment[0].string)
for i in range(0,len(comments)):
excel = xlrd.open_workbook('./data/jjwxc1.xls')
wb = copy(excel)
w_sheet = wb.get_sheet(0)
sheet = excel.sheets()[0]
nrow = sheet.nrows # 檔案行數
w_sheet.write(nrow, 0, book_id)
w_sheet.write(nrow, 1, comments[i])
w_sheet.write(nrow, 2, scores[i])
wb.save('./data/jjwxc1.xls')
2. 資料加載和預處理
預處理包括:
- 格式轉化;上一步將爬取資訊存到了xls檔案,將xls格式檔案轉化為csv格式檔案方便下一步加載,
- 資料去重;爬取程序中某些頁面爬取了多次,導致csv檔案包含重復的行,
- 短評去重;對同一部小說,或者不同的小說,可能存在評論內容相同的行,
- 添加情緒標簽
- 去除停用詞和分詞
- 短評可視化
2.1 格式轉化
使用pandas模塊可以快速將xls檔案轉換為.csv
# 格式轉化
ex=pd.read_excel("./data/jjwxc.xls")
ex.to_csv("./data/jjwxc.csv",encoding="gb18030")
# 加載評論
review = pd.read_csv("./data/jjwxc.csv",names=['ID','comment','score'],encoding='gb18030')
2.2 資料去重
去除重復的行
# 去重
review = review.drop_duplicates()
2.3 短評去重
去除評論相同的行
# 洗掉評論內容重復的行
review= review.drop_duplicates('comment')
review.shape
2.4 添加情緒標簽
根據打分的分數來添加情緒標簽,觀察晉江文學城的打分機制發現,打磁區間在[-2,2]內,且打2分的人數占大多數,于是將分數為2的評論看作是好評,情緒標簽為1,而低于2分的看作是差評,情緒標簽為0,
# 添加情緒標簽
review['emotion'] = (review.score ==2) * 1
# 打亂順序
review = review.sample(frac=1).reset_index(drop=True)
print(review.shape)
2.5 去除停用詞和分詞
短評內容進行分詞并去掉停用詞
def review_without_stop(review):
# 打開停用詞檔案
with open("./data/emotion_stopwords.txt","r",encoding="utf-8") as f:
stop_word = [x.strip() for x in f.readlines()]
all_stop_words = set(stop_word) # 洗掉停用詞中重復的項
# 短評中的非中文字符替換為''
review = re.sub("[^\u4e00-\u9fa5]",'',review)
# 去除全角空白字符
review = review.replace("\u3000","")
# 分詞
review = jieba.cut(review)
# 過濾一個字的詞
review = filter(lambda x: len(x)>1,review)
# 去除停用詞
review = filter(lambda x: x not in all_stop_words,review)
return ' '.join(review)
# 自定義分詞字典
jieba.load_userdict("./data/emotion_userdict.txt")
review['cut_jieba'] = review.comment.apply(review_without_stop)
【注】停用詞和分詞檔案需要自己定義
# 查看一些評論
review.head()

# 好評中一些評論包含“不想”,“不喜歡”
review[(review['cut_jieba'] == '不想') & (review['emotion'] == 1)]
review[(review['cut_jieba'] == '不喜歡') & (review['emotion'] == 1)]
# 好評中出現的消極情緒詞,去除這些評論
def change_negtive_like(cut_text):
word_list = cut_text.split()
if "不喜歡" in word_list:
for i in range(len(word_list)):
if word_list[i] == "不喜歡":
word_list[i] = ""
return " ".join(word_list)
elif "不想" in word_list:
for i in range(len(word_list)):
if word_list[i] == "不想":
word_list[i] = ""
return " ".join(word_list)
else:
return cut_text
review.loc[review['emotion'] == 1,'cut_jieba'] = review[review['emotion'] == 1].cut_jieba.apply(change_negtive_like)
# 一些評論內容為空,去除這些為空的評論
review = review[~(review['cut_jieba'] == '')]
review.shape
2.6 短評可視化
- 對所有短評進行可視化
from wordcloud import WordCloud
from imageio import imread
mask = imread("./data/cloud.jpg")
font = './data/FZSTK.TTF'
wc = WordCloud(
font_path= font,
max_words=2000, # 設定最大現實的字數
max_font_size=250,# 設定字體最大值
background_color = "white",
random_state=30,
mask = mask)
wc.generate(''.join(review['cut_jieba'])) # 生成詞云
plt.imshow(wc)
plt.axis('off')

2. 對emotion為1的短評進行可視化
from wordcloud import WordCloud
from imageio import imread
mask = imread("./data/piggy.jpg")
font = './data/FZSTK.TTF'
wc1 = WordCloud(
font_path= font,
max_words=2000, # 設定最大現實的字數
max_font_size=300,# 設定字體最大值
background_color = "white",
random_state=30,
mask = mask)
wc1.generate(''.join(review['cut_jieba'][review['emotion']==1]))
plt.imshow(wc1)
plt.axis('off')

3. 對score為-2的短評進行可視化
wc1.generate(''.join(review['cut_jieba'][review['score']==-2])) # 生成詞云
plt.imshow(wc1)
plt.axis('off')

【注】詞云和字體自己定義
3. 訓練模型
3.1 建立訓練資料集和測驗資料集
由于已經為分析準備好了資料,所以現在需要將資料分成訓練資料集和測驗資料集,將資料分成兩部分:75%的訓練資料和25%的測驗資料,
x, y = review['cut_jieba'], review['emotion']
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.25)
print(x_train.shape)
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)
3.2 使用 sklearn 包中的 TfidfVectorizer 方法進行特征提取,
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vect = TfidfVectorizer(decode_error='ignore',
token_pattern=r"\b[^\d\W]\w+\b", # 剔除向量化結果中的數字
analyzer='word',
ngram_range=(2,4),
max_df = 0.8,
min_df = 3)
Xtrain = tfidf_vect.fit_transform(x_train)
Xtest = tfidf_vect.transform(x_test)
print(Xtrain.shape)
print(Xtest.shape)
3.3 用樸素貝葉斯完成中文文本分類器
from sklearn.naive_bayes import MultinomialNB
review_classifier = MultinomialNB()
review_classifier.fit(Xtrain,y_train)
# 對測驗集的樣本進行預測
y_pred = review_classifier.predict(Xtest)
metrics.confusion_matrix(y_test, y_pred) # 混淆矩陣
# 利用 sns 模塊查看測驗值和預測值構成的熱圖
colorMetrics = metrics.confusion_matrix(y_test, y_pred)
sns.heatmap(colorMetrics,annot=True,fmt='d')

# 分類報告
# 給出每個類的準確率,召回率和F值,以及這三個引數和宏平均值
print(metrics.classification_report(y_test,y_pred))

print(metrics.accuracy_score(y_test,y_pred))
from sklearn.model_selection import cross_val_score
score1 = cross_val_score(review_classifier,Xtrain,y_train,cv=10,scoring="accuracy").mean()
print(score1)
3.4 用邏輯回歸完成中文文本分類
from sklearn.linear_model import LogisticRegression
LR_model = LogisticRegression(penalty='l2',max_iter=3000)
LR_model.fit(Xtrain,y_train)
# 對測驗集的樣本進行預測
y_pred = LR_model.predict(Xtest)
metrics.confusion_matrix(y_test, y_pred) # 混淆矩陣
print(LR_model.score(Xtest,y_test))
# 給出每個類的準確率,召回率和F值,以及這三個引數和宏平均值
print(metrics.classification_report(y_test,y_pred))
4. 結果分析
(1)詞云分析:
- 詞云1中最明顯的詞匯是“喜歡”;
- 詞云2中的詞匯與詞云1區別不大,因為所有短評中好評占大多數;
- 由差評生成的詞云3出現了“不好”、“一般”、“硬傷”等負面色彩的詞語,
(2)影響情感分析準確性的原因:
- 獲取到的短評數量比較少;
- 由于小說中對主角討論比較多,一些小說角色名字會重復出現在短評內,一定程度影響對評論的感情分析;
- 沒有洗掉過于短小的評論;
- 分詞后中發現代表積極或消極情緒的詞匯往往不會成為單獨短評,而是和別的詞一起出現,對于查找差評中的積極詞匯和好評中的消極詞匯造成一定困難,
- 短評中出現明顯代表正面色彩和負面色彩的詞匯較少,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/277676.html
標籤:python
