python爬取三國演義文本,統計三國演義中出場次數前30的人物,並生成詞雲、圖表

1.目標

python爬取三國演義,生成詞雲、圖表

2.碼前須知

項目目標:三國人物名稱及出現次數-----數據統計分析
提出問題:哪個人物在三國演義中出現的次數最多?,我們希望通過數據分析來獲得答案。
分析工具:pandas,Matplotlib
pip install bs4
pip install lxml
pip install pandas
pip install Matplotlib

bs4數據解析必備知識點:標籤定位,提取標籤中的數據值
1.實例化一個BeautifulSoup對象,並將頁面源碼數據加載到該對象中,lxml是解析器,固定的參數,下面是舉例
#本地html加載到該對象:
fp = open(’./test.html’,‘r’,encoding=‘utf-8’)
soup = BeautifulSoup(fp,‘lxml’)
print(soup)
#互聯網上獲取的源碼數據(常用)
page_text = response.text
soup = BeautifulSoup(page_text,‘lxml’)
2.通過調用BeautifulSoup對象中相關的屬性或者方法對標籤進行定位和提取
bs4具體屬性的用法
1.標籤 ,如< p > < a >< div >等等
soup.tagName
例如
soup.a #返回的是html第一次出現的tagName的a標籤
soup.div #返回的是html第一次出現的tagName的div標籤

2.查找
soup.find(‘div’) 用法相當於soup.div
屬性定位, < div class=‘song’ >
soup.find(‘div’,class_=‘song’) class_需要帶下劃線
class_/id/attr

3.所有符合條件的標籤
soup.find_all(‘a’) #返回符合所有的a標籤,也可以屬性定位

4.select放置選擇器 類選擇器. .代表的就是tang
soup.select(’.tang’)
soup.select(‘某種選擇器(id,class,標籤,選擇器)’)
返回的是一個列表
定位到標籤下面的標籤 >表示標籤一個層級選擇器
soup.select(’.tang > ul >li >a’[0])
空格表示多級選擇器
soup.select(‘tang’ > ul a’[0]) 與上述的表達式相同

常用層級選擇器
5.獲取標籤中間的文本數據
soup.a.text/string/get_text()
區別
text/get_text():可以獲取某一個標籤中所有的文本內容,即使不是直系的文本
string:只可以獲取直系文本

6.獲取標籤中的屬性值
soup.a[‘href’] 相當於列表操作

3.操作流程

1.爬取數據來源: 古詩詞網《三國演義》
2.編碼流程:

  • 指定URL–http://www.shicimingju.com/book/sanguoyanyi.html
  • 發起請求–requests
  • 獲取響應數據—頁面信息
  • 數據解析(通過bs4) --1進行指定標籤的定位;2取得標籤當中的文本內容
  • 持久化存儲–保存文件

2.文本詞頻統計:中文分詞庫–jieba庫,具體的解釋已在代碼處聲明
3.生成詞雲:wordcloud,具體的解釋已在代碼處聲明
4.生成柱狀分析圖:matplotlib,具體的解釋已在代碼處聲明

–url首頁
在這裏插入圖片描述

–我們要的是這個目錄的標題和點擊後的頁面內容
在這裏插入圖片描述

點擊後的頁面,發現規律
在這裏插入圖片描述

詳細頁面要獲取的內容
在這裏插入圖片描述

4.完整代碼

from bs4 import BeautifulSoup
import requests
import jieba#優秀的中文分詞第三方庫
import wordcloud
import pandas as pd 
from matplotlib import pyplot as plt

#1.對首頁html進行爬取
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
headers={
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
fp = open('./sanguo.txt','w',encoding='utf-8')
page_text = requests.get(url=url,headers=headers).text

#2.數據解析
#實例化對象
soup = BeautifulSoup(page_text,'lxml')
#獲得li標籤
li_list = soup.select('.book-mulu > ul > li')
#取得li標籤裏的屬性
for li in li_list:
    #通過bs4的方法直接獲取a標籤直系文本
    title = li.a.string
    #對url進行拼接得到詳情頁的url
    detail_url = 'http://www.shicimingju.com'+li.a['href']
    #對詳情頁發起請求
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    #解析詳情頁的標籤內容,重新實例化一個詳情頁bs對象,lxml解析器
    detail_soup = BeautifulSoup(detail_page_text,'lxml')
    #屬性定位
    div_tag = detail_soup.find('div',class_='chapter_content')
    #解析到了章節的內容,利用text方法獲取
    content = div_tag.text
    #持久化存儲
    fp.write(title+':'+content+'\n')
    print(title,'爬取成功!!!')
print('爬取文本成功,進行下一步,jieba分詞,並生成一個sanguo.xlsx文件用於數據分析')


#排除一些不是人名,但是出現次數比較靠前的單詞
excludes = {"將軍","卻說","荊州","二人","不可","不能","如此","商議","如何","主公","軍士", "左右","軍馬","引兵","次日","大喜","天下","東吳","於是","今日","不敢","魏兵", "陛下","一人","都督","人馬","不知","漢中","只見","衆將","後主","蜀兵","上馬",  "大叫","太守","此人","夫人","先主","後人","背後","城中","天子","一面","何不", "大軍","忽報","先生","百姓","何故","然後","先鋒","不如","趕來","原來","令人", "江東","下馬","喊聲","正是","徐州","忽然","因此","成都","不見","未知","大敗", "大事","之後","一軍","引軍","起兵","軍中","接應","進兵","大驚","可以","以爲", "大怒","不得","心中","下文","一聲","追趕","糧草","曹兵","一齊","分解","回報", "分付","只得","出馬","三千","大將","許都","隨後","報知","前面","之兵","且說",  "衆官","洛陽","領兵","何人","星夜","精兵","城上","之計","不肯","相見","其言", "一日","而行","文武","襄陽","準備","若何","出戰","親自","必有","此事","軍師", "之中","伏兵","祁山","乘勢","忽見","大笑","樊城","兄弟","首級","立於","西川","朝廷","三軍","大王","傳令","當先","五百","一彪","堅守","此時","之間","投降","五千","埋伏","長安","三路","遣使","英雄"}
#打開爬取下來的文件,並設置編碼格式
txt = open("sanguo.txt", "r", encoding='utf-8').read()
#精確模式,把文本精確的切分開,不存在冗餘單詞,返回列表類型
words  = jieba.lcut(txt)
#構造一個字典,來表達單詞和出現頻率的對應關係
counts = {}
#逐一從words中取出每一個元素
for word in words:
    #已經有這個鍵的話就把相應的值加1,沒有的話就取值爲0,再加1
    if len(word) == 1:
        continue
    elif word == "諸葛亮" or word == "孔明曰":
        rword = "孔明"
    elif word == "關公" or word == "雲長":
        rword = "關羽"
    elif word == "玄德" or word == "玄德曰":
        rword = "劉備"
    elif word == "孟德" or word == "丞相":
        rword = "曹操"
    else:
        rword = word
    #如果在裏面返回他的次數,如果不在則添加到字典裏面並加一
    counts[rword] = counts.get(rword,0) + 1
#刪除停用詞
for word in excludes:
    del counts[word]
#排序,變成list類型,並使用sort方法
items = list(counts.items())
#對一個列表按照鍵值對的2個元素的第二個元素進行排序
#Ture從大到小,結果保存在items中,第一個元素就是出現次數最多的元素
items.sort(key=lambda x:x[1], reverse=True) 
#將前十個單詞以及出現的次數打印出來
name=[]
times=[]
for i in range(30):
    word, count = items[i]
    print ("{0:<10}{1:>5}".format(word, count))
    name.append(word)
    times.append(count)
    
print(name)
print(times)

#創建索引
id=[]
for i in range(1,31):
    id.append(i)
#數據幀,相當於Excel中的一個工作表
df = pd.DataFrame({
    'id':id,
    'name':name,
    'times':times,
})
#自定義索引,不然pandas會使用默認的索引,這會導致生成的工作表
#也會存在這些索引,默認從0開始
df = df.set_index('id')
print(df)
df.to_excel('sanguo.xlsx')
print("DONE!")
print('生成文件成功,進行下一步,生成詞雲')

#詞雲部分
w=wordcloud.WordCloud(
               font_path="C:\\Windows\\Fonts\\simhei.ttf", #設置字體
               background_color="white",  #設置詞雲背景顏色
               max_words=1000,  #詞雲允許最大詞彙數
               max_font_size=100,   #最大字體大小
               random_state=50  #配色方案的種數
               )
txt=" ".join(name)
w.generate(txt)
w.to_file("ciyun.png")
print("done!")
print("詞雲生成並保存成功!!!,進行下一步生成柱狀圖")


dirpath = 'sanguo.xlsx'
data = pd.read_excel(dirpath,index_col='id',sheet_name='Sheet1')#指定id列爲索引
#print(data.head())#到此數據正常
print('OK!,到此數據正常')


#柱狀圖部分
#直接使用plt.bar() 繪製柱狀圖,顏色紫羅蘭
plt.bar(data.name,data.times,color="#87CEFA")
#添加中文字體支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
#設置標題,x軸,y軸,fontsize設置字號
plt.title('三國人物名字前三十名出現的次數',fontsize=16)
plt.xlabel('人名')
plt.ylabel('統計次數')
#因爲X軸字體太長,利用rotation將其旋轉90度
plt.xticks(data.name,rotation='90')
#緊湊型佈局,x軸太長爲了顯示全
plt.tight_layout()


imgname = 'sanguo.jpg'#設置圖片保存的位置
plt.savefig(imgname)#保存圖片
plt.show()
print('柱狀圖生成完畢!!!')
print('所有程序執行完成')

在這裏插入圖片描述
在這裏插入圖片描述

5.總結

儘管我們說《三國演義》對漢室、對劉備有很明顯的傾向性,但人物出場最多的還是曹操,這個結果會不會讓你們驚訝呢?
缺點:其實人物排序也不準,比如都督,如果指周瑜的話,周瑜的排名可能會再靠前

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章