(轉)Python新手寫出漂亮的爬蟲代碼1——從html獲取信息

 

https://blog.csdn.net/weixin_36604953/article/details/78156605css

 

Python新手寫出漂亮的爬蟲代碼1
初到大數據學習圈子的同窗可能對爬蟲都有所耳聞,會以爲是一個高大上的東西,彷彿九陽神功和乾坤大挪移同樣,和別人說「老子會爬蟲」,就感受特別有逼格,可是又不知從何入手,這裏,博主給你們糾正一個誤區:爬蟲並不神祕,也不高級,是一個很是好上手和掌握的東西(固然,裏面也有不少坑,也有不少細節,展開說的話其實也蠻複雜的,不過它的模式和套路就擺在那裏,看了小編的博客,保證你能爬下你想要的內容)。html

通常狀況下,爬蟲分爲兩種,一種是靜態爬蟲,一種是動態爬蟲,所謂靜態爬蟲,就是大部分信息(至少你所須要的那些信息)是寫在html代碼中的,而動態爬蟲通常都是寫在一個json文檔中,這麼說可能不太標準,不過初學者這樣理解便可,這篇博客將會帶你們領略靜態爬蟲,下一篇將會講解動態爬蟲。python

補充一句,博主曾是忠實的Python2用戶,不過如今也改到Python3了,曾經新的庫會在Python2中首先兼容,而後要過很久纔在Python3中集成,如今徹底不用擔憂,Python2有了,Python3不日就會集成,Python3也會在編碼方面提供更多遍歷,推薦新手直接從Python3入手,固然,兩者沒有什麼太大區別,遇到問題問問度娘就能夠了了,廢話很少說,咱們開始爬蟲的第一課!程序員

本篇博文將從如下幾個方面進行講解
- 啥是Html代碼?
- 怎麼從Html代碼中定位到我要的東西?
- BeautifulSoup神器
- 案例:愛卡汽車正則表達式

啥是Html代碼
所謂的html代碼,瀏覽博客的你右手必定在鼠標上,好的,跟着我左手右手一個慢動做,點擊右鍵,找到「查看網頁源代碼」,不一樣瀏覽器可能這個描述不太同樣,博主是Chrome,不過都差不太多,是否是有看到相似下面這個圖的一堆不知道是什麼鬼的代碼?算法

 

其實,你能夠按鍵盤上的F12或者右鍵選擇「檢查元素」(不一樣瀏覽器不一樣),這時,瀏覽器的右側(若是你是360瀏覽器,多是在下方)彈出一個東東,相似下面紅色框中的區域 編程


這個東西就是剛纔咱們看的那個不知道是什麼鬼的東西的樹狀結構,看上去會整齊一些。這就是html代碼,html代碼其實就是用許多個"<Y yy='aaa'>xxxx</Y>"是的結構將想要輸出在頁面上的內容包含起來的一種語言。下一個小節將詳細介紹這個結構,總而言之,咱們肉眼所看到的東西大部分都來自於html代碼,html代碼的做用簡單來講就是程序員用一堆html代碼,將須要展現的信息放在指定的位置上的一種東西,有了html代碼,纔有了你眼前頁面上的不少元素;固然,還有其餘方式來將元素展現在頁面上,如css、js等渲染方式,這些咱們下一篇會介紹。json

知道咱們所須要的信息位於html中,那麼只須要找到咱們須要的具體內容在哪裏,而後下載下來,就大功告成了,邏輯就是這麼個邏輯,因此靜態爬蟲的關鍵問題是要準確的解析html代碼,通常使用BeautifulSoup這個庫或者正則表達式。小程序

怎麼從Html代碼中定位到我要的東西
標籤
上一節中提到,html代碼中都是"<Y yy='aaa'>xxxx</Y>"結構,一對」<>」咱們稱之爲標籤,這對標籤中一般會有一些內容,多是一個數字,一段字符串,一個網頁連接,或者一個圖片連接等等,總之,就是咱們在網頁上看到的內容。」Y」稱之爲標籤名,」yy」爲其屬性名,」aaa」是其屬性值,」xxxx」是這個標籤的內容,也就是對應於頁面上的信息。通常狀況下咱們要獲取的就是」xxxx」,有時咱們可能也須要獲取標籤的屬性值」aaa」。標籤多是惟一的,也多是有重複的,回看剛纔那張樹狀的標籤結構,有一種分明的層次感,同一層的標籤咱們稱他們互爲兄弟標籤,而一個標籤和包含他的標籤互爲父子標籤,若是a包含b,b包含c,d,則c是a的後代標籤,是b的子標籤,是d的兄弟標籤,這個名字無所謂的,瞭解一下就好,通常標籤名可能會重複,但標籤屬性名(yy)和屬性值「aaa」不多重複,不過兄弟標籤之間可能會出現標籤名、屬性名、屬性值徹底相同的狀況,後面會介紹(就是find方法和findAll方法的區別)。瀏覽器

好,上實例,打開一個網址把:http://newcar.xcar.com.cn/257/review/0.htm,是愛卡汽車中比亞迪F3的口碑頁面,鼠標右鍵選擇「檢查元素」或者之間按鍵盤上的F12,選擇那個鼠標的按鈕(紅色框1),而後將鼠標放到評論框附近(紅色框2),以下圖所示,看到檢查元素界面中有一段代碼背景色變成了深色(如紅色框3)

 

每一個頁面有10條口碑,可見這10條口碑均存儲在屬性名爲’class’,屬性值爲’review_comments_dl’的’div’標籤中,固然,這個標籤不是一個「葉節點」,也就是說這個標籤內部還有其餘標籤,咱們進一步看看。看下面的圖片。

 

咱們能夠看到紅框3中有不少相同的標籤<dl>...</dl>,他們都是屬性名爲’class’,屬性值爲’review_comments_dl’的’div’標籤的子標籤,他們之間互爲兄弟標籤,咱們把鼠標放在紅框3的位置並選中,這時左側網頁的第一條口碑的位置就會變成深色背景,也就是說,紅框3這個標籤實際上對應着紅框2這個區域中的內容,那麼咱們把紅框3再具體的看一看。以下圖所示。

 

能夠看到,第一條口碑(紅框中的內容)在第一個’dl’標籤中(紅色下劃線2),同理能夠看到第二條口碑在第二個’dl’標籤中。再來看看這個’dl’標籤,他有兩個子標籤,’dt’和’dd’子標籤,口碑數據位於dd子標籤下;好的,再來看’dd’標籤,將’dd’標籤展開,以下圖所示。

 

紅框3是該車的第一頁的第一條口碑,位於dd標籤中,及圖中藍色下劃線<dd>...</dd> 中的內容,圖中從開頭的dd指向紅框3,標註了「同級」,意思是紅框3的內容是dd標籤的內容,而dd標籤下還有子標籤,好比屬性爲class,屬性值爲useful的div標籤,裏面的內容1034是有多少人以爲這個口碑有用;還有一個子標籤p,p標籤的內容是口碑的做者;p中有一個子標籤a,a標籤的內容是評論來源,如圖中的「比亞迪F3論壇」。

好了,如今想必讀者已經對經過標籤訂位信息有所瞭解了,咱們再來練習一下,咱們將口碑頁切換到第2頁,能夠看到地址變成了http://newcar.xcar.com.cn/257/review/0/0_2.htm,多了一個’0_2’。將’0_2’改爲’0_1’就跳回了第一頁(實際上第一頁的真實url是http://newcar.xcar.com.cn/257/review/0/0_1.htm),而改爲’0_3’就到了第三頁。那麼咱們應該怎麼獲取該車型的口碑一共有幾頁呢?看下面的圖。

 

依然是在開發者工具視角(及按F12彈出的窗口這個視角),將鼠標放在尾頁(這裏是122)或者‘下一頁’上,右側的框中會出現如圖所示的畫面,能夠看到尾頁122所在的位於屬性爲class,屬性值爲’pagers’的div標籤的倒數第二個子標籤中,如紅框1所示;而’下一頁’則位於屬性爲class,屬性值爲’pagers’的div標籤的最後一個子標籤中,如紅框2所示。在仔細貫徹一下會發現屬性爲class,屬性值爲’pagers’的div標籤與咱們以前尋找口碑的標籤dl是兄弟標籤,位於所有的dl標籤的再後面一個,也就是說,該標籤的父標籤與dl標籤相同,即屬性名爲’class’,屬性值爲’review_comments_dl’的’div’標籤。

爲何要肯定尾頁呢?由於構造代碼時,咱們要知道代碼的起止位置,使用for循環良好的控制代碼的開始與完結。

這個爬蟲的邏輯是這樣的:找到目標的車型,即其url,實際上,不一樣車型的url只有id不一樣,好比比亞迪F3的url是http://newcar.xcar.com.cn/257/,其車子id是257,當id更改成258時,車型就變成了比亞迪F0;而後查看html代碼,明確要爬取的內容的所在位置,明確換頁規律,明確爬蟲的起止位置(獲取尾頁信息的html位置),而後構造代碼。

BeautifulSoup神器
Python一個第三方庫bs4中有一個BeautifulSoup庫,是用於解析html代碼的,換句話說就是能夠幫助你更方便的經過標籤訂位你須要的信息。這裏只介紹兩個比較關鍵的方法:

一、find方法和findAll方法:
首先,BeautifulSoup會先將整個html或者你所指定的html代碼編程一個BeautifulSoup對象的實例(不懂對象和實例沒關係,你只要把它看成是一套你使用F12看到的樹形html代碼代碼就好),這個實例可使用不少方法,最經常使用的就是find和findAll,兩者的功能是相同的,經過find( )的參數,即find( )括號中指定的標籤名,屬性名,屬性值去搜索對應的標籤,並獲取它,不過find只獲取搜索到的第一個標籤,而findAll將會獲取搜索到的全部符合條件的標籤,放入一個迭代器(其實是將全部符合條件的標籤放入一個list),findAll經常使用於兄弟標籤的定位,如剛纔定位口碑信息,口碑都在dl標籤下,而同一頁的10條口碑對應於10個dl標籤,這時候用find方法只能獲取第一個,而findAll會獲取所有的10個標籤,存入一個列表,想要獲取每一個標籤的內容,只需對這個列表使用一個for循環遍歷一遍便可。

二、get_text()方法:
使用find獲取的內容不只僅是咱們須要的內容,並且包括標籤名、屬性名、屬性值等,好比使用find方法獲取"<Y yy='aaa'>xxxx</Y>" 的內容xxxx,使用find後,咱們會獲得整個"<Y yy='aaa'>xxxx</Y>",十分冗長,實際咱們想要的僅僅是這個標籤的內容xxxx,所以,對使用find方法後的對象再使用get_text( )方法,就能夠獲得標籤的內容了,對應到這裏,咱們經過get_text( )方法就能夠獲得xxxx了。

好了,鋪墊作的差很少了,上代碼咯~~~

案例:愛卡汽車
使用Python3,須要提早安裝bs4庫,博主的環境是win7+Python3+Pycharm(有時候也用Ubuntu16.04+Python3+Pycharm),不少時候都有人問博主,什麼ide好用呢?jupyter notebook?spyder?Pycharm?這裏只能和你們說各個ide各有千秋,作工程(如爬蟲)使用pycharm確定是首選,若是隻是平時的練習,寫個小程序,使用jupyter notebook和spyder就不錯,總之,若是涉及到頻繁打印輸出結果的東西,最好仍是用pycharm,不要用jupyter notebook,否則會很卡。

言歸正傳,上代碼!

兩點說明:爬蟲代碼中,html代碼常常會出現’class’這個屬性名,而class是python中「類」的關鍵字,而爬蟲的find方法對於屬性名而言,是不須要加引號的,若是直接輸入class是會出現問題的,因此須要注意,每次輸入class時應當輸入爲class_,即class後加一個下劃線;

第二就是下方代碼一開始有一個add_header的過程,爲的是將代碼假裝成瀏覽器。不少網站是反對爬蟲程序對其信息進行爬取的,因此會禁止一些程序訪問他們的網站,經過add_header將你的爬蟲程序假裝成了瀏覽器,故在網站看來,訪問它的就不是一個程序,而是一個瀏覽器,或者說是一我的類用戶了。

import urllib
import urllib.request
from bs4 import BeautifulSoup
import re
import random
import time

# 設置目標url,使用urllib.request.Request建立請求
url0 = "http://newcar.xcar.com.cn/257/review/0.htm"
req0 = urllib.request.Request(url0)

# 使用add_header設置請求頭,將代碼假裝成瀏覽器
req0.add_header("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36")

# 使用urllib.request.urlopen打開頁面,使用read方法保存html代碼
html0 = urllib.request.urlopen(req0).read()

# 使用BeautifulSoup建立html代碼的BeautifulSoup實例,存爲soup0
soup0 = BeautifulSoup(html0)

# 獲取尾頁(對照前一小節獲取尾頁的內容看你就明白了)
total_page = int(soup0.find("div",class_= "pagers").findAll("a")[-2].get_text())
myfile = open("aika_qc_gn_1_1_1.txt","a")
print("user","來源","認爲有用人數","類型","評論時間","comment",sep="|",file=myfile)
for i in list(range(1,total_page+1)):
# 設置隨機暫停時間
stop = random.uniform(1, 3)
url = "http://newcar.xcar.com.cn/257/review/0/0_" + str(i) + ".htm"
req = urllib.request.Request(url)
req.add_header("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36")
html = urllib.request.urlopen(req).read()
soup = BeautifulSoup(html)
contents = soup.find('div', class_="review_comments").findAll("dl")
l = len(contents)
for content in contents:
tiaoshu = contents.index(content)
try:
ss = "正在爬取第%d頁的第%d的評論,網址爲%s" % (i, tiaoshu + 1, url)
print(ss)
try:
comment_jiaodu = content.find("dt").find("em").find("a").get_text().strip().replace("\n","").replace("\t","").replace("\r","")
except:
comment_jiaodu = ""
try:
comment_type0 = content.find("dt").get_text().strip().replace("\n","").replace("\t","").replace("\r","")
comment_type1 = comment_type0.split("【")[1]
comment_type = comment_type1.split("】")[0]
except:
comment_type = "好評"
# 認爲該條評價有用的人數
try:
useful = int(content.find("dd").find("div",class_ = "useful").find("i").find("span").get_text().strip().replace("\n","").replace("\t","").replace("\r",""))
except:
useful = ""
# 評論來源
try:
comment_region = content.find("dd").find("p").find("a").get_text().strip().replace("\n","").replace("\t","").replace("\r","")
except:
comment_region = ""
# 評論者名稱
try:
user = content.find("dd").find("p").get_text().strip().replace("\n","").replace("\t","").replace("\r","").split(":")[-1]
except:
user = ""
# 評論內容
try:
comment_url = content.find('dt').findAll('a')[-1]['href']
urlc = comment_url
reqc = urllib.request.Request(urlc)
reqc.add_header("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36")
htmlc = urllib.request.urlopen(reqc).read()
soupc = BeautifulSoup(htmlc)
comment0 = \
soupc.find('div', id='mainNew').find('div', class_='maintable').findAll('form')[1].find('table',class_='t_msg').findAll('tr')[1]
try:
comment = comment0.find('font').get_text().strip().replace("\n", "").replace("\t", "")
except:
comment = ""
try:
comment_time = soupc.find('div', id='mainNew').find('div', class_='maintable').findAll('form')[1].find('table', class_='t_msg').\
find('div', style='padding-top: 4px;float:left').get_text().strip().replace("\n","").replace( "\t", "")[4:]
except:
comment_time = ""
except:
try:
comment = content.find("dd").get_text().split("\n")[-1].split('\r')[-1].strip().replace("\n", "").replace("\t","").replace("\r", "").split(":")[-1]
except:
comment = ""
# time.sleep(stop)
print(user,comment_region,useful,comment_type,comment_time,comment, sep="|", file=myfile)
except:
s = "爬取第%d頁的第%d的評論失敗,網址爲%s" % (i, tiaoshu + 1, url)
print(s)
pass
myfile.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
補充說明一下:try——except這個結構(看起來有點像if——else的結構)是一個很是重要的過程,爲了使爬蟲代碼能夠良好的運行,不至於剛開始爬幾分鐘就報錯這種噁心人的狀況,須要很好的利用try——except過程。程序會先執行try下的語句,若是發生失敗,就會執行except下的語句,你也可使用多個try——except嵌套的結構完成複雜的狀況的覆蓋,最好要保證你的try——except過程包含了程序會遇到的全部狀況,那麼你的代碼就是趨於完美的。

講到這裏,第一節爬蟲課程也就到這裏了,不久以後會介紹動態爬蟲,若是以後還有時間,還會介紹一下selenium這個模擬瀏覽的庫,以及爬蟲框架還有反爬蟲的知識,給本身打個廣告,除了爬蟲可,近期也會分享一些關於word2vec和fastText文本分類算法的內容,讀者有什麼其餘想交流的能夠留言~我也是個正在學習路上的仔,但願能和各路朋友以及大牛交流。

目錄Python新手寫出漂亮的爬蟲代碼1啥是Html代碼怎麼從Html代碼中定位到我要的東西標籤BeautifulSoup神器案例愛卡汽車目錄--------------------- 做者:夏洛克江戶川 來源:CSDN 原文:https://blog.csdn.net/weixin_36604953/article/details/78156605 版權聲明:本文爲博主原創文章,轉載請附上博文連接!

相關文章
相關標籤/搜索