前言
本文的文字及圖片來(lái)源于網(wǎng)絡(luò),僅供學(xué)習(xí)、交流使用,不具有任何商業(yè)用途,如有問(wèn)題請(qǐng)及時(shí)聯(lián)系我們以作處理。
PS:如有需要Python學(xué)習(xí)資料的小伙伴可以加點(diǎn)擊下方鏈接自行獲取
python免費(fèi)學(xué)習(xí)資料以及群交流解答點(diǎn)擊即可加入
大家好,今天我們來(lái)聊聊Python爬蟲(chóng)的基礎(chǔ)操作,反正我是這樣入門了,哈哈。
其實(shí),一開(kāi)始學(xué)python的時(shí)候,我是沖著數(shù)據(jù)處理分析去了,那個(gè)pandas什么的。后來(lái),發(fā)現(xiàn)爬蟲(chóng)挺好玩,可以解決純手工采集網(wǎng)上數(shù)據(jù)的繁瑣問(wèn)題,比如我用的比較多的爬取taptap某游戲評(píng)價(jià)內(nèi)容、某視頻網(wǎng)站某劇的彈幕、某評(píng)的店鋪信息、某牙主播信息等等。
關(guān)于爬蟲(chóng),我也只會(huì)一些比較基礎(chǔ)的操作,不過(guò)個(gè)人經(jīng)驗(yàn)上感覺(jué)這些基礎(chǔ)基本可以滿足比較常規(guī)化的需求。對(duì)于進(jìn)階的爬蟲(chóng)技巧,大家在了解熟悉爬蟲(chóng)基礎(chǔ)后自然會(huì)有進(jìn)階學(xué)習(xí)的思路與途徑。
接下來(lái),我們進(jìn)入主題吧~
0.爬蟲(chóng)基礎(chǔ)流程
把爬蟲(chóng)的過(guò)程模塊化,基本上可以歸納為以下幾個(gè)步驟:
- [√] 分析網(wǎng)頁(yè)URL:打開(kāi)你想要爬取數(shù)據(jù)的網(wǎng)站,然后尋找真實(shí)的頁(yè)面數(shù)據(jù)URL地址;
- [√] 請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù):模擬請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù),這里我們介紹requests庫(kù)的使用;
- [√] 解析網(wǎng)頁(yè)數(shù)據(jù):根據(jù)請(qǐng)求獲得的網(wǎng)頁(yè)數(shù)據(jù)我們用不同的方式解析成我們需要用的數(shù)據(jù)(如果網(wǎng)頁(yè)數(shù)據(jù)為html源碼,我們用Beautiful Soup、xpath和re正則表達(dá)式三種解析;若網(wǎng)頁(yè)數(shù)據(jù)為json格式,我們可以直接用字典列表等基礎(chǔ)知識(shí)處理)
- [√] 存儲(chǔ)網(wǎng)頁(yè)數(shù)據(jù):一般來(lái)說(shuō),解析后的數(shù)據(jù)是比較結(jié)構(gòu)化的,可以保存為txt、csv、json或excel等文本,亦或者可以存儲(chǔ)在數(shù)據(jù)庫(kù)如MySql、MongoDB或SqlLite中。
1.分析網(wǎng)頁(yè)URL
當(dāng)我們有一個(gè)目標(biāo)網(wǎng)站,有時(shí)候會(huì)發(fā)現(xiàn)對(duì)于靜態(tài)網(wǎng)頁(yè),我們只需要把網(wǎng)頁(yè)地址欄中的URL傳到get請(qǐng)求中就可以直接取到網(wǎng)頁(yè)的數(shù)據(jù)。但如果這是動(dòng)態(tài)網(wǎng)頁(yè),我們便無(wú)法通過(guò)簡(jiǎn)單的傳遞網(wǎng)頁(yè)地址欄的URL給get請(qǐng)求來(lái)獲取網(wǎng)頁(yè)數(shù)據(jù),往往這個(gè)時(shí)候,我們進(jìn)行翻頁(yè)的時(shí)候還會(huì)發(fā)現(xiàn)網(wǎng)頁(yè)地址欄中的URL是不會(huì)發(fā)生變化的。
接下來(lái),我們來(lái)分別介紹這兩種情況下如何獲取真實(shí)的頁(yè)面數(shù)據(jù)URL地址。
1.1 靜態(tài)網(wǎng)頁(yè)
對(duì)于靜態(tài)網(wǎng)頁(yè)來(lái)說(shuō),其實(shí)網(wǎng)頁(yè)地址欄中的URL就是我們需要的。
以 貝殼二手房網(wǎng)(https://bj.ke.com/ershoufang/) 為例,我們可以看到進(jìn)行翻頁(yè)(如到第2頁(yè))的時(shí)候網(wǎng)頁(yè)地址欄的URL變?yōu)榱?https://bj.ke.com/ershoufang/pg2/)。類型這種情況,多半就是靜態(tài)網(wǎng)頁(yè)了,而且翻頁(yè)的URL規(guī)律十分明顯。
1.2 動(dòng)態(tài)網(wǎng)頁(yè)
對(duì)于動(dòng)態(tài)網(wǎng)頁(yè)來(lái)說(shuō),我們一般可以通過(guò)以下幾個(gè)步驟找到真實(shí)URL地址:
1.需要按“F12”進(jìn)入到瀏覽器的開(kāi)發(fā)者模式;
2.點(diǎn)擊“Network”—>XHR或JS或者你全部查找看;
3.進(jìn)行翻頁(yè)(可能是點(diǎn)擊下一頁(yè)或者下滑加載更多);
4.觀察第2步中name模塊的內(nèi)容變化,尋找。
以 虎牙星秀區(qū)(https://www.huya.com/g/xingxiu) 為例,我們可以看到進(jìn)行翻頁(yè)(如到第2頁(yè))的時(shí)候網(wǎng)頁(yè)地址欄的URL沒(méi)有發(fā)生任何改變。
為了便于找到真實(shí)的URL地址,我們可以在開(kāi)發(fā)者模式中找以下截圖中的幾點(diǎn),preview是預(yù)覽結(jié)果,可以便于我們進(jìn)行匹配定位具體的Name。
當(dāng)我們定位到具體的Name后,右側(cè)選擇Headers可以查看到請(qǐng)求網(wǎng)頁(yè)需要的相關(guān)參數(shù)信息,而且比較好擬清其變化規(guī)律。以虎牙星秀為例,其真實(shí)URL地址及變化規(guī)律如下:

2.請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù)
當(dāng)我們確定了真實(shí)數(shù)據(jù)的URL后,這里便可以用requests的get或post方法進(jìn)行請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù)。
關(guān)于requests庫(kù)的更多使用方式,大家可以前往(https://requests.readthedocs.io/zh_CN/latest/)查看。
2.1 發(fā)送get請(qǐng)求
In [1]: import requests
In [2]: url = 'https://bj.ke.com/ershoufang/'
In [3]: r = requests.get(url)
In [4]: type(r)
Out[4]: requests.models.Response
In [5]: r.status_code
Out[5]: 200
我們得到的是一個(gè)Response對(duì)象,如果我們想要獲取網(wǎng)頁(yè)數(shù)據(jù),可以使用text或content屬性來(lái)獲取,另外如果獲取的網(wǎng)頁(yè)數(shù)據(jù)是json格式的則可以使用Requests 中內(nèi)置的 json()解碼器方法,助你處理json 數(shù)據(jù)。
- r.text:字符串類型的數(shù)據(jù),一般網(wǎng)頁(yè)數(shù)據(jù)為文本類用此屬性
- r.content:二進(jìn)制類型的數(shù)據(jù),一般網(wǎng)頁(yè)數(shù)據(jù)為視頻或者圖片時(shí)用此屬性
- r.json():json數(shù)據(jù)解碼,一般網(wǎng)頁(yè)數(shù)據(jù)為json格式時(shí)用此方法
對(duì)于一些動(dòng)態(tài)網(wǎng)頁(yè),請(qǐng)求的網(wǎng)址是基礎(chǔ)url和關(guān)鍵字參數(shù)組合而成,這個(gè)時(shí)候我們可以使用 params 關(guān)鍵字參數(shù),以一個(gè)字符串字典來(lái)提供這些參數(shù)。
In [6]: url = 'https://www.huya.com/cache.php'
...: parames = {
...: 'm': 'LiveList',
...: 'do': 'getLiveListByPage',
...: 'gameId': 1663,
...: 'tagAll': 0,
...: 'page': 2, # 翻頁(yè)變化的就是這個(gè)參數(shù)
...: }
...:
...: r = requests.get(url, params=parames)
In [7]: r.url
Out[7]: 'https://www.huya.com/cache.php?m=LiveList&do=getLiveListByPage&gameId=1663&tagAll=0&page=2'
2.2 發(fā)送post請(qǐng)求
通常,你想要發(fā)送一些編碼為表單形式的數(shù)據(jù)——非常像一個(gè) HTML 表單。要實(shí)現(xiàn)這個(gè),只需簡(jiǎn)單地傳遞一個(gè)字典給 data 參數(shù)。你的數(shù)據(jù)字典在發(fā)出請(qǐng)求時(shí)會(huì)自動(dòng)編碼為表單形式:
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
很多時(shí)候你想要發(fā)送的數(shù)據(jù)并非編碼為表單形式的。如果你傳遞一個(gè) string 而不是一個(gè) dict,那么數(shù)據(jù)會(huì)被直接發(fā)布出去。
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, data=json.dumps(payload))
此處除了可以自行對(duì) dict 進(jìn)行編碼,你還可以使用 json 參數(shù)直接傳遞,然后它就會(huì)被自動(dòng)編碼。
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, json=payload)
2.3 定制請(qǐng)求頭
在模擬請(qǐng)求時(shí),如果不設(shè)置請(qǐng)求頭的話是比較容易被網(wǎng)站發(fā)現(xiàn)是來(lái)自爬蟲(chóng)腳本,一些網(wǎng)站會(huì)對(duì)這種模擬請(qǐng)求進(jìn)行拒絕。因此我們可以簡(jiǎn)單設(shè)置一下請(qǐng)求頭做偽裝,一般是設(shè)置瀏覽器。
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
}
r = requests.get(url, headers=headers)
其實(shí),對(duì)于請(qǐng)求頭還可以設(shè)置很多參數(shù),具體大家可以在實(shí)際爬蟲(chóng)過(guò)程中在開(kāi)發(fā)者模式看看里面的請(qǐng)求頭模塊進(jìn)行分析處理。
2.4 響應(yīng)碼
我們?cè)?2.1 中看到獲取響應(yīng)碼的是通過(guò) r.status_code屬性,一般來(lái)說(shuō)如果 返回 數(shù)字 200,則表示成功獲取了網(wǎng)頁(yè)數(shù)據(jù)。
響應(yīng)碼分為五種類型,由它們的第一位數(shù)字表示:1xx:信息,請(qǐng)求收到,繼續(xù)處理 2xx:成功,行為被成功地接受、理解和采納 3xx:重定向,為了完成請(qǐng)求,必須進(jìn)一步執(zhí)行的動(dòng)作 4xx:客戶端錯(cuò)誤,請(qǐng)求包含語(yǔ)法錯(cuò)誤或者請(qǐng)求無(wú)法實(shí)現(xiàn) 5xx:服務(wù)器錯(cuò)誤,服務(wù)器不能實(shí)現(xiàn)一種明顯無(wú)效的請(qǐng)求
3.解析數(shù)據(jù)
上面有提到我們請(qǐng)求的網(wǎng)頁(yè)數(shù)據(jù)有Html源碼文本或者是json字符串文本,兩者的解析方式不同。以下我們分別進(jìn)行簡(jiǎn)單說(shuō)明,大家在實(shí)際操作中視情況而定即可。
3.1 網(wǎng)頁(yè)html文本解析
對(duì)于網(wǎng)頁(yè)html文本來(lái)說(shuō),這里介紹Beautiful Soup、xpath和re正則表達(dá)式三種解析方法。
以貝殼二手房最新房源(https://bj.ke.com/ershoufang/co32/)為例,其html源碼如下,我們通過(guò)get請(qǐng)求后的數(shù)據(jù)進(jìn)行解析。
3.1.1 Beautiful Soup
關(guān)于Beautiful Soup庫(kù)的更多使用方式,大家可以前往查看(https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/)
首先安裝pip install beautifulsoup4。
我們將網(wǎng)頁(yè)html文本內(nèi)容r.text當(dāng)作第一個(gè)參數(shù)傳給BeautifulSoup對(duì)象,該對(duì)象的第二個(gè)參數(shù)為解析器的類型(這里使用lxml),此時(shí)就完成了BeaufulSoup對(duì)象的初始化。然后,將這個(gè)對(duì)象賦值給soup變量。
from bs4 import BeautifulSoup
import requests
url = 'https://bj.ke.com/ershoufang/co32/'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
獲取房源的名稱的代碼如下:
# 獲取全部房源 所在的節(jié)點(diǎn)
sellList = soup.find(class_="sellListContent")
# 獲取全部房源節(jié)點(diǎn)列表
lis = sellList.find_all('li',class_="clear")
# 選取第一個(gè)房源節(jié)點(diǎn)
div = lis[0].find('div',class_="info clear")
# 采集房源名稱
title = div.find('div',class_="title")
print(title.text)
明春西園 2室1廳 南 北
3.1.2 xpath
XPath,全稱 XML Path Language,即 XML 路徑語(yǔ)言,它是一門在 XML 文檔中查找信息的語(yǔ)言。
首先安裝lxmlpip install lxml。
常見(jiàn)的規(guī)則如下:

首先導(dǎo)入 lxml 庫(kù)的 etree 模塊,然后聲明一段 HTML 文本,調(diào)用 HTML 類進(jìn)行初始化,成功構(gòu)造一個(gè) XPath 解析對(duì)象。
from lxml import etree
import requests
url = 'https://bj.ke.com/ershoufang/co32/'
r = requests.get(url)
html = etree.HTML(r.text)
通過(guò)copy獲取的xpath://*[@id="beike"]/div[1]/div[4]/div[1]/div[4]/ul/li[1]/div/div[1]/a
# 獲取 全部房源所在節(jié)點(diǎn) ul,根據(jù)屬性匹配精準(zhǔn)查找
ul = html.xpath('.//ul[@class="sellListContent"]')[0]
# 獲取房源列表
lis = ul.xpath('.//li[@class="clear"]')
# 選取第一個(gè)房源節(jié)點(diǎn)
li = lis[0]
# 獲取其房源名稱
li.xpath('./div/div[1]/a/text()')
['明春西園 2室1廳 南 北']
3.1.3 re正則
關(guān)于re正則解析網(wǎng)頁(yè)html大家也可以前往查看此前發(fā)布的文章《對(duì)著爬蟲(chóng)網(wǎng)頁(yè)HTML學(xué)習(xí)Python正則表達(dá)式re》。
# 找到房源名稱所在的前后字符,然后組成正則表達(dá)式
re.findall(r'<a class="VIEWDATA CLICKDATA maidian-detail" title="(.*?)"',r.text,re.S)[0]
'明春西園 2室1廳 南 北'
3.2 json文本解析
在requests提供了r.json(),可以用于json數(shù)據(jù)解碼,一般網(wǎng)頁(yè)數(shù)據(jù)為json格式時(shí)用此方法。除此之外,還可以通過(guò)json.loads()和eval()方法進(jìn)行處理。

url = 'https://www.huya.com/cache.php'
parames = {
'm': 'LiveList',
'do': 'getLiveListByPage',
'gameId': 1663,
'tagAll': 0,
'page': 2, # 翻頁(yè)變化的就是這個(gè)參數(shù)
}
r = requests.get(url, params=parames)
data = r.json()
type(data)
dict
如此解析后得到的數(shù)據(jù)就是字典,然后我們?cè)诳纯醋值渲心男┳侄问俏覀冃枰?,取出即可?/p>
4.存儲(chǔ)數(shù)據(jù)
當(dāng)我們獲取了到想要的數(shù)據(jù)后,便可以寫入本地了。
對(duì)于文本類數(shù)據(jù),可以通過(guò)csv模塊或pandas模塊進(jìn)行寫入到本地csv文件或excel文件;同時(shí)也可以用pymysql模塊寫入到數(shù)據(jù)庫(kù)或者sqlite寫入到本地?cái)?shù)據(jù)庫(kù)。
對(duì)于視頻或者圖片,可以open一個(gè)文件然后寫入二進(jìn)制內(nèi)容后保存本地亦可。
關(guān)于存儲(chǔ)數(shù)據(jù)大家可以結(jié)合實(shí)際案例進(jìn)行學(xué)習(xí)。