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進(jìn)行自動的圖像上傳桶错。自此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)容需要以二進(jìn)制讀取圖片文件侮攀,并將其使用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,使用正則表達(dá)式識別兰英,正則表達(dá)式如下所示:
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)