0.目的
為了實現(xiàn)博客的多平臺(簡書、掘金、知乎等)自動化發(fā)布,需要將本地的markdown中的圖片自動轉(zhuǎn)為圖床鏈接,盡管已經(jīng)有PicGO這種神器,但是自動調(diào)用PicGo上傳圖床有以下兩個問題
- 本地保留:大量圖片為直接從visio中復(fù)制過來,如果直接上傳本地沒有保留副本
- 隱私性:有些筆記不做公開,不希望圖片公開
因此使用另一種方法解決自動化發(fā)布問題,即優(yōu)先在本地完成文章,設(shè)置編輯器為將圖片保存在本地,編寫一個自動化替換腳本實現(xiàn)三個功能:
- 將圖片上傳到圖床(選擇Gitee)
- 將文章中的鏈接替換為圖床鏈接
1.Gitee圖床
Gitee是國內(nèi)的代碼托管網(wǎng)站,和Github相比具有訪問塊的優(yōu)勢,要將Gitee作為圖床,需要在Gitee中建立一個公開倉庫并獲取Token,首先建立公開倉庫:

隨后點擊頭像,在安全設(shè)置中選擇私人令牌,勾選需要的權(quán)限,點擊提交即可生成token,后續(xù)腳本可以使用這個token通過gitee的API進行自動的圖像上傳。自此Gitee圖床搭建完畢,可以嘗試向該倉庫中上傳圖片,如下所示:

該圖片的位置為<倉庫名稱>/raw/master/<圖片路徑>,例如上述圖片位于:<倉庫路徑>/raw/master/assert/player_structure.png
2.自動化上傳
Gitee有API處理新建文件。根據(jù)API文檔,新建文件的請求類型為POST,請求地址如下所示:
https://gitee.com/api/v5/repos/{owner}/{repo}/contents/{path}
路徑中所需要的內(nèi)容如下所示:
-
owner:倉庫所屬空間的地址,對個人用戶即為用戶名 -
repo:倉庫路徑,即圖床的名稱 -
path:上傳文件的目標(biāo)路徑,例如上一部分中為assert/player_structure.png
POST的formDate中需要帶的參數(shù)如下所示:
-
access_token:數(shù)據(jù)類型為string,為用戶生成的token -
content:文件內(nèi)容,數(shù)據(jù)類型為string,使用base64編碼 -
message:提交信息,數(shù)據(jù)類型為string
這里使用Python3+requests庫構(gòu)建POST請求,構(gòu)建代碼如下所示:
def uploader_picture_gitee(post_data):
url = "https://gitee.com/api/v5/repos/{owner}/{repo}/contents/{path}".format(
owner=post_data["owner"],repo=post_data["repo"],path=post_data["path"])
formdata = {
"access_token":post_data["token"],
"content":post_data["content"],
"message":post_data["message"]
}
r = requests.post(url=url,data=formdata)
if r.status_code == 201:
print("INFO:upload {} successful".format(post_data["path"]))
return r.json()["content"]["download_url"]
return None
其中post_data是包括所有參數(shù)的dict,其中owner、repo和token來自預(yù)先寫好的json文件,讀取部分代碼如下所示:
def get_config(cfg_path):
with open(cfg_path,"r") as f:
data = json.load(f)
return data
另外path、content和message需要根據(jù)圖片文件生成,其中path由原文件名加上時間戳防止重復(fù),content內(nèi)容需要以二進制讀取圖片文件,并將其使用base64編碼,該部分代碼如下所示:
def get_picture(pic_path):
with open(pic_path,'rb') as f:
data = base64.b64encode(f.read())
picture_name = os.path.split(pic_path)[-1]
time_name = int(time.time() * 1000)
return {
"content":data,
"path":"assert/{}_{}".format(time_name,picture_name),
"message":"{}-upload{}".format(time_name,picture_name)
}
3.markdown圖片替換
需要將markdown中的圖片語句![]()中的內(nèi)容替換為上傳后的URL,使用正則表達式識別,正則表達式如下所示:
r"^\s*!\[.*?\]\(.*?\)"
當(dāng)識別出上述內(nèi)容后,判斷當(dāng)前行為圖片,這里僅對單獨出現(xiàn)的圖片做處理,不考慮和文字出現(xiàn)在同一行的圖片。代碼如下所示:
def handle_markdown(mk_path,cfg_path):
# read config
cfg = get_config(cfg_path)
# read markdown
with open(mk_path,'r',encoding='utf-8') as f:
data = f.read().split("\n")
# search pic and upload
for i,line in enumerate(data):
m = re.search(r"^\s*!\[(.*?)\]\((.*?)\)",line)
if m is not None:
pic_name,pic_path = m.groups()
if "://" in pic_path:
print("INFO:{} is url,ignore".format(pic_path))
continue
pic = get_picture(pic_path)
url = uploader_picture_gitee({**cfg,**pic})
if url is None:
raise ValueError("upload {} failed".format(pic_name))
data[i] = "".format(pic_name,url)
# add thanks
data.append("> 感謝gitee提供圖片托管服務(wù),BlogHelper提供快捷發(fā)布服務(wù)")
data.append("> 該版本由自動發(fā)布工具生成,原始內(nèi)容為原創(chuàng),轉(zhuǎn)載需聯(lián)系作者獲得授權(quán)")
# generate new markdown
root,name = os.path.split(mk_path)
new_path = os.path.join(root,"public_{}".format(name))
with open(new_path,'w') as f:
f.write("\n".join(data))
該部分代碼處理的內(nèi)容如下所示:
- 讀取配置信息
- 讀取markdown文件
- 掃描markdown的每一行,若在這一行發(fā)現(xiàn)圖片插入語句,則判斷其是否為url,若不是url則讀取圖片并將其上傳,并替換為返回的URL
- 在尾部添加版權(quán)聲明和感謝信息
- 生成新文件文件名并寫入內(nèi)容
4.發(fā)布
至此,生成了將圖片替換為圖床URL的可發(fā)布版本,通過BlogHelper可自動發(fā)布到各個平臺
感謝gitee提供圖片托管服務(wù),BlogHelper提供快捷發(fā)布服務(wù)
該版本由自動發(fā)布工具生成,原始內(nèi)容為原創(chuàng),轉(zhuǎn)載需聯(lián)系作者獲得授權(quán)