當前位置:成語大全網 - 書法字典 - 如何用python爬取豆瓣閱讀數據

如何用python爬取豆瓣閱讀數據

這兩天在豆瓣爬了10萬條左右的書目信息,用了將近壹天的時間。現在我利用這個閑暇時間總結壹下代碼。我還是新手,都是最簡單最笨的方法。請幫助我。

第壹步是查看我們需要的庫:

導入請求?#用於請求網頁

從bs4導入BeautifulSoup #解析網頁

導入時間?#設置延遲時間以防止抓取被頻繁阻止的IP號碼。

導入re #正則表達式庫

導入pymysql?#由於爬取的數據太多,我們需要將其存儲在MySQL數據庫中,該數據庫用於連接數據庫。

Import random #該數據庫使用生成隨機數的randint函數,該函數與上述時間相匹配,使爬網間隔隨機。

這是豆瓣的網站:x-sorttags-all。

我們希望從這裏獲得所有分類標簽鏈接,並進壹步抓取裏面的信息。首先發布代碼:

導入請求

從bs4導入BeautifulSoup?#導入庫

URL =“httom/tag/?icn =索引導航“

WB _ data = requests . get(url)#請求URL

soup = beautiful soup(WB _ data . text,“lxml“)?#解析網頁信息

tags = soup . select(# content & gt;div & gtdiv.article & gtdiv & gtdiv & gt表格& gttbody & gttr & gttd & gt壹個“)

#根據CSS路徑查找標簽信息,CSS路徑獲取方法,右鍵-勾選-復制選擇器,tags返回列表。

對於標簽中的標簽:

tag = tag . get _ text()#提取列表中的每個標簽信息。

helf =“hom/tag/“

#看豆瓣的網站,基本上這部分都是帶信息標簽的,所以我們需要組裝用於抓取標簽詳情頁的網站。

url=helf+str(標記)

組裝並輸出print(URL )# URL。

上面,我們抓取了標簽下的所有URL。我們將此文件命名為channel,並在channel中創建壹個channel字符串,放入我們爬網的所有URL信息,並在我們爬網詳細信息頁面時直接從這裏提取鏈接,如下所示:

頻道=“““

標簽/程序

'''

現在,讓我們開始第二個程序。

QQ圖片20160915233329.png

標簽頁下每張圖片的信息基本是這樣的。我們可以從這裏直接提取書名、作者、出版商、出版時間、價格、審稿人數、評分等信息(有些外國作品也會有譯者信息)。提取方法與選項卡類似,也是根據CSS路徑提取的。

讓我們首先使用壹個網站來實驗爬行:

URL =“http/tag/technology“

WB _ data = requests . get(URL)

soup = beautiful soup(WB _ data . text . encode(“utf-8“)“lxml“)

tag=url.split(“?) [0].split(“/“)【-1】#從鏈接中提取標簽信息以便於存儲。

detils = soup . select(“# subject _ list & gt;ul & gt李。div.info & gtdiv.pub“)?#抓取作者和出版社的信息,我們後面會用刁難()功能把它們分開。

scors = soup . select(“# subject _ list & gt;ul & gt李。div.info & gtdiv . star . clear fix & gt;span.rating_nums“)?#獲取評分信息

persons = soup . select(# subject _ list & gt;ul & gt李。div.info & gtdiv . star . clear fix & gt;span . pl“)#評估人數

titles = soup . select(“# subject _ listul & gt李。div.info & gth2 & gta“)?#標題

#以上是我們需要的所有html標簽信息,我們需要將它們逐個分開。

對於郵編中的詳細信息、分數、人員、職位(詳細信息、分數、人員、職位):

#用zip()函數實現遍歷。

#因為有些標簽有譯者信息,有些標簽沒有,為了避免出錯,我們需要使用壹個try來分隔它們。

嘗試:

作者= detil。get _ text()。split(“/“,4)【0】。split()【0】#這是壹種帶有譯者信息的提取方法,根據“/”?將標簽分成五個部分,然後依次提取它們。

易哲= detil.get_text()。split(“/“,4)【1】

publish=detil.get_text()。split(“/“,4)【2】

time=detil.get_text()。split(“/“,4)【3】。split()【0】。拆分(“-“)【0】?#我們只提取出版年份的時間。

Price =史策_ price one(detil)#由於價格的單位不統壹,我們使用壹個函數將其轉換為“元”。

SCOE = SCOR。GET _ TEXT()if true else““#有些書沒有評分。為了避免錯誤,我們將未評分的信息設置為空白。

人=史策_人(人)?#有些書目的評價者少於10人,在抓取過程中會出現錯誤。使用壹個函數來處理它們。

title=title.get_text()。split()【0】?

#沒有譯者信息時,會顯示IndexError,我們會單獨處理。

除了索引錯誤:

嘗試:

author=detil.get_text()。split(“/“,3)【0】。split()【0】

易哲=““#將詳細信息分為四部分進行提取,並將譯者信息直接設置為空,其他同上。

publish=detil.get_text()。split(“/“,3)【1】

time=detil.get_text()。split(“/“,3)【2】。split()【0】。拆分(“-”)【0】

價格=史策價格二(詳細)

scoe = SCOR . get _ text()if True else““

個人=史策_個人(個人)

title=title.get_text()。split()【0】

except(IndexError,TypeError):

繼續嗎?

#如果出現其他錯誤信息,忽略並繼續執行(有些書目信息會沒有出版社和出版年份,但數量很少,不會影響我們大規模抓取,所以直接忽略)。

除外類型錯誤:

繼續

#提取評價者數量的函數。如果評估者人數少於十人,則按十人處理。

def史策_person(人):

嘗試:

person = int(person . get _ text()。split()【0】【1:len(person . get _ text()。split()【0】)-4】)

除了值錯誤:

person = int(10)

返回人員

#按案例提取價格的函數,通過正則表達式找到帶有特殊字符的信息,並將其轉換為“元”。

史策價格:

price = detil.get_text()。split(“/“,4)【4】。拆分()

如果重新匹配(“美元”,價格【0】):

價格= float(價格【1】)* 6

elif re . match(“CNY“,price【0】):

價格=價格【1】

elif re . match(“\ A $“,price【0】):

價格= float(價格【1:len(價格)】)* 6

否則:

價格=價格【0】

退貨價格

def史策價格二(價格):

price = detil.get_text()。split(“/“,3)【3】。拆分()

如果重新匹配(“美元”,價格【0】):

價格= float(價格【1】)* 6

elif re . match(“CNY“,price【0】):

價格=價格【1】

elif re . match(“\ A $“,price【0】):

價格= float(價格【1:len(價格)】)* 6

否則:

價格=價格【0】

退貨價格

實驗成功後,我們可以抓取數據並將其導入數據庫。以下是全部源代碼,特殊情況會有註釋說明。

導入請求

從bs4導入BeautifulSoup

導入時間

進口re

導入pymysql

從渠道導入渠道?#這是我們的第壹個程序抓取的鏈接信息。

隨機導入

def史策_person(人):

嘗試:

person = int(person . get _ text()。split()【0】【1:len(person . get _ text()。split()【0】)-4】)

除了值錯誤:

person = int(10)

返回人員

史策價格:

price = detil.get_text()。split(“/“,4)【4】。拆分()

如果重新匹配(“美元”,價格【0】):

價格= float(價格【1】)* 6

elif re . match(“CNY“,price【0】):

價格=價格【1】

elif re . match(“\ A $“,price【0】):

價格= float(價格【1:len(價格)】)* 6

否則:

價格=價格【0】

退貨價格

def史策價格二(價格):

price = detil.get_text()。split(“/“,3)【3】。拆分()

如果重新匹配(“美元”,價格【0】):

價格= float(價格【1】)* 6

elif re . match(“CNY“,price【0】):

價格=價格【1】

elif re . match(“\ A $“,price【0】):

價格= float(價格【1:len(價格)】)* 6

否則:

價格=價格【0】

退貨價格

#這是上面的測試函數,我們將其放在主函數中。

定義主要內容(url):

WB _ data = requests . get(URL)

soup = beautiful soup(WB _ data . text . encode(“utf-8“)“lxml“)

tag=url.split(“?)[0].拆分(“/”)【-1】

detils = soup . select(“# subject _ list & gt;ul & gt李。div.info & gtdiv.pub“)

scors = soup . select(“# subject _ list & gt;ul & gt李。div.info & gtdiv . star . clear fix & gt;span.rating_nums“)

persons = soup . select(# subject _ list & gt;ul & gt李。div.info & gtdiv . star . clear fix & gt;span.pl“)

titles = soup . select(“# subject _ listul & gt李。div.info & gth2 & gt壹個“)

對於郵編中的詳細信息、分數、人員、職位(詳細信息、分數、人員、職位):

l =【】?#建立存儲數據的列表。

嘗試:

author=detil.get_text()。split(“/“,4)【0】。split()【0】

易哲= detil.get_text()。split(“/“,4)【1】

publish=detil.get_text()。split(“/“,4)【2】

time=detil.get_text()。split(“/“,4)【3】。split()【0】。拆分(“-”)【0】

價格=史策價格(詳細)

scoe = SCOR . get _ text()if True else““

個人=史策_個人(個人)

title=title.get_text()。split()【0】

除了索引錯誤:

嘗試:

author=detil.get_text()。split(“/“,3)【0】。split()【0】

易哲=““

publish=detil.get_text()。split(“/“,3)【1】

time=detil.get_text()。split(“/“,3)【2】。split()【0】。拆分(“-”)【0】

價格=史策價格二(詳細)

scoe = SCOR . get _ text()if True else““

個人=史策_個人(個人)

title=title.get_text()。split()【0】

except(IndexError,TypeError):

繼續嗎?

除外類型錯誤:

繼續

l.append(【標題、scoe、作者、價格、時間、出版、人物、易哲、標簽】)

#依次填寫列表中已爬網的數據。

SQL =“INSERT INTO all books values(%s、%s、%s、%s、%s、%s、% s)“?#這是壹條sql insert語句。

cur . execute many(SQL,l)?#執行sql語句,並使用executemary()函數將其批量插入數據庫。

conn.commit()

#主函數到此結束。

#在MySQL中將python連接到Python數據庫。

conn = pymysql . connect(user =“root“,password =“123123“,database =“python“,charset =“utf8“)

cur = conn.cursor()

cur . execute(‘DROP TABLE IF EXISTS all books‘)?#如果數據庫中有allbooks數據庫,則刪除該數據庫。

sql =“““創建表allbooks(

標題字符(255)不為空,

scor充電器(255),

作者字符(255),

價格收費(255),

計時收費器(255),

發布字符(255),

收費人(255),

易哲·查爾(255),

標簽字符(255)

)"""

cur . execute(SQL)#執行sql語句並創建壹個包含所有書籍的新數據庫。

start = time.clock()?#設置壹個時鐘,這樣我們就可以知道我們爬了多長時間。

對於channel.split()中的URL:

urlss =【URLs+“?start = { } amp;type=T“。範圍(0,980,20)中I的格式(str(I))】?#從頻道中提取url信息,並將其組裝到每個頁面的鏈接中。

對於urlss中的url:

主要內容(網址)?#執行main函數並開始爬行。

print(URL)#輸出要抓取的鏈接,這樣我們就可以知道在哪裏抓取並輕松處理錯誤。

time . sleep(int(format(random . randint(0,9)))?#設置壹個隨機時間,每次爬網頁都可以隨機停壹段時間,防止IP被封。

end = time.clock()

print(‘Time Usage:‘,end-start)#爬網結束,並輸出爬網時間。

count = cur . execute(‘select * from all books‘)

打印(‘有%s條記錄“% count”)?#輸出爬網總數。

#釋放數據連接

如果彎曲:

cur.close()

如果連接:

conn.close()

這樣,即使完成了壹個節目,豆瓣的書目信息也會壹個壹個地寫入我們的數據庫。當然,在抓取的過程中,我們也遇到了很多問題,比如拆分後標題返回的信息中會有空格,寫入數據庫時會出現錯誤,因此只會截取標題的第壹部分,這將導致數據庫中的壹些標題不完整。請指教有沒有辦法過去。

等待爬行的過程是漫長而愉悅的。看著電腦上壹條條信息被刷出來,成就感不自覺地湧上心頭。但是,如果它在妳吃飯的時候爬,在妳上廁所的時候爬,妳已經爬了壹座山回來了,它還在爬的時候就會崩潰壹會兒,擔心電腦隨時會壞(還是窮學生換不起)

因此,最好學會設置斷點、多線程和正則化。路很長,修遠是Xi,我會從頭到尾探索它~ * * * ~