用python写个博客迁移工具
前言
最近不少写博客的朋友跟我反馈博客园的一些文章下架了,这让我联想到去年简书一样,我之前写的博客都被下架不可见了。
我最开始接触的博客网址是 csdn、思否、简书还有博客园等,但是后期发现,单论博客的生态感觉做的越来越不行,干货虽然很多,但是垃圾、标题党很严重,我自己也有一些博文被莫名的搬走直接标为原创。
虽然搜问题在上面还是能搜到很多解决方案,但写作的欲望降低了很多。
综上我从去年入驻掘金,并以掘金作为博客的主平台。个人感觉掘金团队对个人原创的保护是非常好的,同时也在不断的听取用户的建议而去改进。有问题与建议能随时与掘金的同学讨论、沟通,非常方便。
掘金的成长
最开始的时候,掘金也是面试、标题党满天飞,但是掘金的运营大佬逐步整顿起来之后,文章的质量有了显著的提高,并且也不断推出有利于新手作者、高质量博文的各种活动,鼓励新人创作、老人分享。
同样在我入驻掘金之后,作为一个长期用户,新人作者,也是见证了这段时间以来掘金为了社区活跃,博客质量而做的种种努力。
而最开始使用掘金的 markdown,能吐槽的地方还是很多,但掘金的研发也非常给力,吸纳了用户的建议后,最新升级的 markdown 编辑器也是广受好评,使用过你就知道真相定律是什么了。
掘金在使用的时候,一直有种特殊的感觉,是一种很纯粹的 coding 情怀。并不仅仅只是一个单纯的博客平台,而是一直致力于社区共建、开源项目、掘金翻译计划等等的建设,为技术社区打造一片纯粹干净的后花园。
搬家命令行工具
那么作为程序员,手动搬文章显然是略 low 的
所以写了一个简单的 python 脚本,有兴趣的同学可以使用它将 cnblogs 上面已有或者创作中的草稿转移到掘金来。
如果有兴趣可以试试改造的更完美点,但不建议泄露自己的隐私信息
环境配置
脚本跑起来需要 python3 环境,所以先安装一下 python 环境
请在 cookie.json 中补充博客园与掘金的 cookie
使用 python3 main.py -h 查看使用说明
作为程序员应该都了解 cookie 是啥,也知道从哪里捞出来吧
使用方法
还是上个获取 cookie 的图吧,哈哈
请先在 cookie.json 中替换 cookie_cnblogs 与 cookie_juejin 为自己在对应站点上的 cookie
请自行替换user_name与blog_id // 下载单篇文章到默认目录'./cnblogs' 并输出日志到'./log' python3 main.py -m download -a https://www.cnblogs.com/{{user_name}}/p/{{blog_id}}.html --enable_log // 下载用户所有文章到目录'/Users/cnblogs_t' python3 main.py -m download -u https://www.cnblogs.com/{{username}} -p /Users/cnblogs_t // 上传单篇文章到掘金草稿箱 python3 main.py -m upload -f ./cnblogs/{{blog_id}}.html // 上传'./test_blogs'下所有的html文件到掘金草稿箱 python3 main.py -m upload -d ./test_blogs
main.py
新建 main.py 文件,将下述 python 代码复制进去
# coding=utf-8 import requests import os import argparse import sys import json from lxml import etree from urllib.parse import urlparse import logging reload(sys) sys.setdefaultencoding('utf-8') parser = argparse.ArgumentParser() args_dict = {} list_url_tpl = 'https://www.cnblogs.com/%s/default.html?page=%d' draft_url = 'https://api.juejin.cn/content_api/v1/article_draft/create_offline' jj_draft_url_tpl = 'https://juejin.cn/editor/drafts/%s' cnblog_headers = {} log_path = './log' def myget(d, k, v): if d.get(k) is None: return v return d.get(k) def init_parser(): parser.description = 'blog move for cnblogs' parser.add_argument('-m', '--method', type=str, dest='method', help='使用方式: download下载 upload上传到草稿箱', choices=['upload', 'download']) parser.add_argument('-p', '--path', type=str, dest='path', help='博客html下载的路径') parser.add_argument('-d', '--dir', type=str, dest='rec_dir', help='制定要上传的博客所在文件夹') parser.add_argument('-f', '--file', type=str, dest='file', help='指定上传的博客html') parser.add_argument('-u', '--url', type=str, dest='url', help='个人主页地址') parser.add_argument('-a', '--article', type=str, dest='article_url', help='单篇文章地址') parser.add_argument('--enable_log', dest='enable_log', help='是否输出日志到./log', action='store_true') parser.set_defaults(enable_log=False) def init_log(): root_logger = logging.getLogger() log_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)s %(message)s') console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(log_formatter) root_logger.addHandler(console_handler) if myget(args_dict, 'enable_log', False): if not os.path.exists(log_path): os.mkdir(log_path) file_handler = logging.FileHandler('./log/debug.log') file_handler.setFormatter(log_formatter) root_logger.addHandler(file_handler) root_logger.setLevel(logging.INFO) def download(): cookies = json.load(open('cookie.json')) headers = {'cookie': cookies.get('cookie_cnblogs', '')} dir_path = myget(args_dict, 'path', './cnblogs') if dir_path[len(dir_path)-1] == '/': dir_path = dir_path[:len(dir_path)-1] if not os.path.exists(dir_path): os.mkdir(dir_path) article_url = myget(args_dict, 'article_url', '-1') if article_url != '-1': logging.info('article_url=%s', article_url) try: resp = requests.get(article_url, headers=headers) if resp.status_code != 200: logging.error('fail to get blog \'%s\', resp=%s', article_url, resp) return tmp_list = article_url.split('/') blog_id_str = tmp_list[len(tmp_list)-1] with open(dir_path+'/'+blog_id_str, 'w') as f: f.write(resp.text) logging.info('get blog \'%s\' success.', article_url) except Exception as e: logging.error('exception raised, fail to get blog \'%s\', exception=%s.', list_url, e) finally: return raw_url = args_dict.get('url') rurl = urlparse(raw_url) username = (rurl.path.split("/", 1))[1] page_no = 1 while True: list_url = list_url_tpl%(username, page_no) logging.info('list_url = %s', list_url) try: resp = requests.get(list_url, headers=headers) if resp.status_code != 200: break except Exception as e: logging.error('exception raised, fail to get list \'%s\', exception=%s.', list_url, e) return html = etree.HTML(resp.text) blog_list = html.xpath('//div[@class=\'postTitle\']/a/@href') if len(blog_list) == 0: break for blog_url in blog_list: tmp_list = blog_url.split('/') blog_id_str = tmp_list[len(tmp_list)-1] blog_resp = requests.get(blog_url, headers=headers) if resp.status_code != 200: logging.error('fail to get blog \'%s\', resp=%s, skip.', blog_url, resp) continue with open(dir_path+'/'+blog_id_str, 'w') as f: f.write(blog_resp.text) logging.info('get blog \'%s\' success.', blog_url) page_no += 1 def upload_request(headers, content, filename): body = { "edit_type": 0, "origin_type": 2, "content": content } data = json.dumps(body) try: resp = requests.post(draft_url, data=data, headers=headers) if resp.status_code != 200: logging.error('fail to upload blog, filename=%s, resp=%s', filename, resp) return ret = resp.json() draft_id = ret.get('data', {}).get('draft_id', '-1') logging.info('upload success, filename=%s, jj_draft_id=%s, jj_draft_url=%s', filename, draft_id, jj_draft_url_tpl%draft_id) except Exception as e: logging.error('exception raised, fail to upload blog, filename=%s, exception=%s', filename, e) return def upload(): cookies = json.load(open('cookie.json')) headers = { 'cookie': cookies.get('cookie_juejin', ''), 'content-type': 'application/json' } filename = myget(args_dict, 'file', '-1') if filename != '-1': logging.info('upload_filename=%s', filename) try: with open(filename, 'r') as f: content = f.read() upload_request(headers, content, filename) return except Exception as e: logging.error('exception raised, exception=%s', e) rec_dir = myget(args_dict, 'rec_dir', '-1') if rec_dir != '-1': logging.info('upload_dir=%s', filename) try: g = os.walk(rec_dir) for path, dir_list, file_list in g: for filename in file_list: if filename.endswith('.html'): filename = os.path.join(path, filename) with open(filename, 'r') as f: content = f.read() upload_request(headers, content, filename) except Exception as e: logging.error('exception raised, exception=%s', e) return if __name__ == '__main__': init_parser() args = parser.parse_args() args_dict = args.__dict__ init_log() empty_flag = True for k, v in args_dict.items(): if k != 'enable_log' and v is not None: empty_flag = False if empty_flag: parser.print_help() exit(0) if args_dict.get('method') == 'upload': upload() else: download() pass
cookie.json
本地新建 cookie.json 文件,与 main.py 同级
{ "cookie_cnblogs": "请替换为博客园cookie", "cookie_juejin": "请替换为掘金cookie" }
github 地址
最后附上 github 地址,里面除了 demo 的 源码之外也有录制好的一个视频,有兴趣的同学可以下载使用或者研究研究,脚本有问题或者写的不好改进的地方也可以互相探讨下。有意见也可以随时留言反馈
以上就是用python写个博客迁移工具的详细内容,更多关于python 博客迁移的资料请关注猪先飞其它相关文章!
相关文章
- 这篇文章主要介绍了python-opencv-画外接矩形框的实例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-04
Python astype(np.float)函数使用方法解析
这篇文章主要介绍了Python astype(np.float)函数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-08- 2022虎年新年即将来临,小编为大家带来了一个利用Python编写的虎年烟花特效,堪称全网最绚烂,文中的示例代码简洁易懂,感兴趣的同学可以动手试一试...2022-02-14
- 在本篇文章里小编给大家分享的是一篇关于python中numpy.empty()函数实例讲解内容,对此有兴趣的朋友们可以学习下。...2021-02-06
python-for x in range的用法(注意要点、细节)
这篇文章主要介绍了python-for x in range的用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-10- 这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
- 这篇文章主要介绍了Python中的imread()函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
- 这篇文章主要介绍了python如何实现b站直播自动发送弹幕,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-02-20
python Matplotlib基础--如何添加文本和标注
这篇文章主要介绍了python Matplotlib基础--如何添加文本和标注,帮助大家更好的利用Matplotlib绘制图表,感兴趣的朋友可以了解下...2021-01-26- 这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
- 今天小编就为大家分享一篇python 计算方位角实例(根据两点的坐标计算),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
- 这篇文章主要为大家详细介绍了python实现双色球随机选号,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-02
- 在本篇文章里小编给大家整理的是一篇关于python中使用np.delete()的实例方法,对此有兴趣的朋友们可以学习参考下。...2021-02-01
- 这篇文章主要介绍了使用Python的pencolor函数实现渐变色功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-09
- 这篇文章主要介绍了python自动化办公操作PPT的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-05
Python getsizeof()和getsize()区分详解
这篇文章主要介绍了Python getsizeof()和getsize()区分详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-20- 这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-25
- 这篇文章主要介绍了PyTorch一小时掌握之迁移学习篇,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-08
- 这篇文章主要介绍了解决python 两个时间戳相减出现结果错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-12
- 这篇文章主要介绍了Python绘制的爱心树与表白代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06