├── .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'
\n'
227 | else:
228 | url_title_str = f'\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'
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)
--------------------------------------------------------------------------------