• 售前

  • 售后

热门帖子
入门百科

用python写个博客迁移工具

[复制链接]
科林回拔 显示全部楼层 发表于 2021-10-26 13:44:14 |阅读模式 打印 上一主题 下一主题
目次


  • 前言
  • 掘金的成长
  • 搬家下令行工具

    • 情况设置
    • main.py
    • cookie.json

  • github 所在

前言


最近不少写博客的朋侪跟我反馈博客园的一些文章下架了,这让我遐想到客岁简书一样,我之前写的博客都被下架不可见了。
我最开始打仗的博客网址是 caogenba、思否、简书还有博客园等,但是后期发现,单论博客的生态感觉做的越来越不可,干货虽然很多,但是垃圾、标题党很严峻,我自己也有一些博文被莫名的搬走直接标为原创。
虽然搜问题在上面还是能搜到很多解决方案,但写作的欲望降低了很多。
综上我从客岁入驻掘金,并以掘金作为博客的主平台。个人感觉掘金团队对个人原创的掩护黑白常好的,同时也在不断的听取用户的发起而去改进。有问题与发起能随时与掘金的同砚讨论、沟通,非常方便。

掘金的成长


最开始的时间,掘金也是口试、标题党满天飞,但是掘金的运营大佬逐步整理起来之后,文章的质量有了明显的提高,并且也不断推出有利于新手作者、高质量博文的各种活动,鼓励新人创作、老人分享。
同样在我入驻掘金之后,作为一个恒久用户,新人作者,也是见证了这段时间以来掘金为了社区活泼,博客质量而做的种种积极。
而最开始使用掘金的 markdown,能吐槽的地方还是很多,但掘金的研发也非常给力,吸纳了用户的发起后,最新升级的 markdown 编辑器也是广受好评,使用过你就知道真相定律是什么了。
掘金在使用的时间,一直有种特殊的感觉,是一种很纯粹的 coding 情怀。并不仅仅只是一个单纯的博客平台,而是一直致力于社区共建、开源项目、掘金翻译筹划等等的建设,为技术社区打造一片纯粹干净的后花园。

搬家下令行工具


那么作为程序员,手动搬文章显然是略 low 的
以是写了一个简单的 python 脚本,有爱好的同砚可以使用它将 cnblogs 上面已有或者创作中的草稿转移到掘金来。
如果有爱好可以试试改造的更完善点,但不发起走漏自己的隐私信息

情况设置


脚本跑起来需要 python3 情况,以是先安装一下 python 情况
请在 cookie.json 中增补博客园与掘金的 cookie
使用 python3 main.py -h 查看使用说明
作为程序员应该都相识 cookie 是啥,也知道从哪里捞出来吧
使用方法

还是上个获取 cookie 的图吧,哈哈
请先在 cookie.json 中替换 cookie_cnblogs 与 cookie_juejin 为自己在对应站点上的 cookie
  1. 请自行替换user_name与blog_id
  2. // 下载单篇文章到默认目录'./cnblogs' 并输出日志到'./log'
  3. python3 main.py -m download -a https://www.cnblogs.com/{{user_name}}/p/{{blog_id}}.html --enable_log
  4. // 下载用户所有文章到目录'/Users/cnblogs_t'
  5. python3 main.py -m download -u https://www.cnblogs.com/{{username}} -p /Users/cnblogs_t
  6. // 上传单篇文章到掘金草稿箱
  7. python3 main.py -m upload -f ./cnblogs/{{blog_id}}.html
  8. // 上传'./test_blogs'下所有的html文件到掘金草稿箱
  9. python3 main.py -m upload -d ./test_blogs
复制代码
main.py


新建 main.py 文件,将下述 python 代码复制进去
  1. # coding=utf-8
  2. import requests
  3. import os
  4. import argparse
  5. import sys
  6. import json
  7. from lxml import etree
  8. from urllib.parse import urlparse
  9. import logging
  10. reload(sys)
  11. sys.setdefaultencoding('utf-8')
  12. parser = argparse.ArgumentParser()
  13. args_dict = {}
  14. list_url_tpl = 'https://www.cnblogs.com/%s/default.html?page=%d'
  15. draft_url = 'https://api.juejin.cn/content_api/v1/article_draft/create_offline'
  16. jj_draft_url_tpl = 'https://juejin.cn/editor/drafts/%s'
  17. cnblog_headers = {}
  18. log_path = './log'
  19. def myget(d, k, v):
  20. if d.get(k) is None:
  21.   return v
  22. return d.get(k)
  23. def init_parser():
  24. parser.description = 'blog move for cnblogs'
  25. parser.add_argument('-m', '--method', type=str, dest='method', help='使用方式: download下载 upload上传到草稿箱', choices=['upload', 'download'])
  26. parser.add_argument('-p', '--path', type=str, dest='path', help='博客html下载的路径')
  27. parser.add_argument('-d', '--dir', type=str, dest='rec_dir', help='制定要上传的博客所在文件夹')
  28. parser.add_argument('-f', '--file', type=str, dest='file', help='指定上传的博客html')
  29. parser.add_argument('-u', '--url', type=str, dest='url', help='个人主页地址')
  30. parser.add_argument('-a', '--article', type=str, dest='article_url', help='单篇文章地址')
  31. parser.add_argument('--enable_log', dest='enable_log', help='是否输出日志到./log', action='store_true')
  32. parser.set_defaults(enable_log=False)
  33. def init_log():
  34. root_logger = logging.getLogger()
  35. log_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)s %(message)s')
  36. console_handler = logging.StreamHandler(sys.stdout)
  37. console_handler.setFormatter(log_formatter)
  38. root_logger.addHandler(console_handler)
  39. if myget(args_dict, 'enable_log', False):
  40.   if not os.path.exists(log_path):
  41.    os.mkdir(log_path)
  42.   file_handler = logging.FileHandler('./log/debug.log')
  43.   file_handler.setFormatter(log_formatter)
  44.   root_logger.addHandler(file_handler)
  45. root_logger.setLevel(logging.INFO)
  46. def download():
  47. cookies = json.load(open('cookie.json'))
  48. headers = {'cookie': cookies.get('cookie_cnblogs', '')}
  49. dir_path = myget(args_dict, 'path', './cnblogs')
  50. if dir_path[len(dir_path)-1] == '/':
  51.   dir_path = dir_path[:len(dir_path)-1]
  52. if not os.path.exists(dir_path):
  53.   os.mkdir(dir_path)
  54. article_url = myget(args_dict, 'article_url', '-1')
  55. if article_url != '-1':
  56.   logging.info('article_url=%s', article_url)
  57.   try:
  58.    resp = requests.get(article_url, headers=headers)
  59.    if resp.status_code != 200:
  60.     logging.error('fail to get blog \'%s\', resp=%s', article_url, resp)
  61.     return
  62.    tmp_list = article_url.split('/')
  63.    blog_id_str = tmp_list[len(tmp_list)-1]
  64.    with open(dir_path+'/'+blog_id_str, 'w') as f:
  65.     f.write(resp.text)
  66.    logging.info('get blog \'%s\' success.', article_url)
  67.   except Exception as e:
  68.    logging.error('exception raised, fail to get blog \'%s\', exception=%s.', list_url, e)
  69.   finally:
  70.    return
  71. raw_url = args_dict.get('url')
  72. rurl = urlparse(raw_url)
  73. username = (rurl.path.split("/", 1))[1]
  74. page_no = 1
  75. while True:
  76.   list_url = list_url_tpl%(username, page_no)
  77.   logging.info('list_url = %s', list_url)
  78.   try:
  79.    resp = requests.get(list_url, headers=headers)
  80.    if resp.status_code != 200:
  81.     break
  82.   except Exception as e:
  83.    logging.error('exception raised, fail to get list \'%s\', exception=%s.', list_url, e)
  84.    return
  85.   html = etree.HTML(resp.text)
  86.   blog_list = html.xpath('//div[@class=\'postTitle\']/a/@href')
  87.   if len(blog_list) == 0:
  88.    break
  89.   for blog_url in blog_list:
  90.    tmp_list = blog_url.split('/')
  91.    blog_id_str = tmp_list[len(tmp_list)-1]
  92.    blog_resp = requests.get(blog_url, headers=headers)
  93.    if resp.status_code != 200:
  94.     logging.error('fail to get blog \'%s\', resp=%s, skip.', blog_url, resp)
  95.     continue
  96.    with open(dir_path+'/'+blog_id_str, 'w') as f:
  97.     f.write(blog_resp.text)
  98.    logging.info('get blog \'%s\' success.', blog_url)
  99.   page_no += 1
  100. def upload_request(headers, content, filename):
  101. body = {
  102.   "edit_type": 0,
  103.   "origin_type": 2,
  104.   "content": content
  105. }
  106. data = json.dumps(body)
  107. try:
  108.   resp = requests.post(draft_url, data=data, headers=headers)
  109.   if resp.status_code != 200:
  110.    logging.error('fail to upload blog, filename=%s, resp=%s', filename, resp)
  111.    return
  112.   ret = resp.json()
  113.   draft_id = ret.get('data', {}).get('draft_id', '-1')
  114.   logging.info('upload success, filename=%s, jj_draft_id=%s, jj_draft_url=%s', filename, draft_id, jj_draft_url_tpl%draft_id)
  115. except Exception as e:
  116.   logging.error('exception raised, fail to upload blog, filename=%s, exception=%s', filename, e)
  117.   return
  118. def upload():
  119. cookies = json.load(open('cookie.json'))
  120. headers = {
  121.   'cookie': cookies.get('cookie_juejin', ''),
  122.   'content-type': 'application/json'
  123. }
  124. filename = myget(args_dict, 'file', '-1')
  125. if filename != '-1':
  126.   logging.info('upload_filename=%s', filename)
  127.   try:
  128.    with open(filename, 'r') as f:
  129.     content = f.read()
  130.     upload_request(headers, content, filename)
  131.    return
  132.   except Exception as e:
  133.    logging.error('exception raised, exception=%s', e)
  134. rec_dir = myget(args_dict, 'rec_dir', '-1')
  135. if rec_dir != '-1':
  136.   logging.info('upload_dir=%s', filename)
  137.   try:
  138.    g = os.walk(rec_dir)
  139.    for path, dir_list, file_list in g:
  140.     for filename in file_list:
  141.      if filename.endswith('.html'):
  142.       filename = os.path.join(path, filename)
  143.       with open(filename, 'r') as f:
  144.        content = f.read()
  145.        upload_request(headers, content, filename)
  146.   except Exception as e:
  147.    logging.error('exception raised, exception=%s', e)
  148.   return
  149. if __name__ == '__main__':
  150. init_parser()
  151. args = parser.parse_args()
  152. args_dict = args.__dict__
  153. init_log()
  154. empty_flag = True
  155. for k, v in args_dict.items():
  156.   if k != 'enable_log' and v is not None:
  157.    empty_flag = False
  158. if empty_flag:
  159.   parser.print_help()
  160.   exit(0)
  161. if args_dict.get('method') == 'upload':
  162.   upload()
  163. else:
  164.   download()
  165. pass
复制代码
cookie.json


本地新建 cookie.json 文件,与 main.py 同级
  1. {
  2. "cookie_cnblogs": "请替换为博客园cookie",
  3. "cookie_juejin": "请替换为掘金cookie"
  4. }
复制代码
github 所在


末了附上 github 所在,内里除了 demo 的 源码之外也有录制好的一个视频,有爱好的同砚可以下载使用或者研究研究,脚本有问题或者写的不好改进的地方也可以相互探究下。有意见也可以随时留言反馈
以上就是用python写个博客迁移工具的详细内容,更多关于python 博客迁移的资料请关注脚本之家别的相干文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作