Asroads'Blog 君子不器
简单优化一下个人博客
发布于: 2019-09-25 更新于: 2022-07-11 分类于: other 阅读次数: 

个人博客开了一年多,平常大都是发布一下文章,写一下工作的感想,很多文章都用了图片,今天发现我好多图片都是后缀png的,而且尺寸都显得很大,要想然自己的博客文章打开的快速,减少读者的加载是一个工程,另外每个文章写的时候,里面有很多图片,最后都重新替换了,可很难找出那些是没有引用的,于是乎,有了这篇文章。

优化四部曲

  • 更改图片格式,比如后缀为 png的改成JPEG
  • 更改图片尺寸。比如原来是1000X600的 可以适当比例缩放
  • 删除多余的没有用到的图片
  • 优化网站链接

更改格式

  • Mac系统自带预览图片可以搞定

因为我文章不多,所以我一个个操作

  1. 比如我们这个文章的博客

    image-20190925142711143

  2. 我们打开文件夹,全选我们的图片

image-20190925142843297

  1. 继续全选我们的图片

image-20190925142931375

  1. image-20190925142957982

  2. 修改我们需要的满意的尺寸 我是按照百分比修改的

image-20190925143141178

  1. 我们发现 图片尺寸已经 缩小

image-20190925143314469

更改格式

  1. 前面几步和上面一致,只是在打开编辑的时候选择的是 导出选定的图像

  2. image-20190925143458361

  3. 选择我们要存放的文件夹 和 选项 选择 格式

image-20190925143546127

image-20190925143605095

  1. 把生成的图片替换

image-20190925143636903

  1. 我们用 Typora 编辑器打开我们的文章 选择查找 –替换 后缀名即可

image-20190925144055367

5.我们发现 可以正常显示我们新的图片了

删除多余的图片

这个我自己去看了 编辑器的设置没有这样的功能,就想着用Python3 自己写个脚本吧

脚本如下:

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
#!/usr/bin/env -S -P${HOME}/anaconda/bin python
# -*- coding:utf-8 -*-
import re, os
from itertools import chain

blogDirsList = []
img_patten = r'!\[.*?\]\((.*?)\)|<img.*?src=[\'\"](.*?)[\'\"].*?>'
# 博客文件夹 本地目录指向 source/_posts 源文件
myblogPath = '/jsroads/blog/asroads.github.io/source/_posts'
blogPath = os.path.abspath(myblogPath)
blogfiles = os.listdir(blogPath)
for blogfile in blogfiles:
# 得到该文件下所有目录的路径
m = os.path.join(blogPath, blogfile)
# 判断该路径下是否是文件夹
if (os.path.isdir(m)):
h = os.path.split(m)
# 把符合要求的目录加进去
blogDirsList.append(os.path.join(blogPath, h[1]))
# print("博客目录", blogDirsList)
# 遍历目录地址
mdList = [] # md 文件里引用的图片
pngList = [] # 本地同名文件夹文件的图片
for source_path in blogDirsList:
if os.path.exists(source_path):
mdList = []
pngList = []
for parent, dirs, files in os.walk(source_path):
for file in files:
# print("file:",file)
file_path = os.path.join(parent, file)
if os.path.splitext(file)[-1] == ".png" or os.path.splitext(file)[-1] == ".jpeg": # 获取后缀
picUrl = os.path.join(parent, file)
pngList.append(picUrl)
# print('jsroads',file_path)
if os.path.splitext(file)[-1] == ".md": # 获取后缀
with open(os.path.join(source_path, file), 'r', encoding='utf-8') as f: # 使用utf-8 编码打开
post = f.read()
matches = re.compile(img_patten).findall(post)
if matches and len(matches) > 0:
# print("jsroads:",matches)
# 多个group整合成一个列表
for match in list(chain(*matches)):
if match and len(match) > 0:
picUrl = os.path.join(parent, match)
mdList.append(picUrl)
# 对比一下 两个文件夹的不同 删除没有使用的
print("------------")
for picPath in pngList:
if picPath not in mdList:
print("picPath", picPath)
# 删除 没有使用的素材(这里主要删除图片)
os.remove(picPath)

下面是我的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
博客目录 ['/jsroads/blog/asroads.github.io/source/_posts/other', '/jsroads/blog/asroads.github.io/source/_posts/about', '/jsroads/blog/asroads.github.io/source/_posts/life', '/jsroads/blog/asroads.github.io/source/_posts/game', '/jsroads/blog/asroads.github.io/source/_posts/tool']
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824183550706.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824184345625.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824184445658.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/LayaBox2-0-圆形进度条制作/image-20190327200707147.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Cocos-Creator-引入TweenMax-Uncaught-TypeError-container-appendChild-解决方法/image-20190916104222217.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Cocos-Creator-引入TweenMax-Uncaught-TypeError-container-appendChild-解决方法/image-20190916104642302.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/LayaAir2-0-LayaBox-之小游戏开放域开发/image-20190307202019424.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/微信小游戏Laya2-0粒子特效实现/image-20190823142029613.jpeg
picPath /jsroads/blog/asroads.github.io/source/_posts/game/微信小游戏Laya2-0粒子特效实现/image-20190823141529866.jpeg
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824183550706.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824184345625.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Layabox2-0引入puremvc框架/image-20190824184445658.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/LayaBox2-0-圆形进度条制作/image-20190327200707147.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Cocos-Creator-引入TweenMax-Uncaught-TypeError-container-appendChild-解决方法/image-20190916104222217.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/Cocos-Creator-引入TweenMax-Uncaught-TypeError-container-appendChild-解决方法/image-20190916104642302.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/LayaAir2-0-LayaBox-之小游戏开放域开发/image-20190307202019424.png
picPath /jsroads/blog/asroads.github.io/source/_posts/game/微信小游戏Laya2-0粒子特效实现/image-20190823142029613.jpeg
picPath /jsroads/blog/asroads.github.io/source/_posts/game/微信小游戏Laya2-0粒子特效实现/image-20190823141529866.jpeg
picPath /jsroads/blog/asroads.github.io/source/_posts/tool/Webstorm如何配置Layabox2-0项目/image-20190302194904756.png
picPath /jsroads/blog/asroads.github.io/source/_posts/tool/Webstorm如何配置Layabox2-0项目/image-20190302195857734.png
picPath /jsroads/blog/asroads.github.io/source/_posts/tool/如何下载微信公众号的文章和媒体文件/image-20190516123503663.png

其实删除多余素材 并不能 加速 用户体验,但是对于自己日常开发要求干净的洁癖还是很重要的,自己试试吧。

下面记录一下 Python3 常用的一些操作

1
2
3
4
5
6
7
8
9
mport os
file = "Hello.py"

# 获取前缀(文件名称)
assert os.path.splitext(file)[0] == "Hello"

# 获取后缀(文件类型)
assert os.path.splitext(file)[-1] == ".py"
assert os.path.splitext(file)[-1][1:] == "py"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os

# 获取当前程序运行目录
print(os.getcwd())

# 获取指定目录下的列表
print(os.listdir("E:\\server"))

# 检查是否存在文件或文件夹
print(os.path.exists("E:\\test\\a.txt"))

# 创建文件夹,已经存在文件会报错
os.mkdir("E:\\test1")

# 删除文件夹,只能删除文件夹
os.remove("E:\\test1")

# 文件重命名
os.rename("E:\\test\\a.txt", "E:\\test\\b.txt")
1
2
3
4
5
6
import shutil,os
if os.path.exists(os.path.join(bizimage_filepath, image_name)):
//移除文件
os.remove(os.path.join(bizimage_filepath, image_name))
//移除空文件夹
shutil.rmtree(bizimage_filepath)
1
2
3
4
5
6
7
#通过in和not in关键字来判读一个list中是否包含一个元素
theList = [‘a’,’b’,’c’]
if ‘a’ in theList:
print ‘a in the list

if ‘d’ not in theList:
print ‘d is not in the list
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env -S -P${HOME}/anaconda/bin python
# -*- coding:utf-8 -*-

import re, os, shutil, time, sys, argparse
from itertools import chain
import oss2

# 需要替换url的MD文件
md_file = ''

# 操作类型, L2L (默认本地到本地), L2W(本地到图床), W2L(图床到本地)
action = 'L2L'

# 保存图片文件的根目录
dir_base = '/*******/_MD_Media'

# Markdown中图片语法 ![](url) 或者 <img src='' />
img_patten = r'!\[.*?\]\((.*?)\)|<img.*?src=[\'\"](.*?)[\'\"].*?>'


def get_img_local_path(md_file, path):
"""
获取MD文件中嵌入图片的本地文件绝对地址
:param md_file: MD文件
:param path: 图片URL
:return: 图片的本地文件绝对地址
"""

result = None

# /a/b/c
if path.startswith('/'):
result = path
# ./a/b/c
elif path.startswith('.'):
result = '{0}/{1}'.format(os.path.dirname(md_file), path)
# file:///a/b/c
elif path.startswith('file:///'):
result = path[8:]
result = result.replace('%20',' ')
else:
result = '{0}/{1}'.format(os.path.dirname(md_file), path)

return result

def local_2_local(md_file, dir_ts, match):
"""
把MD中的本地图片移动到指定目录下,并返回URL。 这里并没有进行URL的替换
:param md_file:
:param dir_ts:
:param match:
:return: new_url,新本地文件地址。如果不需要替换,就返回空
"""
dir_tgt = '{0}/{1}'.format(dir_base, dir_ts)
new_url = None
# 判断是不是已经是一个图片的网址,或者已经在指定目录下
if not (re.match('((http(s?))|(ftp))://.*', match) or re.match('{}/.*'.format(dir_base), match)):
# 如果图片url是本地文件,就替换到指定目录
img_file = get_img_local_path(md_file, match)
if os.path.isfile(img_file):
new_url = '{0}/{1}'.format(dir_tgt, os.path.basename(match))
os.makedirs(dir_tgt, exist_ok=True)
# 移动物理文件
shutil.move(img_file, dir_tgt)

return new_url

def local_2_web(md_file, dir_ts, match):
"""
把MD中的本地图片上传到OSS下,并返回URL。 这里并没有进行URL的替换
:param md_file:
:param dir_ts:
:param match:
:return: new_url,新本地文件地址。如果不需要替换,就返回空
"""

# 阿里云OSS信息
bucket_name = "b******ce"
endpoint = "http://oss-cn-beijing.aliyuncs.com"
access_key_id = "******"
access_key_secret = "******"
web_img_prfix = 'https://******.oss-cn-beijing.aliyuncs.com'
# 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行
bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)

new_url = None
# 判断是不是已经是一个图片的网址
if not (re.match('((http(s?))|(ftp))://.*', match) ):
# 如果图片url是本地文件,就上传
img_file = get_img_local_path(md_file, match)
if os.path.isfile(img_file):
key_url = '{0}/{1}'.format(dir_ts, os.path.basename(match))
bucket.put_object_from_file(key_url, img_file)
new_url = '{}/{}'.format(web_img_prfix, key_url)

return new_url

def replace_md_url(md_file):
"""
把指定MD文件中引用的图片移动到指定地点(本地或者图床),并替换URL
:param md_file: MD文件
:return:
"""

if os.path.splitext(md_file)[1] != '.md':
print('{}不是Markdown文件,不做处理。'.format(md_file))
return

cnt_replace = 0
# 本次操作时间戳
dir_ts = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())

with open(md_file, 'r',encoding='utf-8') as f: #使用utf-8 编码打开
post = f.read()
matches = re.compile(img_patten).findall(post)
if matches and len(matches)>0 :
# 多个group整合成一个列表
for match in list(chain(*matches)) :
if match and len(match)>0 :
new_url = None

# 进行不同类型的URL转换操作
if action == 'L2L':
new_url = local_2_local(md_file, dir_ts, match)
elif action == 'L2W':
new_url = local_2_web(md_file, dir_ts, match)

# 更新MD中的URL
if new_url :
post = post.replace(match, new_url)
cnt_replace = cnt_replace + 1

# 如果有内容的话,就直接覆盖写入当前的markdown文件
if post and cnt_replace > 0:
open(md_file, 'w', encoding='utf-8').write(post)
print('{0}的{1}个URL被替换到<{2}>/{3}'.format(os.path.basename(md_file), cnt_replace, action, dir_ts))
elif cnt_replace == 0:
print('{}中没有需要替换的URL'.format(os.path.basename(md_file)))





if __name__ == '__main__':
parser = argparse.ArgumentParser()

parser.add_argument('-f', '--file', help='文件Full file name ofMarkdown file.')
parser.add_argument('-a', '--action', help='操作类型: L2L, L2W, W2L .')
parser.add_argument('-d', '--dir', help='Base directory to store MD images.')

args = parser.parse_args()

if args.action:
action = args.action
if args.dir:
dir_base = args.dir
if args.file:
replace_md_url(args.file)




优化链接地址

hexo默认的链接是http://xxx.xxxx.com/2019/09/25/hello-world这种类型的,这源于站点目录下的配置_config.yml里的配置:permalink: :year/:month/:day/:title/.这种默认配置的缺陷是就是一般我们文章的名字是中文的时候,链接地址就会会出现一大串,此外不利于seo。年月日都会有分隔符。下面就优化一下链接

  • 使用 hexo-abbrlink这个插件
  • 后期修改一下 hexo-asset-image配置 完美解决

安装插件(在你的本地网站目录)

1
npm install hexo-abbrlink --save

站点配置文件中查找代码permalink,将其更改为:

1
2
3
4
permalink: post/:abbrlink.html
abbrlink:
alg: crc32 # 算法:crc16(default) and crc32
rep: hex # 进制:dec(default) and hex

然后去修改我们的 网站目录下面的 scaffolds目录 下面的 post.md

1
2
3
4
5
6
7
---
title: {{ title }}
date: {{ date }}
comments: true
categories:
tags:
---

这样 之后,我们重新 运行 hexo cleanhexo g 发现我们的网址 已经变了

PS:2020年1月11日 我更新插件后 发现 已经 可以自动匹配了 所以 下面的这个解决方案 可以忽略了

下面是最新的代码 已经 不需要修改了

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
if ($(this).attr('src')){
// For windows style path, we replace '\' to '/'.
var src = $(this).attr('src').replace('\\', '/');
if(!(/http[s]*.*|\/\/.*/.test(src)
|| /^\s+\//.test(src)
|| /^\s*\/uploads|images\//.test(src))) {
// For "about" page, the first part of "src" can't be removed.
// In addition, to support multi-level local directory.
var linkArray = link.split('/').filter(function(elem){
return elem != '';
});
var srcArray = src.split('/').filter(function(elem){
return elem != '' && elem != '.';
});
if(srcArray.length > 1)
srcArray.shift();
src = srcArray.join('/');

$(this).attr('src', config.root + link + src);
console.info&&console.info("update link as:-->"+config.root + link + src);
}
}else{
console.info&&console.info("no src attr, skipped...");
console.info&&console.info($(this));
}

但是此时我发现和我另外一个插件有图片链接的冲突,我的图片地址找不到正确的链接,此时我们去修改我们的插件

  1. 打开我们的插件目录 找到 对应的 xxx\node_modules\_hexo-asset-image@0.0.3@hexo-asset-image\index.js文件

  2. 修改部分代码(这个根据你的情况修改,我的如下)

    • 在源码的12行附近var link = data.permalink;这一行的下面,添加 一行var abbrlink = data.abbrlink(声明一个变量 为 abbrlink)
    • 在44行附近,修改代码 原代码
    1
    2
    3
    if(linkArray[linkArray.length - 1] == srcArray[0])
    srcArray.shift();
    src = srcArray.join('/');

    修改后:

    1
    2
    3
    4
    if(linkArray[linkArray.length - 1] == srcArray[0])
    srcArray.shift();
    if(srcArray[0]!==abbrlink)srcArray[0]=abbrlink;
    src = srcArray.join('/');

    直接贴上我最后的修改文件吧:index.js

    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
    'use strict';
    var cheerio = require('cheerio');

    // http://stackoverflow.com/questions/14480345/how-to-get-the-nth-occurrence-in-a-string
    function getPosition(str, m, i) {
    return str.split(m, i).join(m).length;
    }

    hexo.extend.filter.register('after_post_render', function(data){
    var config = hexo.config;
    if(config.post_asset_folder){
    var link = data.permalink;
    var abbrlink = data.abbrlink
    var beginPos = getPosition(link, '/', 3) + 1;
    // In hexo 3.1.1, the permalink of "about" page is like ".../about/index.html".
    var endPos = link.lastIndexOf('/') + 1;
    link = link.substring(beginPos, endPos);

    var toprocess = ['excerpt', 'more', 'content'];
    for(var i = 0; i < toprocess.length; i++){
    var key = toprocess[i];

    var $ = cheerio.load(data[key], {
    ignoreWhitespace: false,
    xmlMode: false,
    lowerCaseTags: false,
    decodeEntities: false
    });

    $('img').each(function(){
    // For windows style path, we replace '\' to '/'.
    var src = $(this).attr('src').replace('\\', '/');
    if(!/http[s]*.*|\/\/.*/.test(src)){
    // For "about" page, the first part of "src" can't be removed.
    // In addition, to support multi-level local directory.
    var linkArray = link.split('/').filter(function(elem){
    return elem != '';
    });
    var srcArray = src.split('/').filter(function(elem){
    return elem != '';
    });
    if(linkArray[linkArray.length - 1] == srcArray[0])
    srcArray.shift();
    if(srcArray[0]!==abbrlink)srcArray[0]=abbrlink;
    src = srcArray.join('/');
    $(this).attr('src', '/' + link + src);
    // $(this).attr('src' , '/' + link + abbrlink + '/' + src);
    }
    });
    data[key] = $.html();
    }
    }
    });

    1. 重新hexo clean 和 hexo g,即可生效。

    注意:最后这个冲突问题,你根据自己目录实际需要修改代码即可

原文部分引用

方法如下

编辑xxx\node_modules\_hexo-asset-image@0.0.3@hexo-asset-image\index.js文件
1、在源码的12行附近var link = data.permalink;这一行的下面,添加 一行var abbrlink = data.abbrlink
(意思是定义一个变量abbrlink)
2、在44行附近,源码的 $(this).attr('src' , '/' + link + src);这一行,修改 为下面一行:
$(this).attr('src' , '/' + link + abbrlink + '/' + src);
(意思是生成的图片链接中,拼接abbrlink)

然后重新hexo clean 和 hexo g,即可生效。
_posts文件夹下的文章,按照自己喜欢的方式整理,生成的链接是正常的,在typora中可以正常显示。

如果你的permalink加了后缀的话, 例如我的 permalink: p/:abbrlink.html
编辑xxx\node_modules_hexo-asset-image@0.0.3@hexo-asset-image\index.js文件, index多减个值

1
2
3
4
5
6
7
8
9
10
if(/.*\/index\.html$/.test(link)) {
// when permalink is end with index.html, for example 2019/02/20/xxtitle/index.html
// image in xxtitle/ will go to xxtitle/index/
appendLink = 'index/';
var endPos = link.lastIndexOf('/');
}
else {
// var endPos = link.length-1; // 换成下面的这句话
var endPos = link.length-5; //因为我的permalink: p/:abbrlink.html, 这里要改成-5
}

2021-09-22 更新

如果使用最新的hexo 版本 5.x 和 最新的插件版本 发现 源码已经改变了,如果遇到图片不能正常显示,此时需要检查网页的源代码:

此时 config.yml 文件

1
2
url: https://jsroads.gitee.io
permalink: :year/:month/:day/:title/

但是我们打印出来的图片路径 是:

1
2
update link as:-->/.io//image-20210922130821755.png
update link as:-->/.io//image-20210922130821755.png

经过查找问题出在 项目根目录/node_modules/hexo-asset-image/index.js的23行左右

1
2
3
4
5
6
7
8
9
if(/.*\/index\.html$/.test(link)) {
// when permalink is end with index.html, for example 2019/02/20/xxtitle/index.html
// image in xxtitle/ will go to xxtitle/index/
appendLink = 'index/';
var endPos = link.lastIndexOf('/');
}
else {
var endPos = link.lastIndexOf('.');
}

发现 这个走了 else 分支导致的,我们把 link.lastIndexOf('.') 修改为 link.lastIndexOf('/') 即可 修改后

1
2
3
4
5
6
7
8
9
if(/.*\/index\.html$/.test(link)) {
// when permalink is end with index.html, for example 2019/02/20/xxtitle/index.html
// image in xxtitle/ will go to xxtitle/index/
appendLink = 'index/';
var endPos = link.lastIndexOf('/');
}
else {
var endPos = link.lastIndexOf('/');
}

重新 清理运行 : hexo clean & hexo g

1
2
update link as:-->/2021/09/18/hello-world/image-20210922130821755.png
update link as:-->/2021/09/18/hello-world/image-20210922130821755.png

然后运行效果 正常 以上OK

后记

其实很多事情,有了目标,就朝着这个目标努力,虽然未必能真正做到自己最初的想法,但是起码不会原地不动,至少是开卷有益,有时候还有意外的学习收获。

参考链接

--- 本文结束 The End ---