0%

批量将hexo文章中的本地图片转到chevereto图床

前言

这几天在重新弄博客,基本上已经完工了,但是博客的链接还是不够友好。

因为hexo中的链接默认是年月日划分的,这样对SEO很不友好,所以就顺便做了博客的链接持久化,主要是使用的hexo-abbrlink这个插件,方法百度一堆,这里不再赘述。

在这之前因为看教程说会和hexo-asset-image插件冲突,所以一步到位搭了个图床,用来存放我的博客图片,也避免了日后图片过多超过github限制的情况。

准备工作

图床应用我用的chevereto,搭建教程这里也不提了,按照教程一路下一步即可。

图床搭建好了,那么把之前存在本地的图片放上去就成了问题。一方面需要把文件传上去,另一方面还需要把原来文章中的图片引用链接改成图床的链接。我博客里文章不多,也就20多篇,但是图片可不算少,所以写了个脚本来完成这个工作。

chevereto提供了上传图片的API,所以首先需要去chevereto的后台获取你的APIKEY,然后才能调用接口。

仪表盘—>设置—>API菜单下就可以看到了。

2020-02-26_01-46.png

然后就可以写代码了。


基本思路

基本思路是打开本地的markdown文件,然后正则获取其中引用的本地的图片路径,并将对应的文件通过API传到图床,然后把返回的图片链接替换回去即可。流程图如下:

流程图


代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# author: guiu
# data: 2020.2.25

import requests
import json
import mimetypes
import os
import re


class PixMv:
def __init__(self):
# 初始化一些用到的变量
self.root = os.path.dirname(os.path.abspath(__file__)) # 工作目录
self.md_list = [] # 当前目录下的文章列表
self.error_url = {} # 上传失败的链接
self.current_filename = ""
self.current_error_link = []

def list_md_file(self, path):
# 搜寻当前目录下的md文件,方便后续修改(搜索深度只有一级)
for file in os.listdir(path):
if file[-3:] in [".md", ".MD"]:
self.md_list.append(file)

def modify_md_file(self, md_list):
# 对self.md_list中的文件进行修改,将本地引用的图片链接转成图床链接
for file in md_list:
# 记录当前文件名
self.current_filename = file
with open(os.path.join(self.root, file), "r+", encoding='utf8') as f:
file_content = f.read()
# 每个文件都建立一个错误列表,存放失败的链接
self.current_error_link = []
try:
# 正则匹配提取本地图片引用路径,传给modify_url函数修改后替换
file_content = re.sub(r"\!\[.*?\]\((?!http:|data:).*?\)", self.modify_url,
file_content, count=0, flags=0)
except:
print("{} modify failed.".format(self.current_filename))
continue
# 移动文件指针到开头
f.seek(0, 0)
# 覆盖写入修改后的内容
f.write(file_content)
print("{} modify succeeded.".format(self.current_filename))
# 生成日志文件,记录失败的链接
with open("modify.log", 'r+') as log:
log.write(str(self.error_url))

def modify_url(self, url_match):
# 将正则匹配到的路径上传至图床,并把图床链接替换回去
try:
# 提取图片路径
img_path = re.findall(r"\.\/(.*?)\)", url_match.group())[0]
resjson = self.up_to_chevereto(img_path)
# 对获取到的图床链接进行处理
replaced_url = self.parse_response_url(resjson, img_path)
return replaced_url
except:
# 错误的话就存起来,然后不修改
self.current_error_link = url_match.group()
self.error_url[self.current_filename] = self.current_error_link
return url_match.group()

def parse_response_url(self, json, img_path):
# 从返回的json中解析字段
if json['status_code'] != 200:
print("{}\tweb端返回失败,可能是APIKey不对. status_code {} .".format(
img_path, json['status_code'])
)
raise Exception("上传成功了但是状态码不对,请手动核对")
else:
img_url = json["image"]["url"]
filename = json["image"]["filename"]
print(filename + "\t上传图床成功")
replace_url = "![{}]({})".format(filename, img_url)
return replace_url

def up_to_chevereto(self, file):
# 获得本地图片路径后,上传至图床并记录返回的json字段
try:
res_json = self.upload(self.formatSource(file))
return res_json
except:
print(file+"\t上传失败")
# 失败的话就抛一个异常
raise Exception("上传失败")

def upload(self, files):
# 图床api
APIKey = "THERE PUT YOUR APIKEY"
format_str = "json"
url = "http://your_website/api/1/upload/?key=" + \
APIKey + "&format=" + format_str # 图床地址
r = requests.post(url, files=files)
return json.loads(r.text)

def formatSource(self, filename):
imageList = []
mime_type = mimetypes.guess_type(filename)[0]
imageList.append(
('source', (filename, open(filename, 'rb'), mime_type))
)
#print (imageList)
return imageList


if __name__ == '__main__':
p = PixMv()
p.list_md_file(p.root)
p.modify_md_file(p.md_list)

将脚本放在/yourblog/source/_post/文件夹下运行即可。