迁移、备份博客_从CSDN批量导出markdown格式的文章(Python+BeautifulSoap)

今天看我各个平台博客同步情况,发现我之前都是在csdn写完,直接复制粘贴到其它平台的,格式什么的完全没有了,而我也急于发布没有做任何处理。想象以后文章多起来,不仅管理起来不方便,而且对其它平台的阅读者很不友好。


顺势观察了一下各平台的导入、导出功能(针对于自己文章):有平台支持批量导入,亦有平台支持批量导出,还有的支持单篇导入,没有一个既可以批量导入又可以批量导出的(嘤嘤嘤)。


而CSDN同样仅支持单篇导入、导出,需要进到每篇文章的编辑页面再进行导出,如果文章超级多的时候,备份、搬迁时候进行此项操作都不是最佳方案。想想我之前那篇Hexo迁移博客的文章:Mac_如何利用Hexo发布、迁移博文?https://blog.csdn.net/pang787559613/article/details/102619683,竟然还是我手动导出的(可能之前文章少,没觉得费事儿吧),还是太年轻啊。


对于可以批量导入的平台,我本人甚是欢喜,就算新注册的账号,也不用一篇一篇去复制粘贴,那么前提是要先把自己已有文章导出为统一格式(如:Markdown),既做一次备份,也便于在其它平台共用。

延伸一下,只能导出自己的文章也不太好,毕竟如果遇到想要收藏的文章时候,存下的格式很乱,就很尴尬了。所以不仅限于导自己的博客,这篇文章的主题是:如何从CSDN批量导出markdown格式的文章?

网上搜了一下有java的脚本用到jsoap、也有python的selenium跟BeautifulSoap两种。相比之下我还是比较熟悉python,但是selenium是基于浏览器模拟导出,仅能在文章编辑页导出自己的文章,有局限性,所以就研究了下BeautifulSoap。基于这位大佬的代码:https://blog.csdn.net/qq_36962569/article/details/100167955,运行下来,仅能拿到前两页前三条(共计6条数据),而且写入报错。对于我非专业python来说有点小烦躁,好在坚持了下来,理清了思路,解决了报错,并成功导出。下面我来记录下我所理解的大佬思路,还有报错的解决方案,贴一下修改过的代码,给需要的人做参考。



一、思路:

1、csdn自带导出功能是如何导出的?

2、每篇文章怎么做区分的?怎么拿到所有文章的id?

3、分页如何处理?

4、拿到内容后解析写入文件?



二、分析过程:

1、csdn自带导出功能是如何导出的?

打开一片文章编辑页面,F12查看数据如何获取的,发现其为这样一个请求https://blog-console-api.csdn.net/v1/editor/getArticle?id=105360586,返回字段中有content和markdowncontent,我们要拿markdown格式,所以Markdowncontent就好了。
在这里插入图片描述
在这里插入图片描述
**在这里插入图片描述**

2、每篇文章怎么做区分的?怎么拿到所有文章的id?

至于第1步里的id,跟这篇文章详情链接https://blog.csdn.net/pang787559613/article/details/105360586,是一致的,再观察几篇文章详情,仅后轴id不一样, 所以不同文章是以此来区分的。


查看所有文章id:
个人主页,F12打开检查,刷新页面(windows—>>F5,mac—>>command+r):
在这里插入图片描述可以分析以下源码,用BeautifulSoap库解析,能获取id、发布时间等内容:
在这里插入图片描述

3、分页如何处理?

翻到个人主页底部页码出,点开第二页,发现调用接口为:https://blog.csdn.net/pang787559613/article/list/2
在这里插入图片描述

切回第一页时,调用的请求为:https://blog.csdn.net/pang787559613/article/list/1
在这里插入图片描述

4、拿到内容后解析写入文件?

通过调用第3步,拿到所有文章,再用第2步,解析获得文章id以及发布时间,最后调用第1步,解析拿到markdowncontent、文章标题、tags、key等等,保存为hexo格式的markdown(由于我的hexo博客仅有标题+内容,所以代码仅写入了标题跟内容,其余注释了,需要的可自行修改。后来仅保留了内容,做博客迁移)。



三、完整代码:

# encoding:utf-8
# author:笑胖仔

import json
import uuid
import time
import requests
import datetime
from bs4 import BeautifulSoup


def request_blog_list(page):
    """获取博客列表
    主要包括博客的id以及发表时间等
    """
    url = f'https://blog.csdn.net/pang787559613/article/list/{page}'
    reply = requests.get(url)
    parse = BeautifulSoup(reply.content, "lxml")
    spans = parse.find_all('div', attrs={'class':'article-item-box csdn-tracking-statistics'})
    blogs = []
    for span in spans[:40]:
        try:
            href = span.find('a', attrs={'target':'_blank'})['href']
            read_num = span.find('span', attrs={'class':'num'}).get_text()
            date = span.find('span', attrs={'class':'date'}).get_text()
            blog_id = href.split("/")[-1]
            blogs.append([blog_id, date, read_num])
        except:
            print('Wrong, ' + href)
    return blogs

def request_md(blog_id, date):
    """获取博客包含markdown文本的json数据"""
    url = f"https://blog-console-api.csdn.net/v1/editor/getArticle?id={blog_id}"
    headers = {
        "cookie":"uuid_tt_dd=10_20621362900-1586421086666-163599; dc_session_id=10_1586421086666.420623; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1586421618; dc_sid=d4ceee41911ac755c162110ff811aee3; __gads=ID=608336bee91baf3d:T=1586421689:S=ALNI_MZozulzITWLw3Hxzo3jrnu5fmz8CA; c_ref=https%3A//blog.csdn.net/pang787559613/article/list/2; c-toolbar-writeguide=1; SESSION=3b5e7c88-b27d-4fcc-a2d5-4e97c1438a3c; UN=pang787559613; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=6525*1*10_20621362900-1586421086666-163599!5744*1*pang787559613; announcement=%257B%2522isLogin%2522%253Atrue%252C%2522announcementUrl%2522%253A%2522https%253A%252F%252Fblog.csdn.net%252Fblogdevteam%252Farticle%252Fdetails%252F105203745%2522%252C%2522announcementCount%2522%253A0%252C%2522announcementExpire%2522%253A3600000%257D; UserName=pang787559613; UserInfo=604f13922dc04f2d8071fe0834e95db3; UserToken=604f13922dc04f2d8071fe0834e95db3; UserNick=%E7%AC%91%E8%83%96%E4%BB%94; AU=5FE; BT=1586422795507; p_uid=U000000; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1586422842; TY_SESSION_ID=ffc735f4-f5ae-40ed-9b98-ff01e337bf76; dc_tos=q8ijsv",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"
    }
    data = {"id": blog_id}
    reply = requests.get(url, headers=headers, data=data)

    try:
        write_hexo_md(reply.json(), date)
    except Exception as e:
        print("***********************************")
        print(e)
        print(url)
        # print(reply.json())

def write_hexo_md(data, date):
    """将获取的json数据解析为hexo的markdown格式"""
    title = data["data"]["title"]
    title = title.replace("[", "【")
    title = title.replace("]", "】")
    tags = data["data"]["tags"]
    # 页面唯一标识符,用于统计系统和评论系统
    key = "key" + str(uuid.uuid4())
    name = f"{date[0]}-{date[1]}-{date[2]}-{title}"
    tag = "tags:\n    - " + "\n    - ".join(tags.split(","))
    # #hexo内容顶部拼接:title、tag、key
    # header = "---\n" + f"title: {title}\n" + tag + "\n" + f"key: {key}\n" + "---\n\n"
    # #hexo内容顶部拼接:仅title
    # header = "---\n" + f"title: {title}\n" + "---\n\n"

    content = data["data"]["markdowncontent"].replace("@[toc]", "")

    # hexo格式markdown
    # with open(f"blogs/{name}.md", "w", encoding="utf-8") as f:
        # f.write(header + content)
    # print(f"写入 {name}")


    # 用来博客迁移。遂仅保留内容
    with open(f"blogs/{title}.md", "w", encoding="utf-8") as f:
        f.write(content)
    print(f"写入 {title}")


def main(total_pages=2):
    """
    获取博客列表,包括id,时间
    获取博客markdown数据
    保存hexo格式markdown
    """
    blogs = []
    for page in range(1, total_pages + 1):
        blogs.extend(request_blog_list(page))
    for blog in blogs:
        blog_id = blog[0]
        date = blog[1].split()[0].split("-")
        request_md(blog_id, date)
        time.sleep(1)

if __name__ == '__main__':
    main()
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值