一、小說資料的獲取
獲取的資料為起點中文網的小說推薦周榜的所有小說資訊。
原始碼對所有想要獲取的資料都有註釋。
# -*- coding: utf-8 -*-"""
Created on Mon Jan 4 22:59:11 2021
"""import requestsfrom bs4 import BeautifulSoupimport os.pathimport csvimport timeimport pymysqlimport randomclass DrawBookMessage():
def __init__(self):
"""
定義建構函式,初始化最初網址,方便後面呼叫,不必重複寫
"""
self.baseUrl='
#定義baseurl目標網址
def User_Agent(self):
"""
定義5個代理IP隱藏身份,用5個IP隨機選取,以防止被檢測到連結物件而終止訪問
"""
user_agent1 = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0'
user_agent2 = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19'
user_agent3 ='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
#user_agent4 ='Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0'
#這個代理在我的開發環境中會發生訪問錯誤,作者註釋在這裡,便於提醒自己
user_agent5 ='Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3'
lst = [user_agent1,user_agent2,user_agent3,user_agent5]
return random.choice(lst)#返回隨機IP
def getHtml(self,url):
"""
透過隨機IP訪問網頁獲取網頁的內容
"""
user_agent = self.User_Agent()#獲取隨機IP
headers = {"User-Agent":user_agent}
request = requests.get(url,headers=headers).text#透過IP訪問網頁,並且獲取網頁內容請求
return request #返回
def commonsdk(self,url):
"""
把文字型別轉換為<class 'bs4.BeautifulSoup'>型別,
之後還會用BeautifulSoup庫來提取資料,如果這不是一個BeautifulSoup物件,
我們是沒法呼叫相關的屬性和方法的,所以,這是非常重要。
"""
html = self.getHtml(url)
doc=BeautifulSoup(html,'lxml')#轉換為BeautifulSoup物件
return doc
def get_page_size(self,url):
'''獲取頁面總數'''
doc = self.commonsdk(url)
self.pageNum = doc.find("div",class_="pagination fr")['data-pagemax']
return int(self.pageNum)
def draw_base_list(self,url):
'''初級網頁內容'''
doc = self.commonsdk(url)
listt=doc.find('div',class_ = "book-img-text").find_all('div',class_ = 'book-mid-info')
for x in listt:
self.bookName = x.find('h4').text.strip()#書名
self.bookUrl ='https:'+x.find('h4').find('a')['href']#書的二級網址
self.bookAuthor = x.find('p').find(class_='name').text.strip()#
self.bookType = x.find('p').find('a',class_='').text.strip()#小說的型別
self.bookStatus = x.find('p').find('span').text.strip()#小說更新的狀態
self.draw_Second_list()#呼叫獲取二級網頁內容
self.dict_data()#呼叫生成字典的函式
def draw_Second_list(self):
'''獲取二級網頁內容'''
doc = self.commonsdk(self.bookUrl)
listt1 = doc.find('div',class_="book-info")
self.bookIntrodaction = listt1.find(class_="intro").text.strip()#獲取小說簡介
listt2 = doc.find(class_="fans-interact cf")
if listt2.find(class_ ='ticket rec-ticket')==None:#ticket rec-ticket為空,ticket rec-ticket hidde不為空,有月票的標籤
self. monthTickets = listt2.find(class_ ='ticket month-ticket').find(class_ = 'num').text#小說月票
self. weekTickets = listt2.find(class_ ='ticket rec-ticket hidden').find(class_ = 'num').text#小說周票
if listt2.find(class_ ='ticket rec-ticket hidden')==None:#ticket rec-ticket不為空,ticket rec-ticket hidde為空,沒有有月票的標籤
self. monthTickets=0#沒有月票標籤時,月票為0
self. weekTickets = listt2.find(class_ ='ticket rec-ticket').find(class_ = 'num').text #小說周票
self.weekWardNum = listt2.find(class_= 'rewardNum').text#小說本週打賞人數
def dict_data(self):
"""
定義一個人方法生成需要存入資料的字典
"""
ctime = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime());#當前爬取時間
data={
'書名':self.bookName,
'作者':self.bookAuthor,
'型別':self.bookType,
'狀態':self.bookStatus,
'月票':int(self. monthTickets),
'周票':int(self.weekTickets),
'本週打賞人數':int(self.weekWardNum),
'本書簡介':self.bookIntrodaction,
'爬取時間':ctime
}
print(data)
print("="*50)
self.write_to_MySQL(data,"spiders","bookMessage")#寫入資料庫
self.write_to_scv(data,'bookMessage.csv')#寫入.CVS檔案
pass
def write_to_scv(self,dic,filename):
"""寫入csv檔案"""
file_exists = os.path.isfile(filename)#判斷是否為檔案
with open(filename, 'a',encoding='gb18030',newline='') as f: #a表示追加模式不覆蓋原檔案中的內容,newline = "" 表示讀取的換行符保持不變,原來是啥,讀出來還是啥
headers=dic.keys()
w =csv.DictWriter(f,delimiter=',',lineterminator='\n',fieldnames=headers)#建立一個物件
if not file_exists :
w.writeheader()
w.writerow(dic)#單行寫入
print('當前行寫入csv成功!')
pass
def write_to_MySQL(self,dic,database,table_name):
""" 寫入資料庫"""
keys = ', '.join(dic.keys())
values = ', '.join(['% s'] * len(dic))#動態的構造佔位符
db = pymysql.connect(host='localhost', user='root', password=(自己的資料庫密碼), port=3306, db=database)#連線資料庫
cursor = db.cursor()#資料庫連線物件
sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table_name, keys=keys, values=values)#插入語句
try:
if cursor.execute(sql, tuple(dic.values())):
print('Successful')
db.commit()#commit是把查詢語句提交到資料庫內
except:
print('Failed')
db.rollback()
cursor.close()#關閉物件
db.close()#關閉資料庫釋放資源
if __name__ == '__main__':
"""主函式"""
drawBook = DrawBookMessage()
page = drawBook.get_page_size(drawBook.baseUrl)
for x in range(1,page+1):
drawBook.draw_base_list(drawBook.baseUrl+'?page='+str(x))
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
看到這裡不知道是否對你有所幫助?看不懂的可以評論區留言,順便點個贊。嘻嘻嘻嘻嘻嘻!
二、資料的分析與視覺化
相信大家對pandas都有了解吧,我就直入主題——資料分析。
2.1、Python讀取資料表時,有時候會發生一個很頑固的錯誤
在這裡一般性如果表中有中文的話,讀表的時候就會報這個錯誤,這裡把預設編碼改為gbk一般就能解決這個問題。即encoding=‘gbk’。
2.2、檢視錶的統計資訊
(1)describe()檢視錶的相關資訊資訊
data.describe()
# count:數量統計,此列共有多少有效值
#std:標準差
#min:最小值
#25%:四分之一分位數
#50%:二分之一分位數
#75%:四分之三分位數
#max:最大值
#mean:均值123456789
透過這個結果可以得出各票數的情況和打賞的人數。
(2)根據周票數對小說排序
我們透過排序可以篩選出周票數前5的小說
data.sort_values(by = '周票',ascending = False).head(5)1
可以知道當前這5本小說人氣很高。很多人還喜歡看完結的小說,畢竟一次性看完的感覺特別爽。我們也把幾本完結的小說獲取出來
data.loc[data['狀態']=='完本'].sort_values(by = '周票',ascending = False)1
可以得出最近100流行小說中只有2本是完結的。
2.3視覺化圖分析
anhui/
(1)折線圖
對於讀者,都有不同的喜好都市、有的喜好玄幻、有的喜歡輕小說……讓我們看一下最近這些小說各票數綜合情況。透過下面打程式碼可以得出折線圖情況。
import matplotlib.pyplot as pltimport pandas as pdimport numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei'] #解決橫座標不能顯示中文的況plt.rcParams['axes.unicode_minus'] = False#解決橫座標不能顯示中文的情況#三條縱座標的值y1 = data.groupby('型別').sum()['本週打賞人數']#求和y2 = data.groupby('型別').mean()['周票']#求平均值y3 = data.groupby('型別').mean()['月票']#求平均值x=list(dict(y1).keys())#橫座標值fig = plt.figure(figsize=(8,6), dpi=100)#指定畫布大小plt.plot(x,y1,c='red',label='打賞票和')指定折線的顏色和標籤
plt.plot(x,y2,c='green',label='周票均值')plt.plot(x,y3,c='blue',label='月票均值')plt.legend(loc='upper left')#標籤靠左plt.ylabel('周票平局值、月票平局值、打賞票和',fontsize=15)改變定橫座標名稱以及字型大小。
plt.title("小說票數折線圖")#圖名plt.xlabel('小說型別',fontsize=15)plt.show()12345678910111213141516171819
透過折線圖可以直觀的看書流行的趨勢,可以分析到奇幻小說最受歡迎,讀者最多。
(2)柱狀圖
changchun
在這裡插入程式碼片plt.rcParams['figure.figsize']=(8,3)#圖形大小data.groupby(['型別']).mean().plot(kind = 'bar')plt.xticks(rotation=0)#橫座標的角度plt.ylabel('number of people',fontsize = 15)#縱座標名plt.xlabel('Date',fontsize = 15)#橫座標名12345
柱狀圖可以出月票、周票、以及打賞人數沒有很直接的關係。比如奇幻周票高,但是其他兩項的票數卻非常低。
(3)餅狀圖
sizes = []for booktype in x:#x是上文折線圖中橫座標,即小說所有的型別。
bookTypeNum=len(data[data['型別']==booktype])#獲取各種小說的數量
sizes.append(bookTypeNum)plt.figure(figsize=(10,15)) #調節圖形大小plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = Falseplt.pie(
sizes,
labels=x,#指定顯示的標籤
autopct='%1.1f%%'#資料保留固定小數位)#plt.axis('equal')# x,y軸刻度設定一致#本文中可以不用plt.title('小說型別受歡迎的分佈圖比')plt.legend(loc='upper left')# 左上角顯示plt.show()12345678910111213141516
透過餅狀圖可以得出奇幻、都市、仙俠、輕小說幾類小說很受大家追捧。
(4)詞雲圖
import jiebaimport wordcloud
string = ''for i in range(len(x)):
string = str + (x[i])*int(sizes[i])print(string)string=' '.join(string)w = wordcloud.WordCloud(background_color='white',font_path='simfang.ttf')#這裡指明font_path時的字型一定要是自己電腦C:\windows\Fonts下包含有的字型,不然會報錯,或者出現亂碼。w.generate(string)w.to_file(r"bookMessage.png")12345678910
根據詞雲的字的大小可以看出當下最受大家追捧的小說的型別。
(5)散點圖
import matplotlib.pyplot as pltimport numpy as np
plt.rcParams['figure.figsize']=(12,8)np.random.seed(0) #執行多次每次獲取的隨機數都是一樣的colors = np.random.rand(100)size = np.random.rand(20)*1000#隨機大小plt.scatter(a,b,c=colors,s=size,alpha=0.7,marker='*')plt.xlabel('月票數',fontsize = 15)#橫座標名plt.ylabel('周票數',fontsize = 15)#縱座標名plt.title("月票和周票散點圖")plt.show()1234567891011
透過散點圖可以得出大部分小說的月票和周票的數目很少,只有少數的小說月票和周票數目多。往往這些小說就是當下最火的小說。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30239065/viewspace-2748646/,如需轉載,請註明出處,否則將追究法律責任。