10分鐘教你Python爬蟲(下)--爬蟲的基本模塊與簡(jiǎn)單的實(shí)戰(zhàn)
新年快樂
各位看客老爺們,新年好。小瑋又來啦。這次給大家?guī)淼氖桥老x系列的第二課---爬蟲的基本模塊與簡(jiǎn)單的實(shí)戰(zhàn)。
說到爬蟲的基本模塊,不知道大家之前有沒有了解過呢。如果你之前沒有了解過,給小瑋一個(gè)機(jī)會(huì)帶您慢慢了解它,如果你之前了解過,也請(qǐng)給小瑋一個(gè)機(jī)會(huì)幫助您再次鞏固。
下面讓我來慢慢細(xì)說。

在這節(jié)課上,我們會(huì)主要了解兩個(gè)模塊,requests和BeautifulSoup。
在最開始呢,肯定是大家要下載安裝一下這兩個(gè)模塊。當(dāng)然如果你按照很久以前的一篇推文里面安裝的是anaconda的話,你就不需要下載,因?yàn)樵缇鸵呀?jīng)安裝好了。
下面我介紹一下直接安裝python的人的安裝方法。打開cmd控制臺(tái),輸入pip ?install ?requests,mac用戶呢,輸入pip3 ?install ?requests等待下載結(jié)束就可以了。Beautifulsoup的安裝會(huì)在后面給出。
下面分別來介紹一下這兩個(gè)模塊。requests是干什么用的呢。它是用作進(jìn)行網(wǎng)絡(luò)請(qǐng)求的模塊。在這里給大家舉一個(gè)例子,大家可以試著去輸出一下下面的代碼,看看到底是什么。
import requestsreq=requests.get('http://docs.python-requests.org/en/master')print(type(req))print(req.status_code)print(req.encoding)print(req.cookies)
這里的status是狀態(tài)碼,encoding是編碼方式。在這里簡(jiǎn)單的介紹一下常見的狀態(tài)碼。
?

那么最后的cookies是啥呢?
其實(shí)就是一個(gè)記錄你在這個(gè)網(wǎng)頁中的活動(dòng)的東西,可能這么說并不是很形象,可以這樣理解,在抖音等APP上,你有沒有發(fā)現(xiàn)經(jīng)??吹囊恍┓N類的視頻總是不斷的推送給你,而其他的內(nèi)容很少推送給你,這是為什么呢?原因很簡(jiǎn)單,就是因?yàn)橛羞@個(gè)cookies記錄了你的愛好。
就我個(gè)人而言,并不是很喜歡cookies,因?yàn)橛锌赡苣銦o意中點(diǎn)到了某個(gè)東西,她就不斷地給你推送。考慮到有些人會(huì)和小編一樣不太習(xí)慣一些莫名其妙的推送,一些網(wǎng)站會(huì)詢問用戶是否同意網(wǎng)站有cookies。
對(duì)于requests其實(shí)介紹到這里就差不多了,因?yàn)檫€有其他的內(nèi)容在我們的課上不會(huì)用到很多。如果大家還有別的需求的話,可以去網(wǎng)上搜一搜。那么下面我們介紹一下BeautifulSoup。
對(duì)于這個(gè)模塊,我想說她確實(shí)是一個(gè)爬蟲利器,出色的解析工具。因?yàn)槲覀冎苯佑胷equests獲取這個(gè)網(wǎng)頁代碼的時(shí)候,我們的程序是不知道究竟這個(gè)代碼中有些什么東西的,只有通過解析html代碼我們才知道這個(gè)網(wǎng)頁中究竟有一些什么。
BeautifulSoup 的安裝比requests的安裝會(huì)復(fù)雜一點(diǎn),她需要安裝兩個(gè)東西。一個(gè)是lxml,一個(gè)是beautifulsoup4,打開cmd命令行,輸入pip install lxml,輸入pip install beautifulsoup4就可以了。
在導(dǎo)入這個(gè)模塊的時(shí)候,我們通常是這樣進(jìn)行導(dǎo)入的。
from bs4 import BeautifulSoup這個(gè)模塊怎么使用呢?在這里舉一個(gè)例子,大家可以去嘗試一下。
import?requestsfrom?bs4?import?beautifulsoupr=requests.get(網(wǎng)址)html=r.textsoup=Beautifulsoup(html,’lxml’)print(soup.prettify())
把這個(gè)程序的網(wǎng)址位置填上相應(yīng)的網(wǎng)址就可以進(jìn)行輸出了。最后的prettify函數(shù)是做什么的呢?他是用來把我們輸出的內(nèi)容進(jìn)行一定的格式化,相當(dāng)于美化一樣的作用。
不知道大家在上一節(jié)課的時(shí)候是否還記得標(biāo)簽Tag這個(gè)屬性。
現(xiàn)在這個(gè)屬性就起作用啦。因?yàn)楝F(xiàn)在我們的soup已經(jīng)把整個(gè)網(wǎng)頁源代碼進(jìn)行了解析,那么接下來我們就可以通過soup.tag來輸出我們需要的內(nèi)容。比方說我想要輸出我們當(dāng)前網(wǎng)頁的title,我們就可以print(soup.title)就可以輸出了,十分簡(jiǎn)單。
當(dāng)然這個(gè)輸出并不是把所有這個(gè)標(biāo)簽的量都返回,她只會(huì)返回第一個(gè)帶有這個(gè)標(biāo)簽的量。如果想要獲得所有的這類標(biāo)簽的內(nèi)容,就可以使用soup.find_all(‘xxx’),就可以找到所有這個(gè)標(biāo)簽的內(nèi)容。
差不多把基礎(chǔ)內(nèi)容說了一下之后呢,現(xiàn)在讓我們進(jìn)入實(shí)戰(zhàn)的環(huán)節(jié)。今天我們爬取的內(nèi)容是一個(gè)叫做笑話大全zol的網(wǎng)站。
首先,在最開始,我們應(yīng)該要做的是引用模塊
import?requestsfrom?bs4?import?beautifulsoup
然后找到咱們?yōu)g覽器的header,header怎么找我就不再多說了啊,在之前的推文已經(jīng)說過了,這里就不重復(fù)說了。寫上
header={'User-Agent':xxxxxx}然后讓我們進(jìn)入http://xiaohua.zol.com.cn/這個(gè)網(wǎng)址。如果你有電腦在身邊的話,可以現(xiàn)在就打開這個(gè)網(wǎng)址進(jìn)入。

進(jìn)入了以后,隨便點(diǎn)擊一個(gè)分類,在本次教學(xué)中我們點(diǎn)擊的是冷笑話這個(gè)分類。好的,點(diǎn)進(jìn)來以后,我們先嘗試著對(duì)這個(gè)網(wǎng)頁進(jìn)行一些爬取操作。
存放咱們的
url=http://xiaohua.zol.com.cn/lengxiaohua/,
然后用requests工具對(duì)這個(gè)網(wǎng)站進(jìn)行請(qǐng)求。
html=requests.get(url,headers=heades)然后對(duì)這個(gè)網(wǎng)頁進(jìn)行解析,
soup=BeautifulSoup(html,'lxml')其實(shí)這個(gè)步驟在之前也已經(jīng)仔細(xì)的說過了,在這里沒有重復(fù)的必要,如果你仍然感到一些困惑,可以回到之前的推文再回顧一下。
這一次爬取的網(wǎng)頁比上一次爬取時(shí)間和距離的網(wǎng)頁更復(fù)雜,所以相關(guān)的操作也會(huì)更加麻煩。
讓我們繼續(xù)往下面看。我們現(xiàn)在已經(jīng)完成了獲取網(wǎng)站源代碼并進(jìn)行解析的過程了,接下來我們就要確定我們所需要爬取的內(nèi)容。
觀察這個(gè)頁面,找出我們所需要內(nèi)容所在的最小單元。仔細(xì)觀察了以后,我們可以知道,我們需要的最小單元是這樣一塊內(nèi)容。
?

現(xiàn)在已經(jīng)明確了我們需要爬取每一個(gè)這樣的方塊里面的相應(yīng)內(nèi)容以后,我們要做的就是找到這一塊東西的位置的源代碼。右鍵點(diǎn)擊空白處,選擇檢查。出現(xiàn)如圖所示的界面。
?

大家肯定會(huì)問,打開這個(gè)做什么呢?
這個(gè)是幫助我們確定我們到時(shí)候需要爬取的內(nèi)容的標(biāo)簽是什么。點(diǎn)擊左上角的箭頭符號(hào),放在我們選取的最小單元上面,我們可以看到如圖所示的東西。

這個(gè)時(shí)候我們就可以發(fā)現(xiàn),其實(shí)每一個(gè)這樣的最小單元對(duì)應(yīng)一個(gè)article-summary這個(gè)標(biāo)簽。
這樣就很明確了,我們所需要的內(nèi)容就在每一個(gè)article-summary里面。我們利用beautifulsoup的特有函數(shù)select選擇器函數(shù)選定這個(gè)內(nèi)容,lis=soup.select(.article-summary),記住一定要在article-summary前面加上‘.’,這是因?yàn)殡m然select選擇器中可以不寫class,但是你必須指明我們需要的內(nèi)容是一個(gè)class,怎么指明呢?就是通過這樣一個(gè)‘.’符號(hào)。
現(xiàn)在為止,我們已經(jīng)獲取了所有的article-summary,并且存到了lis里面.
當(dāng)然還不夠,我們需要的東西并不是lis里面所有的東西,就打個(gè)比方說,這次爬取我的主要目的是笑話標(biāo)題,笑話內(nèi)容和笑話來源。那么我就需要再回到檢查頁面,找到我們所需要內(nèi)容的標(biāo)簽。
下面是標(biāo)題的標(biāo)簽。
?

下面是來源的標(biāo)簽。
?

下面是內(nèi)容的標(biāo)簽。
?

在很多時(shí)候,可能你不知道自己標(biāo)簽選擇正確沒有,我們可以在檢查欄,按下ctrl+f,出現(xiàn)搜索欄,輸入我們當(dāng)前的標(biāo)簽。
如圖所示,既可以幫助我們檢查標(biāo)簽查找是否正確,同時(shí)有利于我們估計(jì)網(wǎng)頁中符合條件的項(xiàng)目數(shù)量。
?

現(xiàn)在已經(jīng)把目標(biāo)的標(biāo)簽找到了以后,我們就可以把內(nèi)容賦給相應(yīng)的變量。如下
title=li.select_one('.article-title a').textsource=li.select('.article-source')[1].textcontent=li.select('.summary-text p')laugh=''for c in content:laugh=laugh+c.text
在這里我們講解一下代碼,為什么第一行我們要使用select_one呢?這是一個(gè)li標(biāo)簽中只有一個(gè)title,我們只需要選擇這一個(gè)就可以了,即選擇第一個(gè)。
.text的作用重新再說一下,因?yàn)槲覀冊(cè)讷@取這個(gè)標(biāo)簽下的東西的時(shí)候,其實(shí)是有很多東西的,還有各種各樣的標(biāo)簽,當(dāng)然標(biāo)簽我們是不要的,怎么辦呢?使用.text就可以了。
第二行的代碼,我們?cè)诤竺婕恿艘粋€(gè)[1],這是為什么呢?因?yàn)槲覀兛瓷厦娴乃阉鹘Y(jié)果,其實(shí)這個(gè)標(biāo)簽里面的內(nèi)容有兩個(gè),第一個(gè)是‘來源:’,第二個(gè)才是我們要的內(nèi)容,因?yàn)閕ndex是從0開始的,所以我們選擇的是[1]。
但是我們還需要進(jìn)行一些別的操作,我們這樣做只是把一個(gè)最小單元里面的內(nèi)容存進(jìn)去了,并不是所有的。那如果我們想要把所有的單元都存進(jìn)去呢?這個(gè)也很簡(jiǎn)單,利用for函數(shù)就可以輕松實(shí)現(xiàn)。
for li in lis:這個(gè)函數(shù)的意思就是依次把lis里面的內(nèi)容取出來賦給li。
其實(shí)到這個(gè)位置,我們已經(jīng)完成了當(dāng)前頁面的爬取,各位看客老爺們可以試著輸出一下我們這幾個(gè)變量,看看是不是爬取成功。那么請(qǐng)?jiān)诒WC上面內(nèi)容已經(jīng)完成的前提下,我們繼續(xù)下面的內(nèi)容。
因?yàn)槭桥廊?nèi)容嘛,我們當(dāng)然不會(huì)只爬這一個(gè)頁面,這肯定是遠(yuǎn)遠(yuǎn)不夠的。那么怎么辦呢?我們?cè)趺床拍芘廊《鄠€(gè)頁面呢?
對(duì),沒錯(cuò),就是不斷的進(jìn)行換頁操作就可以了。那么怎么進(jìn)行換頁呢?這就需要我們觀察頁面的規(guī)律了,下面我們一起來探究一下我們正在爬取的網(wǎng)址的規(guī)律。
http://xiaohua.zol.com.cn/lengxiaohua/2.htmlhttp://xiaohua.zol.com.cn/lengxiaohua/3.html……
其實(shí)這個(gè)網(wǎng)頁是相當(dāng)有規(guī)律的,我們可以很輕松發(fā)現(xiàn)他這個(gè)網(wǎng)址其實(shí)就是
http://xiaohua.zol.com.cn/lengxiaohua/{}.html這樣子,對(duì)吧?這樣我們是不是就可以用到for函數(shù)和format()函數(shù)來進(jìn)行我們的翻頁操作了?是的!讓我們看一看代碼。
for?i?in?range(1,10)#這里的意思是生成1-9的整數(shù),在這里我們假設(shè)爬取1-9面的內(nèi)容for i in range(1,5):url='http://xiaohua.zol.com.cn/lengxiaohua/{}.html'.format(str(i))
在這里一定要注意,要用強(qiáng)制轉(zhuǎn)換str(),為什么呢?這是因?yàn)槲覀兙W(wǎng)址里面的數(shù)字類型其實(shí)是字符串型的。
現(xiàn)在我們已經(jīng)完成了翻頁功能,也完成了相應(yīng)頁面的爬取功能,但是還是不夠完美。主要還有以下幾個(gè)問題.
是不是最終輸出的結(jié)果有很多空白?有很多其他字符?是不是來源那個(gè)位置有的時(shí)候會(huì)出錯(cuò)?
別急,我們一個(gè)一個(gè)來解決。為了使我們的輸出結(jié)果更加精簡(jiǎn)和規(guī)范。我們可以使用strip函數(shù)和replace函數(shù)。
strip() 方法用于移除字符串頭尾指定的字符(默認(rèn)為空格或換行符)或字符序列。replace()函數(shù)用于去除其他位置的空白。讓我們?cè)诖a里面看看具體怎么寫。
laugh=laugh.strip().replace(' ','')#strip()刪除開頭和結(jié)尾的字符replace函數(shù)的使用方式是replace(a,b),意思是把文本中的a用b代替。解決了這個(gè)問題之后,我們來解決來源出錯(cuò)的問題。
我們來分析一下為什么有的時(shí)候來源這個(gè)位置會(huì)出錯(cuò),我們回到原來的頁面觀察來源那個(gè)位置,我們可以看到有很多笑話都是沒有來源的,那么這個(gè)時(shí)候我們其實(shí)啥都沒有爬取到,所有就會(huì)出錯(cuò)。
那么這個(gè)時(shí)候怎么辦呢?我們只需要進(jìn)行一個(gè)簡(jiǎn)單的判斷。
try:source=li.select('.article-source')[1].textexcept:source='暫無來源'
這是什么意思呢?意思就是如果try里面的內(nèi)容沒有出錯(cuò),我們就執(zhí)行try里面的內(nèi)容,如果出錯(cuò)了,我們就執(zhí)行except里面的內(nèi)容。
但是到目前為止,我們還是有問題的,雖然我們已經(jīng)完成了整個(gè)的爬取,但是我們還沒有把他們存進(jìn)來呀。如果我們要存進(jìn)來怎么辦呢?這就涉及到python的文件操作了。在這里呢,小瑋就不多說文件的操作了。大家看看代碼應(yīng)該可以明白的!
下面給出所有的代碼。
import requestsfrom bs4 import BeautifulSoupheaders={"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.116 Safari/537.36"}for i in range(1,5):fw = open('./record{}.txt'.format(i),'w',encoding='UTF-8')fw.write('page{}\n'.format(i))print('page{}'.format(i))url='http://xiaohua.zol.com.cn/lengxiaohua/{}.html'.format(str(i))html=requests.get(url,headers=headers)soup=BeautifulSoup(html.text,"lxml")lis=soup.select('.article-summary')for li in lis:title=li.select_one('.article-title a').texttry:source=li.select('.article-source')[1].textexcept:source='暫無來源'content=li.select('.summary-text p')laugh=''for c in content:laugh=laugh+c.textlaugh=laugh.strip().replace(' ','')#strip()刪除開頭和結(jié)尾的字符print(title,source)print(laugh)print('-'*30)fw.write('title:{}\nsource:{}\nlaugh:{}\n'.format(title,source,laugh))fw.write('-'*30+'\n')fw.close()
其實(shí)到目前位置,做一個(gè)比較簡(jiǎn)單的爬蟲項(xiàng)目已經(jīng)足夠了,但是我們會(huì)在后面介紹更加專業(yè)適用于大項(xiàng)目的爬蟲方法,讓我們一起期待下一期推文吧!

