本篇文章給大家分享的是有關(guān)Python如何一鍵爬取你所關(guān)心的書(shū)籍信息,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
成都創(chuàng)新互聯(lián)公司一直通過(guò)網(wǎng)站建設(shè)和網(wǎng)站營(yíng)銷(xiāo)幫助企業(yè)獲得更多客戶資源。 以"深度挖掘,量身打造,注重實(shí)效"的一站式服務(wù),以成都網(wǎng)站建設(shè)、網(wǎng)站制作、移動(dòng)互聯(lián)產(chǎn)品、營(yíng)銷(xiāo)型網(wǎng)站服務(wù)為核心業(yè)務(wù)。十多年網(wǎng)站制作的經(jīng)驗(yàn),使用新網(wǎng)站建設(shè)技術(shù),全新開(kāi)發(fā)出的標(biāo)準(zhǔn)網(wǎng)站,不但價(jià)格便宜而且實(shí)用、靈活,特別適合中小公司網(wǎng)站制作。網(wǎng)站管理系統(tǒng)簡(jiǎn)單易用,維護(hù)方便,您可以完全操作網(wǎng)站資料,是中小公司快速網(wǎng)站建設(shè)的選擇。
平時(shí)看到的豆瓣爬蟲(chóng)基本都是爬豆瓣top100電影、某電影熱評(píng)、top100圖書(shū)、熱門(mén)圖書(shū)等,最近遇到的一個(gè)需求是根據(jù)一堆書(shū)名的列表(或者書(shū)名Excel文件)爬取對(duì)應(yīng)的書(shū)目信息,也就是豆瓣圖書(shū)頁(yè)面上的出版社、出版時(shí)間、ISBN、定價(jià)、評(píng)分、評(píng)分人數(shù)等信息,再整合到pandas里進(jìn)行處理,最后可以進(jìn)行數(shù)據(jù)分析。
最近整理書(shū)目的時(shí)候需要根據(jù)幾百本書(shū)的書(shū)名整理出對(duì)應(yīng)的出版社、出版時(shí)間、ISBN、評(píng)分等屬性,書(shū)單Excel如下圖1中的表。批量處理肯定是用爬蟲(chóng)啦,查了一下沒(méi)有發(fā)現(xiàn)相似的文章,并且自己操作時(shí)也遇到了比較有趣的問(wèn)題,于是把自己的操作思路和過(guò)程整理成本文。
圖1,書(shū)單數(shù)據(jù)部分截圖
頁(yè)面分析
首先分析豆瓣圖書(shū)首頁(yè):book.douban.com,直接搜索書(shū)名時(shí)可以看到搜索參數(shù)是寫(xiě)在url上的,于是想著直接用https://book.douban.com/subject_search?search_text={0}&cat=1001'.format('書(shū)名')
,直接改search_text參數(shù),在這個(gè)頁(yè)面按F12調(diào)出控制臺(tái),失望的是這個(gè)url返回的html是不含數(shù)據(jù)的,如圖2。關(guān)鍵是找了一段時(shí)間還是沒(méi)找到異步返回的數(shù)據(jù)json(如果有人找到了豆瓣subject_search?search_text={0}&cat=1001這類(lèi)頁(yè)面的書(shū)籍?dāng)?shù)據(jù)的位置歡迎告訴我呀),這時(shí)候考慮用Selenium或者查其他接口。
圖2,基于搜索url的html截圖
json分析
注意到豆瓣圖書(shū)的搜索頁(yè)面有一個(gè)搜索提示,于是在控制臺(tái)查Network發(fā)現(xiàn)搜索提示返回的直接是一個(gè)json,例如查“未來(lái)簡(jiǎn)史”,結(jié)果如下:
圖3,未來(lái)簡(jiǎn)史搜索提示
返回json可以用的屬性有:title:書(shū)名、url:對(duì)應(yīng)書(shū)的豆瓣頁(yè)面、pic:書(shū)封面圖資源位置等。如果上面的輸入咱們只有書(shū)名,就根據(jù)書(shū)名和返回的json對(duì)應(yīng),如果有作者、出版年份等屬性,就可以更好的核對(duì)是否是我們要找的書(shū),為了簡(jiǎn)化,下面只用了返回json數(shù)據(jù)的第1條。
基本代碼
根據(jù)返回的url就可以從這個(gè)url去定位我們需要爬的信息。走通了就可以正式寫(xiě)代碼了,以下代碼采用jupyter notebook的組織方式,也就是切分得比較細(xì)。先引入所需庫(kù):
import json
import requests
import pandas as pd
from lxml import etree
讀取書(shū)名Excel數(shù)據(jù),只用了"書(shū)名"列,先不考慮其他列
bsdf=pd.read_excel('booklistfortest.xlsx')
blst=list(bsdf['書(shū)名']) #書(shū)名列表
#bsdf.head(3)
對(duì)書(shū)名列表進(jìn)行循環(huán),得到的屬性用字典裝著,每本書(shū)的屬性是一個(gè)字典,用列表裝各個(gè)字典。
通過(guò)requests.get('https://book.douban.com/j/subject_suggest?q={0}'.format(bn))
獲取搜索建議返回的json數(shù)據(jù),其中bn是書(shū)名字符串。
爬蟲(chóng)的一般解析是用BeautifulSoup或xpath,我更喜歡用xpath,因此下面的代碼主要基于xpath解析文本。
以評(píng)分為例,鼠標(biāo)點(diǎn)擊評(píng)分部分,然后按Ctrl+Shift+I,或者右鍵點(diǎn)擊檢查元素,反正就是定位到評(píng)分對(duì)應(yīng)的HTML上,定位到評(píng)分的代碼部分后,右鍵,選擇Copy->Copy XPath,例如對(duì)于評(píng)分來(lái)說(shuō)有://*[@id="interest_sectl"]/div/div[2]/strong
。
圖4,復(fù)制評(píng)分的xpath
通過(guò)con.xpath('//*[@id="interest_sectl"]/div/div[2]/strong/text()')
就可以得到評(píng)分?jǐn)?shù)據(jù),返回的是列表,一般就是第0個(gè)值。同樣,其他地方也是這樣,而作者、出版社那幾個(gè)屬性是結(jié)構(gòu)比較散的,需要特殊處理。
圖5,自由度較大的書(shū)目信息部分
通過(guò)//*[@id="info"]/span[2]
可以確定 出版社 這個(gè)屬性,但是屬性的值,具體是哪個(gè)出版社不能確定,這些文字是在info這個(gè)節(jié)點(diǎn)上的。對(duì)于這種長(zhǎng)度不定的一個(gè)html區(qū)域,不能寫(xiě)死xpath解析式,需要理清其HTML樹(shù)結(jié)構(gòu),建立info的樹(shù)結(jié)構(gòu)。通過(guò)分析幾個(gè)具體的頁(yè)面的info部分,建立樹(shù)結(jié)構(gòu)如下:
圖6,info部分的HTML樹(shù)
需要得到的是{'出版社’:'中信出版集團(tuán)'}
這樣的數(shù)據(jù),通過(guò)HTML樹(shù)結(jié)構(gòu)可以看到的特征是鍵(如出版社)在span里,值可能在text里,也可能封裝在span里的子元素里,反正每個(gè)鍵值對(duì)之后都有一個(gè)br去切分??紤]這些情況寫(xiě)出的代碼如下:
def getBookInfo(binfo,cc):
i=0
rss={}
k=''
v=''
f=0
clw=[]
for c in cc:
if '\n' in c:
if '\xa0' in c:
clw.append(c)
else:
clw.append(c)
for m in binfo[0]:
if m.tag=='span':
mlst=m.getchildren()
if len(mlst)==0:
k=m.text.replace(':','')
if '\xa0' in clw[i]:
f=1#需要m.tag=='a'下的值
else:
v=clw[i].replace('\n','').replace(' ','')
i+=1
elif len(mlst)>0:#下面有子span 一種判斷是m.attrib=={} 不夠精確
for n in mlst:
if n.tag=='span':
k=n.text.replace('\n','').replace(' ','') #不至于下面還有span,懶得用遞歸了
elif n.tag=='a':
v=n.text.replace('\n','').replace(' ','')
elif m.tag=='a':
if f==1: #是否可以不用這個(gè)if
v=m.text.replace('\n','').replace(' ','')
f=0
elif m.tag=='br':
if k=='':
print(i,'err')
else:
rss[k]=v
else:
print(m.tag,i)
return rss
為了在大循環(huán)里好調(diào)用,上面的部分封裝成函數(shù),調(diào)用getBookInfo()返回的是一個(gè)字典,要整合到已有的字典里。涉及字典的組合,查了一下可以用d=dict(d,**dw)
,其中d是舊字典,dw是要加到d里的新字典,更簡(jiǎn)便的方式是用d.update(dw)函數(shù),下面的代碼就是用的update的。
主循環(huán)代碼:
rlst=[]
for bn in blst:
res={}
r=requests.get('https://book.douban.com/j/subject_suggest?q={0}'.format(bn))
rj=json.loads(r.text)
#對(duì)rj進(jìn)行一下驗(yàn)證和篩選
html=requests.get(rj[0]['url']) #之后再考慮多個(gè)返回值的驗(yàn)證
con = etree.HTML(html.text)
bname=con.xpath('//*[@id="wrapper"]/h2/span/text()')[0] #和bn比較
res['bname_sq']=bn
res['bname']=bname
res['dbid']=rj[0]['id'] #不需要存url,存id就夠了
#這部分取到info就夠了,之后再用高級(jí)方法去匹配需要的元素,目前對(duì)應(yīng)不對(duì)
binfo=con.xpath('//*[@id="info"]')
cc=con.xpath('//*[@id="info"]/text()')
res.update(getBookInfo(binfo,cc)) #調(diào)用上面的函數(shù)處理binfo
bmark=con.xpath('//*[@id="interest_sectl"]/div/div[2]/strong/text()')[0]
if bmark==' ':
bits=con.xpath('//*[@id="interest_sectl"]/div/div[2]/div/div[2]/span/a/text()')[0]
if bits=='評(píng)價(jià)人數(shù)不足':
res['評(píng)分']=''
res['評(píng)價(jià)人數(shù)']='評(píng)價(jià)人數(shù)不足'
else:
res['評(píng)分']=''
res['評(píng)價(jià)人數(shù)']=''
else:
res['評(píng)分']=bmark.replace(' ','')
bmnum=con.xpath('//*[@id="interest_sectl"]/div/div[2]/div/div[2]/span/a/span/text()')[0]
res['評(píng)價(jià)人數(shù)']=bmnum
rlst.append(res)
得到的數(shù)據(jù)可以進(jìn)行一定的標(biāo)準(zhǔn)化然后進(jìn)行分析再輸出。上面得到的列表rlst=[{'書(shū)名':'a','出版社':'b'},{'','','':''}],可以直接變成dataframe,
outdf=pd.DataFrame(rlst) #轉(zhuǎn)dataframe
outdf.to_excel('out_douban_binfo.xlsx',index=False) #輸出數(shù)據(jù)
圖7,爬到的數(shù)據(jù)概覽
我們開(kāi)始時(shí)讀入的bsdf有書(shū)名、作者、閱讀時(shí)間等屬性,因?yàn)榕老聛?lái)的數(shù)據(jù)可能會(huì)有缺失值,將兩個(gè)表合并起來(lái)進(jìn)行分析。分析的維度有書(shū)名、作者、閱讀時(shí)間、出版社、頁(yè)數(shù)等。首先是用merge整合兩表然后看一些基本的統(tǒng)計(jì)量。
bdf=bsdf.merge(outdf,on='書(shū)名',how='left') # 數(shù)據(jù)合并
# 基本統(tǒng)計(jì)值
print('一共有{0}本書(shū),{1}個(gè)作者,{2}個(gè)出版社;'.format(len(bdf),len(set(list(bdf['作
者']))),len(set(list(bdf['出版社'])))))
輸出是一共有421本書(shū),309個(gè)作者,97個(gè)出版社;
我們就來(lái)看看前幾位的作者和出版社,通過(guò)bdf['作者'].value_counts().head(7)
可以輸出前7位書(shū)單里出現(xiàn)最多的作者,出版社同理,結(jié)果如下:
圖8,出版社和作者統(tǒng)計(jì)
從作者出現(xiàn)次數(shù)來(lái)看,前6位都是小說(shuō)類(lèi)型的書(shū),可以看一下吳軍的是哪些書(shū):
bdf.loc[bdf['作者']=='吳軍',['書(shū)名','閱讀時(shí)間','閱讀情況','出版社']]
#output:
'''
書(shū)名 閱讀時(shí)間 閱讀情況 出版社
103 數(shù)學(xué)之美 2016-10-20 P5 人民郵電出版社
233 智能時(shí)代 2017-06-22 P4 中信出版社
237 硅谷之謎 2017-07-01 P4 人民郵電出版社
383 見(jiàn)識(shí)--商業(yè)的本質(zhì)和人生的智慧 2018-10-21 P4 中信出版社
'''
對(duì)每月閱讀數(shù)量進(jìn)行統(tǒng)計(jì):
import matplotlib.pyplot as plt #繪圖用到matplotlib庫(kù)
%matplotlib inline
bdf['閱讀年月']=bdf['閱讀時(shí)間'].apply(lambda x : x.strftime('%Y-%m'))
read_date=bdf['閱讀年月'].value_counts() #每月閱讀量,按月計(jì)數(shù)
read_date=pd.DataFrame(read_date,columns=['閱讀年月']) #從Series變?yōu)镈ataFrame
read_date=read_date.sort_index()
plt.figure(figsize=(15,5))
plt.xticks(rotation=90)#設(shè)置時(shí)間標(biāo)簽顯示格式
plt.plot(read_date) #因?yàn)閖upyter里寫(xiě)了 %matplotlib inline 不用寫(xiě) plt.show()
圖9,每月閱讀數(shù)量_時(shí)間軸折線圖.png
好奇不同年份每個(gè)月是否有一定規(guī)律呢。要統(tǒng)計(jì)這個(gè)比較方便的就是用數(shù)據(jù)透視表了,pandas里的pivot_table
出場(chǎng)。
import numpy as np
bdf['閱讀年']=bdf['閱讀時(shí)間'].apply(lambda x : x.strftime('%Y'))
bdf['閱讀月']=bdf['閱讀時(shí)間'].apply(lambda x : x.strftime('%m')) #這里也可以用.month .year
r_dd=bdf.loc[:,['閱讀年','閱讀月']]
r_dd['val']=1 #用以初始化
r_dd=pd.pivot_table(r_dd,values='val',index=['閱讀月'],columns=['閱讀年'],aggfunc=np.sum).fillna(value=0)
#這部分代碼的細(xì)節(jié)可以看本人github里jupyter notebook文件的輸出
r_dd=r_dd.loc[:,['2016','2017','2018']] #因?yàn)槠渌攴菰路莶蝗蝗∵@3年來(lái)看
plt.figure()
r_dd.plot(xticks=range(1,13),figsize=(12,5))
圖10,每月閱讀數(shù)量_按年統(tǒng)計(jì)
可以看到這3年在2月和7月閱讀普遍數(shù)量更多,在7月份之前每月閱讀量是逐年上漲的,而從8月到12月則是遞減的規(guī)律,2016年11月閱讀的書(shū)籍最多,達(dá)到40本以上。
評(píng)分是一個(gè)數(shù)值型變量,用箱線圖[圖片上傳中...(圖12_書(shū)單內(nèi)數(shù)據(jù)相關(guān)的書(shū)籍.png-5352ab-1551272966564-0)]
展現(xiàn)其特征:
b_rank=pd.DataFrame(bdf['評(píng)分']) #評(píng)分分布(箱線圖)
b_rank.boxplot()
#另,評(píng)分 top 10:
#bdf.sort_values(by='評(píng)分',ascending=False).head(10).loc[:,['書(shū)名','作者','閱讀時(shí)間'
,'閱讀情況','出版社','評(píng)分']]
圖11,書(shū)籍評(píng)分箱線圖
從箱線圖來(lái)看,書(shū)單有評(píng)分的書(shū)籍的豆瓣平均分在7.8左右,75%的書(shū)評(píng)分在7.2以上,也有一些書(shū)是在4分一下的。
圖12,書(shū)單內(nèi)數(shù)據(jù)相關(guān)的書(shū)籍
書(shū)單里書(shū)名直接包含數(shù)據(jù)的書(shū)有37本,數(shù)據(jù)科學(xué)相關(guān)的書(shū)籍?dāng)?shù)量應(yīng)該大于這個(gè)值。
可以進(jìn)一步分析的有:
看的書(shū)的書(shū)名詞云、作者的詞云
出版社省份
把字?jǐn)?shù)統(tǒng)計(jì)和爬下來(lái)的頁(yè)數(shù)進(jìn)行擬合,把字?jǐn)?shù)和頁(yè)數(shù)一起處理
把含有多國(guó)貨幣的價(jià)格屬性按匯率換算后看價(jià)格的分布
上面通過(guò)一個(gè)具體的需求實(shí)踐了能解決問(wèn)題的爬蟲(chóng),豆瓣還是比較容易爬的,上面解析書(shū)目信息的做法還是很有意義的,當(dāng)然我是用xpath做的,如果用BeautifulSoup又會(huì)是另一種實(shí)現(xiàn)方式,但分析問(wèn)題->建立HTML樹(shù)的過(guò)程是通用的。上面的代碼還是比較簡(jiǎn)略的,沒(méi)有考慮過(guò)多的驗(yàn)證和異常處理,有任何意見(jiàn)或建議歡迎交流。
以上就是Python如何一鍵爬取你所關(guān)心的書(shū)籍信息,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
當(dāng)前名稱:Python如何一鍵爬取你所關(guān)心的書(shū)籍信息
分享路徑:http://jinyejixie.com/article38/gdgjpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、面包屑導(dǎo)航、品牌網(wǎng)站設(shè)計(jì)、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)