├── .idea ├── dictionaries │ └── mac.xml └── vcs.xml ├── README.md ├── articles └── __call__.md ├── cnblog.py ├── git └── commit-msg ├── hooks └── commit-msg ├── md文档添加索引.py ├── test └── __call__.md ├── 去除文件名序号.py ├── 批量修改文档内容.py ├── 生成目录.py └── 读取title_postid文件.py /.idea/dictionaries/mac.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 一、cnblogs_automatic_blog_uploading 2 | 3 | 4 | 基于rpcxml协议,利用githook,在commit时自动发布本地markdown文章到博客园,如文章已发布,则会更新。 5 | 6 | # 二、项目地址 7 | 8 | 9 | 项目地址:https://github.com/nickchen121/cnblogs_automatic_blog_uploading 10 | 11 | # 三、参考效果 12 | 13 | 14 | 参考效果:https://www.cnblogs.com/nickchen121/p/10718112.html 15 | 16 | # 四、使用说明 17 | 18 | 19 | 本脚本用`python3.+`编写,请配置好运行环境。 20 | 21 | 1. 第一次使用前先把`./hooks/commit-msg`文件复制到`./.git/hooks/`中(如有则无需修改)。 22 | 2. 运行`cnblogs.py`: 23 | 1. 程序有一个可选参数(如无特殊需求不要添加参数)。 24 | - `config` 设置博客信息。 25 | - `download` 下载文章。 26 | 2. 第一次运行`cnblogs.py`时默认选择`config`参数,设置博客信息,会生成一个`blog_config.json`文件(文件内有博客园账号密码,小心使用)。 27 | 3. 此后每次运行程序时,`./articles/*.md`将被上传到博客并发布;`./unpublished/*.md`将被上传到博客,但不发布(并标注分类“unpublished”)。文章均**以文件名为题**,且不发布的文章。**如果博客中已经存在同名文章,将替换其内容!** 28 | 3. 编辑`./articles/`,`./unpublished/`中markdown文件,在本地git仓库`commit`更改,自动运行`./cnblogs.py`(需要使用终端命令才能查看返回信息)。 29 | 30 | # 五、其他脚本 31 | 32 | 33 | ## 5.1 md文档添加索引 34 | 35 | 36 | 自动给md文档添加索引,即: 37 | 38 | ```python 39 | # 一级标题 40 | 41 | ## 二级标题 42 | ``` 43 | 变为 44 | 45 | ```python 46 | # 一、一级标题 47 | 48 | ## 1.1 二级标题 49 | ``` 50 | 51 | ## 5.2 取出文件名序号 52 | 53 | 54 | 如果你的md文件为`01 第一篇md.md`/`02 第一篇md.md`/`03 第一篇md.md`,则会变成`第一篇md.md`/`第一篇md.md`/`第一篇md.md` 55 | 56 | ## 5.3 批量修改文档内容 57 | 58 | 59 | 选择特定文件目录,批量修改文件下文件的内容,**小心使用**。 60 | 61 | ## 5.4 生成目录 62 | 63 | 64 | 根据特定的字符串,生成特定的目录结构,可以参考:https://www.cnblogs.com/nickchen121/p/10718112.html 65 | 66 | ## 5.5 读取title_postid文件 67 | 68 | 69 | 博客上传成功后,会生成一个`title_postid.json`文件,里面保存了发布成功文件的信息。 70 | 71 | # 六、注意事项(已知Bug) 72 | 73 | 74 | 1. **本程序不保证稳定性**,为防止数据丢失,建议使用前预先备份博客。 75 | 2. clone仓库不能下载`.git`文件夹,因此需要手动复制调用`cnblogs.py`的脚本`./hooks/commit-msg`到`.git`。 76 | 3. 由于metaWeBlog本身没有提供查看文章是否已发布的接口,所有使用“unpublished”分类标注未发布文章。也就是说,**当执行`python cnblogs.py download`命令时,博客中没有发布也没有“unpublished”分类的文章也会存到`./articles/`,下次运行时将被自动发布。** 77 | 4. 由于接口不允许将已经发布的文章设置为未发布,所以若`./unpublished/`内的文章在博客内有同名文章时不会被上传。 -------------------------------------------------------------------------------- /articles/__call__.md: -------------------------------------------------------------------------------- 1 | ``` 2 | sdkfs 3 | 4 | # fdsf 5 | ``` 6 | 7 | # 一、yiji 8 | 9 | 10 | ## 1.1 erji 11 | 12 | 13 | # 二、erjiji 14 | 15 | 16 | ``` 17 | sdkfs 18 | 19 | # fdsf 20 | ``` 21 | 22 | # 三、yiji 23 | 24 | 25 | ## 3.1 erji 26 | 27 | 28 | # 四、erjiji 29 | -------------------------------------------------------------------------------- /cnblog.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | # 使用python xmlrpc 发送内容到博客园 5 | # http://rpc.cnblogs.com/metaweblog/nickchen121 从链接可以看到支持的metaweblog API 6 | import xmlrpc.client as xmlrpclib 7 | import glob 8 | import os 9 | import sys 10 | import json 11 | import time 12 | import datetime 13 | import ssl 14 | ssl._create_default_https_context = ssl._create_unverified_context 15 | 16 | # 发布文章路径(article path) 17 | art_path = "./articles/" 18 | # 不发布文章路径(unpublished article path) 19 | unp_path = "./unpublished/" 20 | # 博客配置路径(config path) 21 | cfg_path = "blog_config.json" 22 | # 备份路径(backup path) 23 | bak_path = "./backup/" 24 | # 获取文章篇数 25 | recentnum = 99999 26 | 27 | # 创建路径 28 | for path in [art_path, unp_path, bak_path]: 29 | if not os.path.exists(path): 30 | os.makedirs(path) 31 | 32 | # -----配置读写操作----- 33 | ''' 34 | 配置字典: 35 | type | description(example) 36 | str | metaWeblog url, 博客设置中有('https://rpc.cnblogs.com/metaweblog/nickchen121') 37 | str | appkey, Blog地址名('nickchen121') 38 | str | blogid, 这个无需手动输入,通过getUsersBlogs得到 39 | str | usr, 登录用户名 40 | str | passwd, 登录密码 41 | ''' 42 | 43 | 44 | def exist_cfg(): 45 | ''' 46 | 返回配置是否存在 47 | ''' 48 | try: 49 | with open(cfg_path, "r", encoding="utf-8") as f: 50 | try: 51 | cfg = json.load(f) 52 | if cfg == {}: 53 | return False 54 | else: 55 | return True 56 | except json.decoder.JSONDecodeError: # 文件为空 57 | return False 58 | except: 59 | with open(cfg_path, "w", encoding="utf-8") as f: 60 | json.dump({}, f) 61 | return False 62 | 63 | 64 | def create_cfg(): 65 | ''' 66 | 创建配置 67 | ''' 68 | while True: 69 | cfg = {} 70 | for item in [("url", "metaWeblog url, 博客设置中有\ 71 | ('https://rpc.cnblogs.com/metaweblog/blogaddress')"), 72 | ("appkey", "Blog地址名('blogaddress')"), 73 | ("usr", "登录用户名"), 74 | ("passwd", "登录密码")]: 75 | cfg[item[0]] = input("输入" + item[1]) 76 | try: 77 | server = xmlrpclib.ServerProxy(cfg["url"]) 78 | userInfo = server.blogger.getUsersBlogs( 79 | cfg["appkey"], cfg["usr"], cfg["passwd"]) 80 | print(userInfo[0]) 81 | # {'blogid': 'xxx', 'url': 'xxx', 'blogName': 'xxx'} 82 | cfg["blogid"] = userInfo[0]["blogid"] 83 | break 84 | except: 85 | print("发生错误!") 86 | with open(cfg_path, "w", encoding="utf-8") as f: 87 | json.dump(cfg, f, indent=4, ensure_ascii=False) 88 | 89 | 90 | url = appkey = blogid = usr = passwd = "" 91 | server = None 92 | mwb = None 93 | title2id = {} 94 | 95 | 96 | def get_cfg(): 97 | global url, appkey, blogid, usr, passwd, server, mwb, title2id 98 | with open(cfg_path, "r", encoding="utf-8") as f: 99 | cfg = json.load(f) 100 | url = cfg["url"] 101 | appkey = cfg["appkey"] 102 | blogid = cfg["blogid"] 103 | usr = cfg["usr"] 104 | passwd = cfg["passwd"] 105 | server = xmlrpclib.ServerProxy(cfg["url"]) 106 | mwb = server.metaWeblog 107 | # title2id[title]=postid 储存博客中文章标题对应的postid 108 | print(cfg["blogid"], cfg["usr"], recentnum) 109 | recentPost = mwb.getRecentPosts( 110 | cfg["blogid"], cfg["usr"], cfg["passwd"], recentnum) 111 | for post in recentPost: 112 | # 1.把datetime转成字符串 113 | dt = post["dateCreated"] 114 | # post["dateCreated"] = dt.strftime("%Y%m%dT%H:%M:%S") 115 | post["dateCreated"] = dt.__str__() 116 | # 2.把字符串转成datetime 117 | # datetime.datetime.strptime(st, "%Y%m%dT%H:%M:%S") 118 | # datetime.datetime.fromisoformat(str) 119 | title2id[post["title"]] = post["postid"] 120 | # 格式化成20160320-114539形式 121 | filename = time.strftime("%Y%m%d-%H%M%S", time.localtime()) 122 | with open(bak_path + filename + ".json", "w", encoding="utf-8") as f: 123 | json.dump(recentPost, f, indent=4) 124 | 125 | 126 | # server = xmlrpclib.ServerProxy(url) 127 | # userInfo = server.blogger.getUsersBlogs(appkey, usr, passwd) 128 | # recentPost = mwb.getRecentPosts(blogid, usr, passwd, 9) 129 | def newPost(blogid, usr, passwd, post, publish): 130 | while True: 131 | try: 132 | postid = mwb.newPost(blogid, usr, passwd, post, publish) 133 | break 134 | except: 135 | time.sleep(5) 136 | return postid 137 | 138 | 139 | def post_art(path, publish=True): 140 | title = os.path.basename(path) # 获取文件名做博客文章标题 141 | [title, _] = os.path.splitext(title) # 去除扩展名 142 | with open(mdfile, "r", encoding="utf-8") as f: 143 | post = dict(description=f.read(), title=title) 144 | post["categories"] = ["[Markdown]"] 145 | 146 | # 判断是否发布 147 | if not publish: # 不发布 148 | # 对于已经发布的文章,直接修改为未发布会报错: 149 | # xmlrpc.client.Fault: <'published post can not be saved as draft'> 150 | # 所以先删除这个文章 151 | # if title in title2id.keys(): 152 | # server.blogger.deletePost( 153 | # appkey, title2id[title], usr, passwd, True) 154 | if title not in title2id.keys(): 155 | post["categories"].append('[随笔分类]unpublished') # 标记未发布 156 | # post["postid"] = title2id[title] 157 | postid = newPost(blogid, usr, passwd, post, publish) 158 | print("New:[title=%s][postid=%s][publish=%r]" % 159 | (title, postid, publish)) 160 | 161 | filepath_ = os.path.join('./unpublished/', f'{title}.md') 162 | os.remove(filepath_) 163 | 164 | return (title, postid, publish) 165 | else: # 发布 166 | if title in title2id.keys(): # 博客里已经存在这篇文章 167 | mwb.editPost(title2id[title], usr, passwd, post, publish) 168 | print("Update:[title=%s][postid=%s][publish=%r]" % 169 | (title, title2id[title], publish)) 170 | 171 | filepath_ = os.path.join('./articles/', f'{title}.md') 172 | os.remove(filepath_) 173 | 174 | return (title, title2id[title], publish) 175 | 176 | else: # 博客里还不存在这篇文章 177 | postid = newPost(blogid, usr, passwd, post, publish) 178 | print("New:[title=%s][postid=%s][publish=%r]" % 179 | (title, postid, publish)) 180 | 181 | filepath_ = os.path.join('./articles/', f'{title}.md') 182 | os.remove(filepath_) 183 | 184 | return (title, postid, publish) 185 | 186 | 187 | def download_art(): 188 | """下载文章""" 189 | # 获取最近文章,并获取所有文章信息 190 | recentPost = mwb.getRecentPosts(blogid, usr, passwd, recentnum) 191 | for post in recentPost: 192 | if "categories" in post.keys(): 193 | if '[随笔分类]unpublished' in post["categories"]: 194 | with open(unp_path + post["title"] + ".md", 195 | "w", encoding="utf-8") as f: 196 | f.write(post["description"]) 197 | else: 198 | with open(art_path + post["title"] + ".md", 199 | "w", encoding="utf-8") as f: 200 | f.write(post["description"]) 201 | 202 | 203 | if __name__ == "__main__": 204 | 205 | title_postid_dict = dict() 206 | 207 | try: 208 | # 创建用户配置 209 | if not exist_cfg(): 210 | create_cfg() 211 | 212 | # 获取文章参数 213 | get_cfg() 214 | 215 | # 配置用户参数 216 | if len(sys.argv) > 1: 217 | if sys.argv[1] == "download": 218 | download_art() 219 | elif sys.argv[1] == "config": 220 | create_cfg() 221 | get_cfg() 222 | 223 | # 发布文章 224 | for mdfile in glob.glob(art_path + "*.md"): 225 | title, postid, publish = post_art(mdfile, True) 226 | title_postid_dict[title] = postid 227 | 228 | # 提交文章不发布 229 | for mdfile in glob.glob(unp_path + "*.md"): 230 | title, postid, publish = post_art(mdfile, False) 231 | except KeyboardInterrupt: 232 | with open('title_postid.json', 'w', encoding='utf8') as fw: 233 | json.dump(title_postid_dict, fw) 234 | 235 | with open('title_postid.json', 'w', encoding='utf8') as fw: 236 | json.dump(title_postid_dict, fw) 237 | -------------------------------------------------------------------------------- /git/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | # test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | # sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | # echo >&2 Duplicate Signed-off-by lines. 23 | # exit 1 24 | # } 25 | 26 | chmod +x ./cnblog.py 27 | ./cnblog.py -------------------------------------------------------------------------------- /hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | # test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | # sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | # echo >&2 Duplicate Signed-off-by lines. 23 | # exit 1 24 | # } 25 | 26 | chmod +x ./cnblog.py 27 | ./cnblog.py -------------------------------------------------------------------------------- /md文档添加索引.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | def md_add_index(dic, filename): 6 | """给没有序列的markdown文档自动添加序列号""" 7 | one_count = 0 8 | two_count = 0 9 | three_count = 0 10 | four_count = 0 11 | five_count = 0 12 | six_count = 0 13 | 14 | str = '' 15 | with open(filename, 'r', encoding='utf8') as fr: 16 | # 对1-6级标题做处理 17 | judge_py_code = 1 18 | for i in fr: 19 | if i.startswith('```') and judge_py_code == 1: 20 | judge_py_code -= 1 21 | str += i 22 | continue 23 | if i.startswith('```') and judge_py_code == 0: 24 | judge_py_code += 1 25 | str += i 26 | continue 27 | 28 | if i.startswith('# ') and judge_py_code: 29 | str += f'# {dic[one_count+1]}、{i.replace("# ","")}\n' 30 | one_count += 1 31 | two_count = 0 32 | continue 33 | elif i.startswith('## ') and judge_py_code: 34 | str += f'## {one_count}.{two_count+1} {i.replace("## ","")}\n' 35 | two_count += 1 36 | three_count = 0 37 | continue 38 | elif i.startswith('### ') and judge_py_code: 39 | str += f'### {one_count}.{two_count}.{three_count+1} {i.replace("### ","")}\n' 40 | three_count += 1 41 | four_count = 0 42 | continue 43 | elif i.startswith('#### ') and judge_py_code: 44 | str += f'#### {one_count}.{two_count}.{three_count}.{four_count+1} {i.replace("#### ","")}\n' 45 | four_count += 1 46 | five_count = 0 47 | continue 48 | elif i.startswith('##### ') and judge_py_code: 49 | str += f'##### {one_count}.{two_count}.{three_count}.{four_count}.{five_count+1} {i.replace("##### ","")}\n' 50 | five_count += 1 51 | six_count = 0 52 | continue 53 | elif i.startswith('###### ') and judge_py_code: 54 | str += f'###### {one_count}.{two_count}.{three_count}.{four_count}.{five_count}.{six_count+1} {i.replace("###### ","")}\n' 55 | six_count += 1 56 | continue 57 | 58 | str += i 59 | 60 | with open(filename, 'w', encoding='utf8') as fw: 61 | fw.write(str) 62 | fw.flush() 63 | 64 | 65 | def get_chinese_num(): 66 | """将1-99转换为汉字""" 67 | dic = {1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '七', 8: '八', 9: '九', 10: '十'} 68 | 69 | for num in range(10, 100): 70 | if num > 10 and num < 20: 71 | str_num = f'十{dic[num-10]}' 72 | dic[num] = str_num 73 | elif num % 10 == 0: 74 | dic[num] = f'{dic[num//10]}十' 75 | elif num > 20 and num < 100: 76 | str_num = f'{dic[num//10]}十{dic[num%10]}' 77 | dic[num] = str_num 78 | return dic 79 | 80 | 81 | def run(directo): 82 | """运行函数,可以传入文件夹,也可以传入文件""" 83 | dic = get_chinese_num() 84 | count = 0 85 | if os.path.isdir(directo): 86 | for filename in os.listdir(directo): 87 | if filename.split('.')[-1] == 'md': 88 | new_filename = os.path.join(directo, filename) 89 | try: 90 | md_add_index(dic, new_filename) 91 | except UnicodeDecodeError: 92 | print(f'{filename} wrong') 93 | continue 94 | count += 1 95 | print(f'{filename}替换成功, {count}') 96 | elif os.path.isfile(directo): 97 | md_add_index(dic, directo) 98 | print(f'{directo}替换成功') 99 | 100 | 101 | if __name__ == '__main__': 102 | try: 103 | directo = sys.argv[1] 104 | except IndexError: 105 | directo = '/Users/mac/Desktop/jupyter/cnblogs_automatic_blog_uploading/articles' 106 | # directo = '/Users/mac/Desktop/jupyter/cnblogs_automatic_blog_uploading/test' 107 | # directo = '/Users/mac/Desktop/jupyter/课件/nick/python' 108 | run(directo) 109 | -------------------------------------------------------------------------------- /test/__call__.md: -------------------------------------------------------------------------------- 1 | ``` 2 | sdkfs 3 | 4 | # fdsf 5 | ``` 6 | 7 | # 一、yiji 8 | 9 | 10 | ## 1.1 erji 11 | 12 | 13 | # 二、erjiji 14 | 15 | 16 | ``` 17 | sdkfs 18 | 19 | # fdsf 20 | ``` 21 | 22 | # 三、yiji 23 | 24 | 25 | ## 3.1 erji 26 | 27 | 28 | # 四、erjiji 29 | -------------------------------------------------------------------------------- /去除文件名序号.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | import os 5 | 6 | BATH = '/Users/mac/Desktop/jupyter/cnblogs_automatic_blog_uploading/articles' 7 | for filename in os.listdir(BATH): 8 | if filename.endswith('md'): 9 | old_name = os.path.join(BATH, filename) 10 | new_name = os.path.join(BATH, filename.split()[1]) 11 | # print(old_name,new_name) 12 | os.rename(old_name, new_name) 13 | -------------------------------------------------------------------------------- /批量修改文档内容.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | import os 4 | import re 5 | import time 6 | 7 | 8 | def modify_md_content(top): 9 | for root, dirs, files in os.walk(top, topdown=False): 10 | # 循环文件 11 | for file_name in files: 12 | file_name_split = file_name.split('.') 13 | 14 | try: 15 | if file_name_split[-1] == 'ipynb': 16 | # 找到md文件并且复制一份md文件路径 17 | md_file_path = os.path.join(root, '.'.join(file_name_split)) 18 | copy_md_file_path = os.path.join(root, '.'.join([f'{file_name_split[0]}_copy', file_name_split[1]])) 19 | 20 | # 打开md文件然后进行替换 21 | with open(md_file_path, 'r', encoding='utf8') as fr, \ 22 | open(copy_md_file_path, 'w', encoding='utf8') as fw: 23 | 24 | data = fr.read() 25 | # data = re.sub('.jpg', '.jpg?x-oss-process=style/watermark', data) 26 | # data = re.sub('.png', '.png?x-oss-process=style/watermark', data) 27 | data = re.sub('\?x-oss-process=style/watermark\?x-oss-process=style/watermark', '?x-oss-process=style/watermark', data) 28 | # print(data) 29 | # data = re.sub('
', '
\n', data) 30 | # data = re.sub('
', '', data) 31 | # data = re.sub('^[TOC] #.*? ', '', data) 32 | 33 | fw.write(data) # 新文件一次性写入原文件内容 34 | # fw.flush() 35 | 36 | # 删除原文件 37 | os.remove(md_file_path) 38 | # 重命名新文件名为原文件名 39 | os.rename(copy_md_file_path, md_file_path) 40 | print(f'{md_file_path} done...') 41 | time.sleep(0.5) 42 | except FileNotFoundError as e: 43 | print(e) 44 | time.sleep(0.5) 45 | 46 | 47 | if __name__ == '__main__': 48 | top = r'/Users/mac/Desktop/jupyter/课件/nick/python' 49 | modify_md_content(top) 50 | -------------------------------------------------------------------------------- /生成目录.py: -------------------------------------------------------------------------------- 1 | url_title_str = ''' 2 | 10821946 markdown基本语法 3 | 4 | 10721884 计算机基础之编程 5 | 10715496 计算机组成原理 6 | 10721933 计算机操作系统 7 | 10722720 编程语言分类 8 | 11069962 网络的瓶颈效应 9 | 10 | 11069964 计算机基础小结 11 | 12 | 10722729 Python和Python解释器 13 | 11069968 Python解释器安装 14 | 11107842 Anaconada安装 15 | 10888887 Python解释器镜像源修改 16 | 10722731 执行Python程序的两种方式 17 | 10722733 Python集成开发环境之Pycharm的使用 18 | 10531966 Python集成开发环境之Jupyter的使用 19 | 20 | 11070551 Python解释器和Python集成环境小结 21 | 22 | 10722738 变量 23 | 11069975 常量 24 | 10731690 Python变量内存管理 25 | 10731697 变量的三个特征 26 | 11069978 花式赋值 27 | 11069981 注释 28 | 10728220 数据类型基础 29 | 10728233 数字类型 30 | 10728244 字符串类型 31 | 10728254 列表类型 32 | 10728262 字典类型 33 | 10728270 布尔类型 34 | 11069984 解压缩 35 | 10728278 Python与用户交互 36 | 10728289 格式化输出的三种方式 37 | 10728299 基本运算符 38 | 10737326 流程控制之if判断 39 | 10737337 流程控制之while循环 40 | 10737348 流程控制之for循环 41 | 42 | 11069987 Python基础小结 43 | 11069989 Python基础实战之猜年龄游戏 44 | 45 | 10993377 异常处理 46 | 11069994 Python深浅拷贝 47 | 10739861 数字类型内置方法 48 | 10740498 字符串类型内置方法 49 | 10741860 列表类型内置方法 50 | 10742427 元组类型内置方法 51 | 10744137 字典类型内置方法 52 | 10744169 集合类型内置方法 53 | 10745614 数据类型分类 54 | 55 | 11069996 Python进阶小结 56 | 11069998 Python进阶实战之三级菜单 57 | 58 | 10745620 字符编码 59 | 10745637 Python2和3字符编码的区别 60 | 10749347 基本的文件操作 61 | 10749338 绝对路径和相对路径 62 | 10750262 文件的三种打开模式 63 | 10750390 with管理文件操作上下文 64 | 10751104 文件的高级应用 65 | 10752250 文件修改的两种方式 66 | 67 | 68 | 11070002 文件处理小结 69 | 11070005 文件处理实战之购物车系统 70 | 71 | 10754505 函数的定义 72 | 10754828 定义函数的三种形式 73 | 10756633 函数的返回值 74 | 10756785 函数的调用 75 | 10757181 函数的参数 76 | 10758610 可变长参数 77 | 10760382 函数对象 78 | 10760437 函数嵌套 79 | 10761575 名称空间和作用域 80 | 81 | 11070432 函数基础小结 82 | 11070436 函数基础实战之ATM和购物车系统 83 | 84 | 85 | 10769394 闭包函数 86 | 10771174 装饰器 87 | 10778506 迭代器 88 | 10778650 三元表达式 89 | 11125713 列表推导式 90 | 10778757 字典生成式 91 | 10779713 生成器 92 | 10791260 递归 93 | 10793551 匿名函数 94 | 10796073 内置函数 95 | 10799173 面向过程编程 96 | 97 | 98 | 11106249 函数高级小结 99 | 11125925 函数高级实战之ATM和购物车系统升级 100 | 101 | 10802050 模块的四种形式 102 | 10802052 import和from...import 103 | 10802260 循环导入问题 104 | 10802417 模块的搜索路径 105 | 10802423 Python文件的两种用途 106 | 10802465 编译Python文件(了解) 107 | 10804427 包 108 | 10802707 软件开发目录规范 109 | 110 | 11070439 模块基础小结 111 | 11070441 模块基础实战之ATM和购物车系统分文件处理 112 | 113 | 10807493 time模块 114 | 10807548 datetime模块 115 | 10807555 random模块 116 | 10807556 os模块 117 | 10807558 sys模块 118 | 10807559 json和pickle模块 119 | 10807561 hashlib和hmac模块 120 | 10804432 logging模块 121 | 10807564 numpy模块 122 | 10807568 pandas模块 123 | 10807571 matplotlib模块 124 | 10808645 re模块 125 | 11013953 typing模块 126 | 10807811 shutil模块(了解) 127 | 10807967 xml模块(了解) 128 | 10807985 subprocess模块(了解) 129 | 130 | 10532049 Python常用模块小结 131 | 10796123 Python常用模块实战之ATM和购物车系统再升级 132 | 133 | 10981462 面向对象程序设计的由来(了解) 134 | 10982086 面向对象编程介绍 135 | 10982270 类和对象 136 | 10986649 定制对象独有特征 137 | 10986857 对象的属性查找顺序 138 | 10987600 对象的绑定方法 139 | 10987642 类和数据类型 140 | 10987699 对象的高度整合 141 | 142 | 11070451 面向对象基础小结 143 | 11045903 面向对象基础实战之英雄联盟 144 | 145 | 10987832 类的继承 146 | 10987834 类的派生 147 | 10988446 类的组合 148 | 10272737 菱形继承问题 149 | 11053268 super()方法详解 150 | 10989309 类的多态和多态性 151 | 10989430 类的封装 152 | 10990412 类的property特性 153 | 10990544 类和对象的绑定方法及非绑定方法 154 | 155 | 156 | 11070457 面向对象进阶小结 157 | 10990797 面向对象进阶实战之选课系统 158 | 159 | 10991110 isinstance和issubclass 160 | 10990781 反射(hasattr和getattr和setattr和delattr) 161 | 10991163 __setattr__和__delattr__和__getattr__ 162 | 10991198 __getattribute__ 163 | 10991295 描述符(__get__和__set__和__delete__) 164 | 10991309 __setitem__和__getitem和__delitem__ 165 | 10991480 __format__ 166 | 10991095 __del__ 167 | 10991340 __slots__ 168 | 10991464 __doc__ 169 | 10991472 __call__ 170 | 11061527 __init__和__new__ 171 | 10990811 __str__和__repr__ 172 | 10991493 实现迭代器(__next__和__iter__) 173 | 10991513 __module__和__class__ 174 | 10991541 实现文件上下文管理(__enter__和__exit__) 175 | 10992975 元类(metaclass) 176 | 177 | 11070460 面向对象高级小结 178 | 10272688 面向对象高级实战之单例模式 179 | 180 | 11004951 网络架构及其演变过程 181 | 11004980 互联网和互联网的组成 182 | 11027196 大白话OSI七层协议 183 | 11027575 TCP协议的三次握手和四次挥手 184 | 11028147 基于TCP协议的socket套接字编程 185 | 11080518 Socket抽象层 186 | 11030880 模拟ssh远程执行命令 187 | 11031027 粘包问题 188 | 11032005 解决粘包问题 189 | 11032116 基于UDP协议的socket套接字编程 190 | 11032290 基于socketserver实现并发的socket套接字编程 191 | 192 | 11070465 网络编程小结 193 | 11032332 网络编程实战之FTP的文件断点续传 194 | 195 | 11130272 操作系统的发展史 196 | 11130244 进程基础 197 | 11130238 进程调度 198 | 11130250 进程的并行和并发 199 | 11130263 同步异步阻塞非阻塞 200 | 11130239 进程的创建和结束 201 | 11130256 Python程序中的进程操作-开启多进程(multiprocess.process) 202 | 11130253 Python程序中的进程操作-进程同步(multiprocess.Lock) 203 | 11130293 Python程序中的进程操作-进程间通信(multiprocess.Queue) 204 | 11130265 Python程序中的进程操作-进程间数据共享(multiprocess.Manager) 205 | 11130258 Python程序中的进程操作-进程池(multiprocess.Pool) 206 | 207 | 10840284 TensorFlow2 208 | 10802091 机器学习 209 | 10825705 Python能干啥 210 | 11087801 我真的还是18岁的那个我 211 | ''' 212 | 213 | import re 214 | 215 | url_title_list = re.findall('(\d{8} .*?)\n', url_title_str) 216 | 217 | url_title_result = '' 218 | count = 1 219 | for url_title in url_title_list: 220 | url_title_split = url_title.split() 221 | url_ = url_title_split[0] 222 | url = f'https://www.cnblogs.com/nickchen121/p/{url_}.html' 223 | title = url_title_split[1] 224 | 225 | if '小结' in title or '实战' in title: 226 | url_title_str = f'
{str(count).zfill(3)} {title}
\n' 227 | else: 228 | url_title_str = f'
{str(count).zfill(3)} {title}
\n' 229 | 230 | if title == 'markdown基本语法': 231 | url_title_str = '

第一篇 markdown编辑器


\n\n' + url_title_str 232 | elif title == '计算机基础之编程': 233 | url_title_str = '\n

第二篇 计算机基础


\n\n' + url_title_str 234 | elif title == 'Python和Python解释器': 235 | url_title_str = '\n

第三篇 Python解释器和集成环境


\n\n' + url_title_str 236 | elif title == '变量': 237 | url_title_str = '\n

第三篇 Python基础


\n\n' + url_title_str 238 | elif title == '异常处理': 239 | url_title_str = '\n

第四篇 Python进阶


\n\n' + url_title_str 240 | elif title == '字符编码': 241 | url_title_str = '\n

第五篇 文件处理


\n\n' + url_title_str 242 | elif title == '函数的定义': 243 | url_title_str = '\n

第六篇 函数基础


\n\n' + url_title_str 244 | elif title == '闭包函数': 245 | url_title_str = '\n

第七篇 函数进阶


\n\n' + url_title_str 246 | elif title == '模块的四种形式': 247 | url_title_str = '\n

第八篇 模块基础


\n\n' + url_title_str 248 | elif title == 'time模块': 249 | url_title_str = '\n

第九篇 Python常用模块


\n\n' + url_title_str 250 | elif title == '面向对象程序设计的由来(了解)': 251 | url_title_str = '\n

第十篇 面向对象基础


\n\n' + url_title_str 252 | elif title == '类的继承': 253 | url_title_str = '\n

第十一篇 面向对象进阶


\n\n' + url_title_str 254 | elif title == 'isinstance和issubclass': 255 | url_title_str = '\n

第十二篇 面向对象高阶


\n\n' + url_title_str 256 | elif title == '网络架构及其演变过程': 257 | url_title_str = '\n

第十三篇 网络编程


\n\n' + url_title_str 258 | elif title == '操作系统的发展史': 259 | url_title_str = '\n

第十四篇 并发编程


\n\n' + url_title_str 260 | elif title == 'TensorFlow2': 261 | url_title_str = '\n

第十五篇 推荐阅读


\n\n' + url_title_str 262 | 263 | url_title_result += url_title_str 264 | 265 | count += 1 266 | 267 | url_title_result += '\n
debugging……
' 268 | 269 | print(url_title_result) -------------------------------------------------------------------------------- /读取title_postid文件.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | with open('title_postid.json','rb') as fr: 4 | data = json.load(fr) 5 | 6 | s = ''' 7 | 11130272 操作系统的发展史 8 | 11130244 进程基础 9 | 11130238 进程调度 10 | 11130250 进程的并行和并发 11 | 11130263 同步异步阻塞非阻塞 12 | 11130239 进程的创建和结束 13 | 11130256 Python程序中的进程操作-开启多进程(multiprocess.process) 14 | 11130253 Python程序中的进程操作-进程同步(multiprocess.Lock) 15 | 11130293 Python程序中的进程操作-进程间通信(multiprocess.Queue) 16 | 11130265 Python程序中的进程操作-进程间数据共享(multiprocess.Manager) 17 | 11130258 Python程序中的进程操作-进程池(multiprocess.Pool) 18 | ''' 19 | 20 | for k,v in data.items(): 21 | if k in s: 22 | print(k,v) --------------------------------------------------------------------------------