Python批量格式化hugo文章

由于之前有很多md文件的文章分布在不同的分类目录下(在同一父级目录下),使用docsify作为网站编译解释框架。

docsify用起来很舒服,之前在github.io没有seo方面的需求,后续有了seo的需求后,docsify在seo方面还需要等下一个大版本,实在等不及,只能考虑将批量转换所有md文件,支持hugo的Front Matter、内联md、摘要等属性设置。

写这个python脚本只是为了帮助人,而不是完全做了我们人该做的,本地也没有文章机器学习的能力,有机会考虑使用机器学习实现文章分类、标签、关键字、标题的自动生成,当然最后还是需要人为的完善这些自动生成的信息。

目录

脚本介绍

代码实现

演示日志

效果

脚本介绍

python中实现一个类,用于处理:

1、scanFiles方法支持:扫描源目录所有md文件,提取文件支持hugo相关的FrontMatter等信息,并在hugo项目的content/post/目录下,按照目录层级创建目录及写入文件文件

2、scanFile方法支持:输入单个md文件路径,提取文件支持hugo相关的FrontMatter等信息,并在hugo项目的content/post/目录下,按照目录层级创建目录及写入文件文件

usage:

1
& python hugo-md-format.py > mdlog

代码实现

准备:安装jieba、enchant模块(enchant暂时可以不用,用于英文单词判断)

  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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import os
import time
import datetime
# import enchant
import jieba


class HugoMarkdown:

    # __srcDir = 'I:\src\hugo\docs' #源文章目录
    # __desDir = 'I:\src\hugo\9ong\content\post' #目的文件目录

    __srcDir = 'I:\src\github-page\docs' #源文章目录
    __desDir = 'I:\src\hugo\9ong\content\post' #目的文件目录
    __ignoreFile = ["index.md","README.md",'more.md']#文件忽略
    __ignoreParentDir = ["docs","post","content","互联网"]#分类忽略(父级目录)


    def __init__(self):
        print("···HugoMarkdown···\n")
        

    #遍历源日志目录所有文件,批量处理
    def scanFiles(self):
        print("不再使用,除非有新的md文件目录需要批量转换")
        return False

        print("开始遍历源文章目录:",self.__srcDir,"\n")
        for root,dirs,files in os.walk(self.__srcDir):
            for file in files:   
                
                print("\n-----开始处理文章:",os.path.join(root,file),"-----\n")

                if self.__isIgnoreFile(file):            
                    print("忽略",file,"\n")
                    continue


                fileInfoDict = self.__getFileInfo(root,file)

                if (fileInfoDict['fileExt'] != ".md") or (fileInfoDict['parentDir']==''):
                    print("忽略",file,"\n")
                    continue                

                #测试输出    
                print(fileInfoDict,"\n")                

                self.__adjustFIleContent(fileInfoDict)

                #只循环一次,跳出所有循环
                # return 

    def scanFile(self,filePath):           

        self.__srcDir = self.__desDir

        root = os.path.dirname(filePath)
        file = os.path.basename(filePath)
        # print(os.path.join(root,file))
        # return False

        print("\n-----开始处理文章:",os.path.join(root,file),"-----\n")
        if self.__isIgnoreFile(file):
            print("忽略",file,"\n")
            return False


        fileInfoDict = self.__getFileInfo(root,file)

        if (fileInfoDict['fileExt'] != ".md") or (fileInfoDict['parentDir']==''):
            print("忽略",file,"\n")
            return False            

        #测试输出    
        print(fileInfoDict,"\n")                

        self.__adjustFIleContent(fileInfoDict)
        

    def __getFileInfo(self,root,file):
        print("获取文章信息:\n")
        #文件全路径                
        filePath = os.path.join(root,file)
        #文件名、扩展名
        filename,fileExt = os.path.splitext(file)
        #所在目录及上级目录
        parentDir = os.path.basename(root)
        grandpaDir = os.path.basename(os.path.dirname(root))
        if self.__isIgnoreParentDir(parentDir):        
            parentDir = ""

        if self.__isIgnoreParentDir(grandpaDir):        
            grandpaDir = ""

        #文件相关时间
        fileCtime = self.__timeToDate(os.path.getctime(filePath),"%Y-%m-%d")
        fileMtime = self.__timeToDate(os.path.getmtime(filePath),"%Y-%m-%d")

        return {
            "filePath":filePath,
            "fileName":filename,
            "fileExt":fileExt,
            "parentDir":parentDir,
            "grandpaDir":grandpaDir,
            "fileCtime":fileCtime,
            "fileMtime":fileMtime
        }

    def __isIgnoreParentDir(self,parentDir):
        if parentDir in self.__ignoreParentDir:
            return True

    #调整文章内容 比如meta设置、TOC、MORE设置,
    def __adjustFIleContent(self,fileInfoDict):
        #读取文章内容 及 关键词
        print("读取文章内容...\n")
        with open(fileInfoDict['filePath'],"r",encoding="utf-8") as mdFile:
            content = mdFile.read().strip()            
            
            fileInfoDict['keywords'] = self.__getKeywords(content,fileInfoDict['fileName'])
            
            content = self.__getMmeta(fileInfoDict) + self.__insertMoreToContent(content)

            #写入新文件
            self.__writeNewMarkdownFile(content,fileInfoDict)

    #获取meta
    def __getMmeta(self,fileInfoDict):
        print("准备文章meta信息:","\n")        
        meta = ""
        metaTitle = "title: \""+fileInfoDict['fileName']+"\"\n"
        metaCJK = "isCJKLanguage: true\n"
        metaDate = "date: "+fileInfoDict['fileCtime']+"\n"
        metaCategories = "categories: \n"
        metaParentCategory = ""
        metaGrandpaCategory = ""
        metaTags = "tags: \n"
        metaTagsList = ""
        metaKeywords = "keywords: \n"
        metaKeywordsList = ""


        if fileInfoDict['grandpaDir']!='':
            metaGrandpaCategory = "- "+fileInfoDict['grandpaDir']+"\n"
        
        if fileInfoDict['parentDir']!='':
            metaParentCategory = "- "+fileInfoDict['parentDir']+"\n"
        
        if fileInfoDict['keywords']:
            for word in fileInfoDict['keywords']:
                metaTagsList += "- "+word+"\n"
                metaKeywordsList += "- "+word+"\n"

        meta = "---\n"+metaTitle+metaCJK+metaDate+metaCategories+metaGrandpaCategory+metaParentCategory+metaTags+metaTagsList+metaKeywords+metaKeywordsList+"---\n\n"
        print(meta,"\n")
        return meta

    #插入



到文章
    def __insertMoreToContent(self,content):        
        tocFlag = '<!-- /TOC -->
<!--more-->
'
        if (content.find(tocFlag) != -1):            
            print("发现",tocFlag,"\n")
            content = content.replace(tocFlag,tocFlag+"\n"+'<!--more-->'+"\n")
        else:
            print("没有发现",tocFlag,"\n")
            contents = content.splitlines()
            contentsLen = len(contents)
            if contentsLen>4:
                contents[4] = contents[4]+"\n"+'<!--more-->'+"\n"
                content = "\n".join(contents)

        print("插入<!--more-->...","\n")
        return content

    def __writeNewMarkdownFile(self,content,fileInfoDict):        
        relativeFilePath = fileInfoDict['filePath'].replace(self.__srcDir,"")

        desFilePath = self.__desDir+relativeFilePath
        print("写入新文件:",desFilePath,"\n")
        desDirPath = os.path.dirname(desFilePath)
        # print("##Final Path:"+desFilePath)
        # return 
        if not os.path.exists(desDirPath):
            os.makedirs(desDirPath)
        with open(desFilePath,"w",encoding="utf-8") as nf:
            nf.write(content)

        if os.path.exists(desFilePath):
            print("----- 完成文章处理:",desFilePath," -----\n")
        else:
            print("---- 写入新文件失败! -----\n")

    def __isIgnoreFile(self,file):
        if file in self.__ignoreFile:
            return True

    #时间戳转换成日期
    def __timeToDate(self,timeStamp,format="%Y-%m-%d %H:%M:%S"):
        timeArray = time.localtime(timeStamp)
        return time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
    

    #获取文章关键词
    def __getKeywords(self,content,filename):
        keywords = self.__wordStatistics(content,filename)
        keywordsList = sorted(keywords.items(), key=lambda item:item[1], reverse=True)            
        keywordsList = keywordsList[0:50]   
        keywordsList = self.__filterKeywords(keywordsList,filename)   
        print("保留关键词:",keywordsList,"\n")           
        return keywordsList

    #词频统计
    def __wordStatistics(self,content,filename):        
        stopwords = open('stopwords.txt', 'r', encoding='utf-8').read().split('\n')[:-1]        
        words_dict = {}
    
        temp = jieba.cut(content)
        for t in temp:
            if t in stopwords or t == 'unknow' or t.strip() == "":
                continue
            if t in words_dict.keys():
                words_dict[t] += 1
            else:
                words_dict[t] = 1

        # filenameCuts = jieba.cut(filename)                
        # for fc in filenameCuts:
        #     if fc in stopwords or fc == 'unknow' or fc.strip() == "":
        #         continue
        #     if fc in words_dict.keys():
        #         words_dict[fc] += 100
        #     else:
        #         words_dict[fc] = 100
        return words_dict

    #再次过滤关键词:在文件名也就是标题中,且汉字不少于2个,字符串不少于3个,不是纯数字
    def __filterKeywords(self,keywordsList,filename):
        print("分析文章标签/关键词...\n")
        newKeywordsList = []
        # print(keywordsList)
        # enD = enchant.Dict("en_US")
        for word,count in keywordsList:            

            # print(word,"\t",count)            
            wordLen = len(word)
            if filename.find(word)!=-1:
                if self.__isChinese(word) and wordLen<2:
                    continue
                elif wordLen<3:
                    continue                                        
                elif word.isdigit():
                    continue
                else:
                    newKeywordsList.append(word)
            # else:
            #     if wordLen>1 and self.__isChinese(word) and count>5:
            #         newKeywordsList.append(word)                
            #     elif wordLen>2 and enD.check(word) and count>5:
            #         newKeywordsList.append(word)   
            #     else:
            #         continue

        return newKeywordsList

    def __isChinese(self,word):
        for ch in word:
            if '\u4e00' <= ch <= '\u9fff':
                return True
        return False


if __name__ == '__main__':
    hm = HugoMarkdown()
    #scanFiles 扫描一个目录下所有文件,批量处理
    # hm.scanFiles()

    #单独处理一个文件,覆盖原文件,注意保存
    theFile = input(r'输入文章绝对路径,比如I:\src\xxx\xxx\content\post\其他\xxx.md:')
    hm.scanFile(theFile)
    # theFile = r'I:\srcxxx\xxxx\content\post\其他\xxx.md'

演示日志

这里我们使用处理单个文件scanFile方法进行演示:

Uniapp小程序分包(uniapp分布)都是干货

首先说分包

uniapp分包的方法在开放文档里有,有基础的小伙伴就可以看懂

下面是我在开发中用到的分包 首先 我们在根目录下创建一个pagesB文件夹,用来放置需要分包的页面 下一步是把比较大的文件直接拉过去,pages里就没有这个文件了,然后配置路由

Uniapp配置小程序分包、路由系统跳转

1.分包

简介:

某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。

在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。 所谓的主包,即放置默认启动页面/TabBar页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。

Uni App项目结构及一些坑

需要注意的是:

static目录下的js文件不会被编译,如果里面有es6的代码,不经过转换直接运行,在手机上会报错。 建议在static目录下不要放一些css、less/scss等的资源文件,可以将其放在专门建的公共样式文件目录中。

内网开发服务器环境配置

内网开发服务器环境配置

配置固定IP

1
2
cd /etc/sysconfig/network-scripts/
vim ./ifcfg-eno1

根据你的网络设备情况来,编辑对应的ifcfg文件,例如我是联想ThinkServer TS80X ,对应的配置是ifcfg-eno1

配置内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eno1
UUID=af941b4f-0d3c-4e34-824a-9d3c564cbcb2
DEVICE=eno1
ONBOOT=yes
IPADDR=192.168.1.200
PREFIX=24
GATEWAY=192.168.1.1
DNS1=192.168.1.1
DNS2=8.8.8.8

以上是设置为固定IP 192.168.1.201 DNS是192.168.1.18.8.8.8 ONBOOT=yes 开机启动

为docker创建内部通讯网络

为docker创建内部通讯网络

1
docker network create common-network

安装mongo

1
docker run -itd --name mongo -v /d/docker_data/mogodb/data:/data/db -p 27017:27017 mongo --auth

连接mongo

1
docker exec -it mongo mongosh admin

创建一个名为 admin,密码为 123456 的用户。

1
db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

尝试使用上面创建的用户信息进行连接。

1
db.auth('admin', '123456')

安装mariadb

1
docker  pull  mariadb

持久化 数据卷容器

清除无主的数据卷

1
docker volume prune

创建mariadb数据卷

1
docker  volume  create   mariadb

查看mariadb数据卷

1
docker  volume  inspect  mariadb

查看所有数据卷

1
docker  volume ls

删除数据卷

1
docker volume rm 数据卷名

启动一个挂载数据卷的容器

1
docker  run  -d -P  -e MYSQL_ROOT_PASSWORD=123456 --mount  source=mariadb,target=/opt   --name mysql_volume  mariadb

–mount : 挂载目录(或-v:目录不存在时会自动创建目录) source=:创建的数据卷名(mariadb),或本地目录 target=:挂载到容器中的目录

利用Docker创建内网开发环境

利用Docker创建内网开发环境

服务器地址:192.168.1.200

为docker创建内部通讯网络

1
docker network create common-network

安装mongo

1
docker run -itd --name mongo -v /data/docker_data/mogodb/data:/data/db -p 27017:27017 mongo --auth

连接mongo

1
docker exec -it mongo mongosh admin

创建一个名为 admin,密码为 123456 的用户。

1
db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

尝试使用上面创建的用户信息进行连接。

1
db.auth('admin', '123456')

安装mariadb

1
docker  pull  mariadb

启动mariadb

1
docker  run  -d -p 3306:3306  -v /data/docker_data/mysql/data:/var/lib/mysql  -e MYSQL_ROOT_PASSWORD="123456" --name mariadb  mariadb

安装redis

拉取镜像

Uni App中理解,区分,使用rpx单位和px单位及样式字体的导入

uni-app中的rpx

Tips:

  • uni-app支持的通用css单位包括px,rpx
  • px即屏幕像素
  • rpx 即响应式 px,是一种根据屏幕宽度自适应的动态单位。
  • rpx 以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度 (即 375rpx) 为屏幕一半的宽度);当屏幕变宽时,rpx 实际显示效果也会等比例放大
  • rpx和px的区分和转换:

开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下: