第壹步是查看我們需要的庫:
導入請求?#用於請求網頁
從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,我會從頭到尾探索它~ * * * ~