一些關(guān)于自己學(xué)習(xí)Python的經(jīng)歷的內(nèi)容,遇到的問(wèn)題和思考等,方便以后查詢(xún)和復(fù)習(xí)。
聲明:本人學(xué)習(xí)是在扇貝編程通過(guò)網(wǎng)絡(luò)學(xué)習(xí)的,相關(guān)的知識(shí)、案例來(lái)源于扇貝編程。如果使用請(qǐng)說(shuō)明來(lái)源。
第1關(guān):爬蟲(chóng)初體驗(yàn)
什么是網(wǎng)絡(luò)爬蟲(chóng)
網(wǎng)絡(luò)爬蟲(chóng),簡(jiǎn)稱(chēng)爬蟲(chóng),是一種按照一定的規(guī)則,自動(dòng)地抓取互聯(lián)網(wǎng)信息的程序或者腳本。
爬蟲(chóng)做的事情其實(shí)和蜘蛛是類(lèi)似的,所以網(wǎng)絡(luò)爬蟲(chóng)也被稱(chēng)為網(wǎng)絡(luò)蜘蛛(spider)。蜘蛛在蜘蛛網(wǎng)上爬來(lái)爬去,把觸手伸到蜘蛛網(wǎng)獲取食物,而網(wǎng)絡(luò)爬蟲(chóng)則是在互聯(lián)網(wǎng)上爬來(lái)爬去,爬取我們需要的數(shù)據(jù)。
搜索引擎本質(zhì)上就是爬蟲(chóng),搜索引擎將互聯(lián)網(wǎng)上的網(wǎng)頁(yè)都爬取并存儲(chǔ)起來(lái)。當(dāng)我們搜索的時(shí)候,搜索引擎就從自己存儲(chǔ)的網(wǎng)頁(yè)里找到我們需要的結(jié)果并展示出來(lái)。
而我們可以通過(guò)爬蟲(chóng)獲取海量的數(shù)據(jù),所以爬蟲(chóng)是這一切的源頭。
瀏覽器的工作原理
瀏覽器是怎么知道網(wǎng)站內(nèi)容的呢?難道瀏覽器將所有網(wǎng)站的內(nèi)容保存下來(lái)了?
當(dāng)然不是這樣!其實(shí),瀏覽器偷偷地和 服務(wù)器 進(jìn)行了交流,服務(wù)器將博客網(wǎng)站的內(nèi)容傳輸給瀏覽器,瀏覽器收到后解析成你最終看到的網(wǎng)頁(yè)。
拓展:瀏覽器通過(guò) DNS(Domain
Name System)將域名轉(zhuǎn)換成對(duì)應(yīng)的 IP 地址,從而找到對(duì)應(yīng)網(wǎng)站的服務(wù)器。圖1
首先,我們?cè)跒g覽器輸入網(wǎng)址(URL)。然后瀏覽器去訪問(wèn)該網(wǎng)址對(duì)應(yīng)的服務(wù)器,這個(gè)過(guò)程叫請(qǐng)求(request)。接著服務(wù)器將網(wǎng)站內(nèi)容發(fā)送給瀏覽器,這個(gè)過(guò)程叫 響應(yīng)(response)。
瀏覽器拿到服務(wù)器返回的內(nèi)容后,一般都是網(wǎng)頁(yè)的源代碼。還需要瀏覽器將內(nèi)容解析成我們能看懂的樣子,也就是我們最終在瀏覽器里看到的網(wǎng)頁(yè)。
其實(shí),爬蟲(chóng)就是模擬瀏覽器的行為,從而獲取網(wǎng)站的數(shù)據(jù)。
爬蟲(chóng)的工作原理
爬蟲(chóng)可以像瀏覽器一樣向服務(wù)器發(fā)起請(qǐng)求,拿到服務(wù)器返回的數(shù)據(jù)后,可以根據(jù)我們?cè)O(shè)定的規(guī)則去提取需要的數(shù)據(jù),數(shù)據(jù)處理完成后再將數(shù)據(jù)存儲(chǔ)起來(lái)。圖2
爬蟲(chóng)工作的三個(gè)步驟:
第一步:獲取數(shù)據(jù),爬蟲(chóng)會(huì)根據(jù)我們提供的網(wǎng)址,向服務(wù)器發(fā)起請(qǐng)求獲取數(shù)據(jù);
第二步:處理數(shù)據(jù),對(duì)獲取的數(shù)據(jù)進(jìn)行處理,得到我們需要的部分;
第三步:存儲(chǔ)數(shù)據(jù),將處理后的數(shù)據(jù)保存起來(lái),便于后續(xù)的使用和分析等。
爬蟲(chóng)中最常用的發(fā)起請(qǐng)求的第三方庫(kù)——requests。requests 的中文文檔頁(yè)面(https://requests.kennethreitz.org/zh_CN/latest/)。
Tips:如果你的電腦上沒(méi)安裝Python,或者不知道具體如何安裝 requests 庫(kù)。請(qǐng)查看該文章:https://wpblog.x0y1.com/?p=34。
requests.get() 方法
import requests?#導(dǎo)入 requests 模塊
res =requests.get('https://wpblog.x0y1.com')? # 發(fā)起請(qǐng)求
print(res)
# 輸出:
使用 requests.get('網(wǎng)站地址') 方法向?qū)?yīng)的網(wǎng)站發(fā)起了請(qǐng)求,然后我們將返回的結(jié)果存到了變量 res 中供后續(xù)使用。它的類(lèi)型是 Response 對(duì)象,后面的 200 是狀態(tài)碼,表示請(qǐng)求成功。圖3
Response 對(duì)象
通過(guò) requests.get() 方法獲取到了網(wǎng)頁(yè)的數(shù)據(jù),作為 Response 對(duì)象存到了變量 res,那么我們?nèi)绾尾榭此木唧w內(nèi)容呢?
Response 對(duì)象的常用屬性:
res.status_code????? 響應(yīng)的HTTP狀態(tài)碼
res.text???????????? 相應(yīng)內(nèi)容的字符串形式
res.content????????? 響應(yīng)內(nèi)容的二進(jìn)制形式
res.encoding???????? 響應(yīng)內(nèi)容的編碼
res.status_code
?
import requests
res =requests.get('https://wpblog.x0y1.com')
print(res.status_code)
# 輸出:200
這里的 200 就是響應(yīng)的狀態(tài)碼,表示請(qǐng)求成功。當(dāng)請(qǐng)求失敗時(shí)會(huì)有不同的狀態(tài)碼,不同的狀態(tài)碼有不同的含義,常見(jiàn)的狀態(tài)碼如下:
1xx??消息???????100?? 繼續(xù)發(fā)出請(qǐng)求
2xx??請(qǐng)求成功???200?? 請(qǐng)求成功
3xx??重定向?????301??永久重定向
4xx??客戶(hù)端錯(cuò)誤?404?? 找不到資源
5xx??服務(wù)端錯(cuò)誤?503?? 服務(wù)不可用
練習(xí):請(qǐng)求是否成功
通過(guò) res.status_code 的值來(lái)判斷請(qǐng)求是否成功,當(dāng)其值為 200 時(shí)表示請(qǐng)求成功。
接下來(lái)請(qǐng)你補(bǔ)全下面的代碼,當(dāng)請(qǐng)求成功時(shí)打印出 請(qǐng)求成功,否則打印出 請(qǐng)求失敗。
import requests
res =requests.get('https://wpblog.x0y1.com')
# 補(bǔ)全下行代碼
if 200 <= res.status_code< 300:
# 答案直接用if res.status_code== 200:我理解2xx 是200到300之間的都可以,是否如此?
?print('請(qǐng)求成功')
else:
?print('請(qǐng)求失敗')
res.text
res.text 返回的是服務(wù)器響應(yīng)內(nèi)容的字符串形式,也就是文本內(nèi)容。
import requests
res = requests.get('https://wpblog.x0y1.com')
print(res.text)
練習(xí):
試試用爬蟲(chóng)下載一個(gè)小說(shuō)——孔乙己,它的網(wǎng)址是
https://apiv3.shanbay.com/codetime/articles/mnvdu。該網(wǎng)址返回的是小說(shuō)的純文本格式,源代碼和內(nèi)容是一樣的。
import requests
# 獲取孔乙己數(shù)據(jù)
res =requests.get('https://apiv3.shanbay.com/codetime/articles/mnvdu')
# 以寫(xiě)入的方式打開(kāi)一個(gè)名為孔乙己的txt 文檔
with open('孔乙己.txt', 'w') as file:
? #將數(shù)據(jù)的字符串形式寫(xiě)入文件中
? file.write(res.text)
open() 函數(shù)是 Python 中的內(nèi)置函數(shù),用于打開(kāi)文件,返回值是一個(gè) file 對(duì)象。
open() 函數(shù)接收的第一個(gè)參數(shù)為文件名,第二個(gè)參數(shù)為文件打開(kāi)模式。打開(kāi)模式默認(rèn)為 r,是 read 的縮寫(xiě),表示只讀模式。即只能讀取內(nèi)容,不能修改內(nèi)容。
常用的打開(kāi)模式有 w(write,只寫(xiě)模式)、b(binary,二進(jìn)制模式)和 a(append,追加模式,表示在文件末尾寫(xiě)入內(nèi)容,不會(huì)從頭開(kāi)始覆蓋原文件)。
Tips:在 w 和 a 模式下,如果你打開(kāi)的文件不存在,那么 open() 函數(shù)會(huì)自動(dòng)幫你創(chuàng)建一個(gè)。
這些打開(kāi)模式還能兩兩組合,比如:rb 表示以二進(jìn)制格式打開(kāi)文件用于讀取,wb 表示以二進(jìn)制格式打開(kāi)文件用于寫(xiě)入,ab 表示以二進(jìn)制格式打開(kāi)文件用于追加寫(xiě)入。
需要注意的是,使用 open() 函數(shù)打開(kāi)文件,操作完畢后,最后一定要調(diào)用 file 對(duì)象的 close() 方法關(guān)閉該文件。所以一般我們像下面這樣讀寫(xiě)文件:
# 讀取文件
file = open('文本.txt')? #打開(kāi)模式默認(rèn)為 r,可省略
print(file.read())? #調(diào)用 read() 方法讀取文件內(nèi)容
file.close()? #關(guān)閉文件
# 寫(xiě)入文件
file = open('文本.txt', 'w')? #寫(xiě)入模式
file.write('扇貝編程')? #調(diào)用 write() 方法寫(xiě)入內(nèi)容
file.close()? #關(guān)閉文件
為了避免忘記調(diào)用 close() 方法關(guān)閉文件,導(dǎo)致資源占用、文件內(nèi)容丟失等問(wèn)題,推薦使用with ... as ...語(yǔ)法,它在最后會(huì)自動(dòng)幫你關(guān)閉文件。
# 普通寫(xiě)法
file = open('文本.txt','w')? #寫(xiě)入模式
file.write('扇貝編程')? #調(diào)用 write() 方法寫(xiě)入內(nèi)容
file.close()? #關(guān)閉文件
# 使用 with ... as
... 寫(xiě)法
with open('文本.txt','w') as file:
?file.write('扇貝編程')
使用 with ... as ... 語(yǔ)法后,關(guān)閉文件的操作就可以省略了。不僅代碼簡(jiǎn)潔了,也避免了忘記關(guān)閉文件的問(wèn)題。
了解了文件操作之后,我們重新
import requests
# 獲取孔乙己數(shù)據(jù)
res =requests.get('https://apiv3.shanbay.com/codetime/articles/mnvdu')
# 以寫(xiě)入的方式打開(kāi)一個(gè)名為孔乙己的txt 文檔
with open('孔乙己.txt','w') as file:
? #將數(shù)據(jù)的字符串形式寫(xiě)入文件中
?file.write(res.text)
獲取到網(wǎng)頁(yè)的響應(yīng)后,以寫(xiě)入模式打開(kāi)一個(gè)名為 孔乙己.txt 的文件,然后調(diào)用 write() 方法將響應(yīng)內(nèi)容的字符串形式寫(xiě)入到文件中,實(shí)現(xiàn)了小說(shuō)的下載。同理,所有文本內(nèi)容都可以通過(guò)這種方式進(jìn)行下載,只需將 res.text 寫(xiě)入到文件當(dāng)中保存即可。
res.content
除了文本內(nèi)容的下載,爬蟲(chóng)還能下載圖片、音頻、視頻等。
import requests
# 獲取圖片數(shù)據(jù)
res =requests.get('https://assets.baydn.com/baydn/public/codetime/xiaobei/info.jpg')
# 以二進(jìn)制寫(xiě)入的方式打開(kāi)一個(gè)名為info.jpg 的文件
with open('info.jpg', 'wb') as file:
? #將數(shù)據(jù)的二進(jìn)制形式寫(xiě)入文件中
?file.write(res.content)
下載小說(shuō)的步驟幾乎一樣。區(qū)別在于圖片是用二進(jìn)制寫(xiě)入的方式,將數(shù)據(jù)的二進(jìn)制形式寫(xiě)入文件當(dāng)中,而不是字符串形式。
所以 res.text 和res.content 的區(qū)別是:res.text 用于文本內(nèi)容的獲取、下載,res.content 用于圖片、音頻、視頻等二進(jìn)制內(nèi)容的獲取、下載。
res.encoding
編碼是信息從一種形式或格式轉(zhuǎn)換為另一種形式的過(guò)程,常見(jiàn)的編碼方式有 ASCII、GBK、UTF-8 等。如果用和文件編碼不同的方式去解碼,我們就會(huì)得到一些亂碼。
res.encoding 就是爬蟲(chóng)獲取到數(shù)據(jù)的編碼格式,requests 庫(kù)會(huì)根據(jù)內(nèi)容推測(cè)編碼格式是什么,然后將 res.encoding 設(shè)成推測(cè)的格式,在訪問(wèn) res.text 時(shí)使用該格式解碼。
當(dāng)推測(cè)的格式錯(cuò)誤時(shí),即出現(xiàn)亂碼時(shí),就需要我們手動(dòng)給 res.encoding 賦值成正確的編碼。
