Context Manager 的中文叫資源管理器
大家應該有在 Python 看過 with ... as 這樣的語法,它就是 Context Manager
比如說 Python 的 File I/O,一般來說寫法可能如下 :
file = open('foo.txt', 'w+') file.write('bar') file.close()
|
執行結果不會有 Output
這段程式碼就是打開一個叫 foo.txt 的檔案,然後寫入字串 bar 並且關檔
大家可以發現到,我們需要做一個「關檔」的動作
沒有關檔會怎樣 ?
首先,我們在撰寫程式語言的時候必須重視記憶體的管理
請求來的物件,當生命週期到了就該銷毀物件,做一個歸還記憶體的動作
即使 Python 不像 C 語言一樣需要時時刻刻注意記憶體管理,但也不能忽略這個議題
再者,程式如果是「不正當」的關閉,可能會造成資料的遺失
所以檔案讀寫完畢,最好的習慣都是馬上關閉檔案
Context Manager 顧名思義就是在幫我們管理資源,參考以下程式碼 :
with open('foo.txt', 'w+') as file: file.write('bar')
|
它和剛才的程式碼做的事情一模一樣,好處在於不用自己管理資源,而且語法更簡潔了
因為 with ... as 的程式區塊結束,file 的資源就會自己被歸還
具體來說,with ... as 在建立資源的時候是呼叫物件的 __enter__ 方法
銷毀的時候呼叫 __exit__ 方法
我們也可以實作一個 File 物件,程式碼如下 :
class File: def __init__(self, file, method): self.file = open(file, method) def __enter__(self): return self.file def __exit__(self, type, value, traceback): self.file.close()
with File('foo.txt', 'w+') as file: file.write('bar')
|
然後別問我 __exit__ 裡面的 type、value、traceback 參數是什麼 ?
我在翻文件的時候看到 「We did not talk about the type, value and traceback
arguments of the __exit__ method .」
所以我也不知道 ...
不過從邏輯上來看用法已經很清楚了,而且一般來說也只需要會使用 with ... as 就足夠了
說了這麼多,Context Manager 具體來說能為爬蟲做些什麼 ?
基本上我常用來讀寫檔案,還有下載二進位檔案,包括圖片、影片等等 ...
他確定是一個 .jpg 檔案,這時候就可以下載它,程式碼如下 :
import requests
response = requests.get('https://www.pythonscraping.com/img/gifts/img1.jpg')
with open('img.jpg', 'wb') as file: file.write(response.content)
|
執行完畢就可以看到 img.jpg 了,點擊開來會跟網站上一模一樣
這就是 Context Manager 的一個應用,或者說讀寫檔案的應用
這邊有幾個重點需要注意一下
首先,開檔案的時候要以 wb 模式,也就是二進位寫入模式
詳細可以搜尋 Python Files I/O,因為開檔模式有太多種了
總之 .jpg 檔案是一個二進位,所以要使用二進位模式
再來,寫入的時候是 response 的 content,為什麼是 content ?
如果你去 print response 的 text 或 content,看起來會長得一模一樣
差別在於 text 回傳的是 Unicode,content 回傳的是 Binary,這樣了解了吧 ?
你想寫入 response 的 text 會直接噴 Error
TypeError : a bytes-like object is required, not 'str'
下載檔案的方法不只一種,下次會介紹 urllib3.request 的 urlretrieve 方法
雖然大部分時候使用 Context Manager 即可