圖解爬蟲,用幾個(gè)最簡(jiǎn)單的例子帶你入門Python爬蟲
一、前言
爬蟲一直是Python的一大應(yīng)用場(chǎng)景,差不多每門語(yǔ)言都可以寫爬蟲,但是程序員們卻獨(dú)愛(ài)Python。之所以偏愛(ài)Python就是因?yàn)樗?jiǎn)潔的語(yǔ)法,我們使用Python可以很簡(jiǎn)單的寫出一個(gè)爬蟲程序。本篇博客將以Python語(yǔ)言,用幾個(gè)非常簡(jiǎn)單的例子帶大家入門Python爬蟲。
二、網(wǎng)絡(luò)爬蟲
如果把我們的因特網(wǎng)比作一張復(fù)雜的蜘蛛網(wǎng)的話,那我們的爬蟲就是一個(gè)蜘,我們可以讓這個(gè)蜘蛛在網(wǎng)上任意爬行,在網(wǎng)中尋找對(duì)我們有價(jià)值的“獵物”。
首先我們的網(wǎng)絡(luò)爬蟲是建立在網(wǎng)絡(luò)之上的,所以網(wǎng)絡(luò)爬蟲的基礎(chǔ)就是網(wǎng)絡(luò)請(qǐng)求。在我們?nèi)粘I钪?,我們?huì)使用瀏覽器瀏覽網(wǎng)頁(yè),我們?cè)诰W(wǎng)址欄輸入一個(gè)網(wǎng)址,點(diǎn)擊回車在幾秒時(shí)間后就能顯示一個(gè)網(wǎng)頁(yè)。
我們表面上是點(diǎn)擊了幾個(gè)按鈕,實(shí)際上瀏覽器幫我們完成了一些了的操作,具體操作有如下幾個(gè):
1.向服務(wù)器發(fā)送網(wǎng)絡(luò)請(qǐng)求2.瀏覽器接收并處理你的請(qǐng)求3.瀏覽器返回你需要的數(shù)據(jù)4.瀏覽器解析數(shù)據(jù),并以網(wǎng)頁(yè)的形式展現(xiàn)出來(lái)
我們可以將上面的過(guò)程類比我們的日常購(gòu)物:
1.和老板說(shuō)我要杯珍珠奶茶2.老板在店里看看有沒(méi)有你要的東西3.老板拿出做奶茶的材料4.老板將材料做成奶茶并給你
上面買奶茶的例子雖然有些不恰當(dāng)?shù)牡胤?,但是我覺(jué)得已經(jīng)能很好的解釋什么是網(wǎng)絡(luò)請(qǐng)求了。
在知道網(wǎng)絡(luò)請(qǐng)求是什么之后,我們就可以來(lái)了解一下什么是爬蟲了。實(shí)際上爬蟲也是網(wǎng)絡(luò)請(qǐng)求,通常情況下我們通過(guò)瀏覽器,而我們的爬蟲則是通過(guò)程序來(lái)模擬網(wǎng)絡(luò)請(qǐng)求這一過(guò)程。但是這種基礎(chǔ)的網(wǎng)絡(luò)請(qǐng)求還算不上是爬蟲,爬蟲通常都是有目的的。比如我想寫一個(gè)爬取美女圖片,我們就需要對(duì)我們請(qǐng)求到的數(shù)據(jù)進(jìn)行一些篩選、匹配,找到對(duì)我們有價(jià)值的數(shù)據(jù)。而這一從網(wǎng)絡(luò)請(qǐng)求到數(shù)據(jù)爬取這整個(gè)過(guò)程才是一個(gè)完整的爬蟲。
有些時(shí)候網(wǎng)站的反爬蟲做的比較差,我們可以直接在瀏覽器中找到它的API,我們通過(guò)API可以直接獲取我們需要的數(shù)據(jù),這種相比就要簡(jiǎn)單許多。
三、簡(jiǎn)單的爬蟲
簡(jiǎn)單的爬蟲就是單純的網(wǎng)絡(luò)請(qǐng)求,也可以對(duì)請(qǐng)求的數(shù)據(jù)進(jìn)行一些簡(jiǎn)單的處理。Python提供了原生的網(wǎng)絡(luò)請(qǐng)求模塊urllib,還有封裝版的requests模塊。相比直線requests要更加方便好用,所以本文使用requests進(jìn)行網(wǎng)絡(luò)請(qǐng)求。
3.1、爬取一個(gè)簡(jiǎn)單的網(wǎng)頁(yè)
在我們發(fā)送請(qǐng)求的時(shí)候,返回的數(shù)據(jù)多種多樣,有HTML代碼、json數(shù)據(jù)、xml數(shù)據(jù),還有二進(jìn)制流。我們先以百度首頁(yè)為例,進(jìn)行爬?。?/p>import requests# 以get方法發(fā)送請(qǐng)求,返回?cái)?shù)據(jù)response = requests.get('http://www.baidu.com')# 以二進(jìn)制寫入的方式打開一個(gè)文件f = open('index.html', 'wb')# 將響應(yīng)的字節(jié)流寫入文件f.write(response.content)# 關(guān)閉文件f.close()
下面我們看看爬取的網(wǎng)站打開是什么樣子的:

這就是我們熟悉的百度頁(yè)面,上面看起來(lái)還是比較完整的。我們?cè)僖云渌W(wǎng)站為例,可以就是不同的效果了,我們以CSDN為例:
可以看到頁(yè)面的布局已經(jīng)完全亂了,而且也丟失了很多東西。學(xué)過(guò)前端的都知道,一個(gè)網(wǎng)頁(yè)是由html頁(yè)面還有許多靜態(tài)文件構(gòu)成的,而我們爬取的時(shí)候只是將HTML代碼爬取下來(lái),HTML中鏈接的靜態(tài)資源,像css樣式和圖片文件等都沒(méi)有爬取,所以會(huì)看到這種很奇怪的頁(yè)面。
3.2、爬取網(wǎng)頁(yè)中的圖片
首先我們需要明確一點(diǎn),在爬取一些簡(jiǎn)單的網(wǎng)頁(yè)時(shí),我們爬取圖片或者視頻就是匹配出網(wǎng)頁(yè)中包含的url信息,也就是我們說(shuō)的網(wǎng)址。然后我們通過(guò)這個(gè)具體的url進(jìn)行圖片的下載,這樣就完成了圖片的爬取。我們有如下url:https://img-blog.csdnimg.cn/2020051614361339.jpg,我們將這個(gè)圖片url來(lái)演示下載圖片的代碼:
import requests# 準(zhǔn)備urlurl = 'https://img-blog.csdnimg.cn/2020051614361339.jpg'# 發(fā)送get請(qǐng)求response = requests.get(url)# 以二進(jìn)制寫入的方式打開圖片文件f = open('test.jpg', 'wb')# 將文件流寫入圖片f.write(response.content)# 關(guān)閉文件f.close()
可以看到,代碼和上面網(wǎng)頁(yè)爬取是一樣的,只是打開的文件后綴為jpg。實(shí)際上圖片、視頻、音頻這種文件用二進(jìn)制寫入的方式比較恰當(dāng),而對(duì)應(yīng)html代碼這種文本信息,我們通常直接獲取它的文本,獲取方式為response.text,在我們獲取文本后就可以匹配其中的圖片url了。我們以下列http://topit.pro為例:
import reimport requests# 要爬取的網(wǎng)站url = 'http://topit.pro'# 獲取網(wǎng)頁(yè)源碼response = requests.get(url)# 匹配源碼中的圖片資源results = re.findall(", response.text)# 用于命名的變量name = 0# 遍歷結(jié)果for result in results:# 在源碼中分析出圖片資源寫的是絕對(duì)路徑,所以完整url是主站+絕對(duì)路徑img_url = url+result# 下載圖片f = open(str(name) + '.jpg', 'wb')f.write(requests.get(img_url).content)f.close()name += 1
上面我們就完成了一個(gè)網(wǎng)站的爬取。在匹配時(shí)我們用到了正則表達(dá)式,因?yàn)檎齽t的內(nèi)容比較多,在這里就不展開了,有興趣的讀者可以自己去了解一下,這里只說(shuō)一個(gè)簡(jiǎn)單的。Python使用正則是通過(guò)re模塊實(shí)現(xiàn)的,可以調(diào)用findall匹配文本中所有符合要求的字符串。該函數(shù)傳入兩個(gè)參數(shù),第一個(gè)為正則表達(dá)式,第二個(gè)為要匹配的字符串,對(duì)正則不了解的話只需要知道我們使用該正則可以將圖片中的src內(nèi)容拿出來(lái)。
四、使用BeautifulSoup解析HTML
BeautifulSoup是一個(gè)用來(lái)分析XML文件和HTML文件的模塊,我們前面使用正則表達(dá)式進(jìn)行模式匹配,但自己寫正則表達(dá)式是一個(gè)比較繁瑣的過(guò)程,而且容易出錯(cuò)。如果我們把解析工作交給BeautifulSoup會(huì)大大減少我們的工作量,在使用之前我們先安裝。
4.1、BeautifulSoup的安裝和簡(jiǎn)單使用
我們直接使用pip安裝:
pip install beautifulsoup4模塊的導(dǎo)入如下:
from bs4 import BeautifulSoup下面我們就來(lái)看看BeautifulSoup的使用,我們用下面HTML文件測(cè)試:
<html lang="en"><head><meta charset="UTF-8"><title>Titletitle>head><body><img class="test" src="1.jpg"><img class="test" src="2.jpg"><img class="test" src="3.jpg"><img class="test" src="4.jpg"><img class="test" src="5.jpg"><img class="test" src="6.jpg"><img class="test" src="7.jpg"><img class="test" src="8.jpg">body>html>
上面是一個(gè)非常簡(jiǎn)答的html頁(yè)面,body內(nèi)包含了8個(gè)img標(biāo)簽,現(xiàn)在我們需要獲取它們的src,代碼如下:
from bs4 import BeautifulSoup# 讀取html文件f = open('test.html', 'r')str = f.read()f.close()# 創(chuàng)建BeautifulSoup對(duì)象,第一個(gè)參數(shù)為解析的字符串,第二個(gè)參數(shù)為解析器soup = BeautifulSoup(str, 'html.parser')# 匹配內(nèi)容,第一個(gè)為標(biāo)簽名稱,第二個(gè)為限定屬性,下面表示匹配class為test的img標(biāo)簽img_list = soup.find_all('img', {'class':'test'})# 遍歷標(biāo)簽for img in img_list:# 獲取img標(biāo)簽的src值src = img['src']print(src)
解析結(jié)果如下:
1.jpg2.jpg3.jpg4.jpg5.jpg6.jpg7.jpg8.jpg
正好就是我們需要的內(nèi)容。
4.2、BeautifulSoup實(shí)戰(zhàn)
我們可以針對(duì)網(wǎng)頁(yè)進(jìn)行解析,解析出其中的src,這樣我們就可以進(jìn)行圖片等資源文件的爬取。下面我們用梨視頻為例,進(jìn)行視頻的爬取。主頁(yè)網(wǎng)址如下:https://www.pearvideo.com/。我們右鍵檢查可以看到如下頁(yè)面:
我們可以先點(diǎn)擊1處,然后選擇需要爬取的位置,比如2,在右邊就會(huì)跳轉(zhuǎn)到相應(yīng)的位置。我們可以看到外層套了一個(gè)a標(biāo)簽,在我們實(shí)際操作是發(fā)現(xiàn)點(diǎn)擊2的位置跳轉(zhuǎn)了網(wǎng)頁(yè),分析出來(lái)跳轉(zhuǎn)的網(wǎng)頁(yè)應(yīng)該就是a標(biāo)簽中的herf值。因?yàn)閔erf值是以/開頭的,所以完整的URL應(yīng)該是主站+href值,知道了這個(gè)我們就可以進(jìn)行下一步的操作了,我們先從主站爬取跳轉(zhuǎn)的url:
import requestsfrom bs4 import BeautifulSoup# 主站url = 'https://www.pearvideo.com/'# 模擬瀏覽器訪問(wèn)headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}# 發(fā)送請(qǐng)求response = requests.get(url, headers=headers)# 獲取BeautifulSoup對(duì)象soup = BeautifulSoup(response.text, 'html.parser')# 解析出符合要求的a標(biāo)簽video_list = soup.find_all('a', {'class':'actwapslide-link'})# 遍歷標(biāo)簽for video in video_list:# 獲取herf并組拼成完整的urlvideo_url = video['href']video_url = url + video_urlprint(video_url)
輸出結(jié)果如下:
https://www.pearvideo.com/video_1674906https://www.pearvideo.com/video_1674921https://www.pearvideo.com/video_1674905https://www.pearvideo.com/video_1641829https://www.pearvideo.com/video_1674822
我們只爬取一個(gè)就好了,我們進(jìn)入第一個(gè)網(wǎng)址查看源碼,發(fā)現(xiàn)了這么一句:
var contId="1674906",liveStatusUrl="liveStatus.jsp",liveSta="",playSta="1",autoPlay=!1,isLiving=!1,isVrVideo=!1,hdflvUrl="",sdflvUrl="",hdUrl="",sdUrl="",ldUrl="",srcUrl="https://video.pearvideo.com/mp4/adshort/20200517/cont-1674906-15146856_adpkg-ad_hd.mp4",vdoUrl=srcUrl,skinRes="http://www.pearvideo.com/domain/skin",videoCDN="http://video.pearvideo.com";其中srcUrl就包含了視頻文件的網(wǎng)站,但是我們肯定不能自己一個(gè)網(wǎng)頁(yè)一個(gè)網(wǎng)頁(yè)自己找,我們可以使用正則表達(dá)式:
import re# 獲取單個(gè)視頻網(wǎng)頁(yè)的源碼response = requests.get(video_url)# 匹配視頻網(wǎng)址results = re.findall('srcUrl="(.*?)"', response.text)# 輸出結(jié)果print(results)
結(jié)果如下:
['https://video.pearvideo.com/mp4/adshort/20200516/cont-1674822-14379289-191950_adpkg-ad_hd.mp4']然后我們就可以下載這個(gè)視頻了:
with open('result.mp4', 'wb') as f:f.write(requests.get(results[0], headers=headers).content)
完整代碼如下:
import reimport requestsfrom bs4 import BeautifulSoup# 主站url = 'https://www.pearvideo.com/'# 模擬瀏覽器訪問(wèn)headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}# 發(fā)送請(qǐng)求response = requests.get(url, headers=headers)# 獲取BeautifulSoup對(duì)象soup = BeautifulSoup(response.text, 'html.parser')# 解析出符合要求的a標(biāo)簽video_list = soup.find_all('a', {'class':'actwapslide-link'})# 遍歷標(biāo)簽video_url = video_list[0]['href']response = requests.get(video_url)results = re.findall('srcUrl="(.*?)"', response.text)with open('result.mp4', 'wb') as f:f.write(requests.get(results[0], headers=headers).content)
到此我們就從簡(jiǎn)單的網(wǎng)頁(yè)到圖片再到視頻實(shí)現(xiàn)了幾個(gè)不同的爬蟲。

推薦閱讀
歡迎長(zhǎng)按掃碼關(guān)注「數(shù)據(jù)管道」
