博客备份

自己动手,丰衣足食。


缘由

写过多年的博客,积累了花费许多时光写出来的一些札记。但为知笔记目前只能单篇单篇地导出,不支持批量导出笔记。恼人。面对几百篇的札记,难道要一篇一篇地导出吗? 懒惰的程序员可不愿这么干!

于是,开始思考。。。可以从博客园的博客上入手,狡兔三窟嘛!

网上搜了下,博客园竟然提供了博客备份能力。强赞啊!登录博客园后台管理界面,有个“博客备份”的功能。如下所示:

点击后,可以选择时间段,然后导出这个时间段的博客。导出的是一个 xml 文件。里面的内容大致是这样的,title 是博文的标题, link 是博文的链接,description 标签里的内容就是博文内容。

<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-编程大观园</title><link>https://www.cnblogs.com/lovesqcc/</link><description>Enjoy programming, Enjoy life ~~~ 设计,诗歌与爱</description><language>zh-cn</language><lastBuildDate>Sat, 11 Feb 2023 12:07:49 GMT</lastBuildDate><pubDate>Sat, 11 Feb 2023 12:07:49 GMT</pubDate><ttl>60</ttl><item><title>专业精进之路:构建扎实而有实效的编程知识体系</title><link>http://www.cnblogs.com/lovesqcc/archive/2023/02/01/17084292.html</link><dc:creator>琴水玉</dc:creator><author>琴水玉</author><pubDate>Wed, 01 Feb 2023 14:05:00 GMT</pubDate><guid>http://www.cnblogs.com/lovesqcc/archive/2023/02/01/17084292.html</guid><description><![CDATA[> 对世界上任何一件事物保持谦卑求知之心。

<br/>

在“[打造适合自己的知识库](https://www.cnblogs.com/lovesqcc/p/16388105.html)”一文中,讲到了构建适合自己的知识库的一些经验和做法,不过,那还仅限于工具之法,并未涉及知识构建之法。本文对编程知识体系的构建作一探讨。

//博文内容。。。
<br/>
]]></description></item><item><title>知乎一答:什么样的知识是有价值的</title><link>http://www.cnblogs.com/lovesqcc/archive/2023/01/29/17072238.html</link><dc:creator>琴水玉</dc:creator><author>琴水玉</author><pubDate>Sun, 29 Jan 2023 03:29:00 GMT</pubDate><guid>http://www.cnblogs.com/lovesqcc/archive/2023/01/29/17072238.html</guid>description><![CDATA[> // 博文内容 ]]></description></item></channel></rss>

emmm…… 离预想的有点差距。不过没关系,你有数据,我就能开干。只要能解析 XML 就可以啦。

编程实现

Python

用什么编程语言来解析呢?悄悄告诉你,咱 Java 程序员可不仅仅只是会 Java,至少还会一门编程语言 Python. 为什么要用 Python 呢? 比如你要打印 hello world 吧。用 Python 只需要打开一个文件 hello.py,然后敲入:

print("hello, world")

用 Java ? 恐怕你要写出个 Hell 来。 Python 绝对是 Java 程序员随身携带的一把短剑。而且 Python 的库也很丰富,包括绘图库、科学数值计算库、深度学习库等,是做本科毕业论文的优选语言。

解析XML

确定用 Python 之后,就从网上搜一段解析 xml 代码,稍微改一改就可以啦。如下所示。将导出的文件重命名为 cnblogs_backup.xml, 提取其中的 link ,根据 link 提供的链接批量下载文件。 创建一个 python 文件: xmlparse.py

# -*- coding: utf-8 -*-

from xml.dom.minidom import parse
def readXML():
    domTree = parse("/home/qinshu/Downloads/cnblogs_backup.xml")
    rootNode = domTree.documentElement

    # 所有文章
    posts = rootNode.getElementsByTagName("item")
    print("****所有文章****")
    for post in posts:
        # title 元素
        # title = post.getElementsByTagName("title")[0]
        # print("title: %s", title.childNodes[0].data)
        # link 元素
        link = post.getElementsByTagName("link")[0]
        print(link.childNodes[0].data)

if __name__ == '__main__':
    readXML()

执行 python xmlparse.py 解析得到 HTML 链接,然后执行如下命令,即可批量下载所有博客文章的 HTML 文件。

注: 博客园对博客备份做了更新,文件内容的原格式有所变化。 博文父标签为 entry,链接地址改成了 href 值。 新的脚本应该是:


# -*- coding: utf-8 -*-

from xml.dom.minidom import parse
def readXML():
    domTree = parse("/home/qinshu/Downloads/cnblogs_backup.xml")
    rootNode = domTree.documentElement

    # 所有文章
    posts = rootNode.getElementsByTagName("entry")
    print("****所有文章****")
    for post in posts:
        link = post.getElementsByTagName("link")[0]
        print(link.getAttribute("href"))

if __name__ == '__main__':
    readXML()

python3 xmlparse.py | grep html  | xargs -I {} wget {}

xargs 是一个非常强大的命令。可以直接将处理单个输入的能力变成批量处理多个输入的能力。推荐品尝。比如 ze a.mp4 是一个将 a.mp4 进行加密压缩的程序,那么如下就可以将任意多个文件进行加密和压缩:

ls *.mp4 | xargs -I {} ze {}

这个命令的意思是说,把 ls *.mp4 的结果搜集起来,每次一个,发给 ze 去处理。xargs 的意思类似:

#/bin/bash

result=$(ls *.mp4)

for res in $result;
do
    ze $res    
done

Shell 也是一把很好的匕首。

HTML转换MD

有了 html 怎么办呢? 可以再写一个 python 程序 html2md.py,解析 html ,生成 md 文件。这需要安装一个 markdownify 的 python 模块。使用 pip3 安装:

pip3 install markdownify

然后网上找一段代码,略作修改,命名为 htm2md.py。

# -*- coding: utf-8 -*-

import markdownify
import sys

inputfname_withext = sys.argv[1]
inputfname = inputfname_withext[:inputfname_withext.index(".")]

with open(inputfname + ".html") as fr:
    html = fr.read()

md = markdownify.markdownify(html, heading_style="ATX")
print(md)

with open(inputfname + ".md", "w") as fw:
    fw.write(md)

同样,使用如下命令可以批量转换:

ls ~/Downloads/*.html | xargs -I {} python3 html2md.py {}

解析HTML

上面还有一点问题,就是一个 html 往往有一些头部和尾部元素,而不仅仅是博文内容。这样,转出来的 markdown 文档“不干净”。事实上,我只想要把博文里的内容转成 markdown 内容。怎么办呢?这里就需要进行 html 解析,提取出想要的内容。

拿一篇文章来分析,打开 google chrome 控制台:

现在,我们的目标就是从 html 中提取 div id = "cnblogs_post_body" 的内容。可以使用 beautifulsoup 模块。使用如下命令安装 beautifulsoup 模块:

pip3 install beautifulsoup4

然后程序修改如下:

# -*- coding: utf-8 -*-

import markdownify
from bs4 import BeautifulSoup
import sys

inputfname_withext = sys.argv[1]
inputfname = inputfname_withext[:inputfname_withext.index(".")]

with open(inputfname + ".html") as fr:
    html = fr.read()

soup = BeautifulSoup(html, "lxml")
post_body = soup.find('div', id="cnblogs_post_body")

md = markdownify.markdownify(str(post_body), heading_style="ATX")

with open(inputfname + ".md", "w") as fw:
    fw.write(md)

这里,我只是把 html 替换成:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "lxml")
post_body = soup.find('div', id="cnblogs_post_body")
html = str(post_body)

关于抓取网页内容,可以参考之前写的一个爬虫程序:批量下载网站图片的Python实用小工具

整合串联

现在,我们有了两个脚本:

  • xmlparse.py: 从博客备份文件里解析出博客链接;
  • html2md.py: 将 html 转换成 markdown。

怎么串联起来呢?一行命令搞定:

python3 xmlparse.py | grep html  | xargs -I {} wget {} && ls *.html | xargs -I {} python3 html2md.py {}

这里 && 表示前面的命令正确执行之后,再执行后面的命令。

有童鞋可能会说:哎呀,好麻烦啊!哎呀,程序员的乐趣不就在折腾嘛 😃

更简单的方法

上面的方法,先要下载 html ,然后再转换成 Markdown。事实上,可以直接提取 [CDATA] 里的博客内容(要求博文本身就是 Markdown 写成的),配合 title ,写入对应的 title.md 文件里。 秒级解决。

# -*- coding: utf-8 -*-

import sys
reload(sys)
sys.setdefaultencoding('utf8')

from xml.dom.minidom import parse
def generate_mds():
    domTree = parse("/Users/qinshu/Downloads/cnblogs_backup.xml")
    # 文档根元素
    rootNode = domTree.documentElement
    print(rootNode.nodeName)

    # 所有顾客
    posts = rootNode.getElementsByTagName("item")
    print("****所有文章****")
    for post in posts:
        # title 元素
        title = post.getElementsByTagName("title")[0]
        post_title = title.childNodes[0].data
  
        try: 
            description = post.getElementsByTagName("description")[0]
            with open(post_title+".md", "w") as fw:
                description = post.getElementsByTagName("description")[0]
                fw.write(description.childNodes[0].data)
        except:
            print(post_title + "failed")

if __name__ == '__main__':
    generate_mds()

小结

程序员有啥本事呢? 即是运用编程来结构化处理数据的能力。只要给定数据,就能够批量地、自动化、快速地处理任意数量的数据。这借助了工具的优势。君子生非异也,善假于物也!希望广大程序员珍惜这个本事,不是仅仅拿来给别人打工。事实上,如果不设置访问权限的话,程序员是可以获取自己想要的互联网上的任意内容资源的。

posted @ 2023-02-11 23:35  琴水玉  阅读(95)  评论(0编辑  收藏  举报