博客备份
自己动手,丰衣足食。
缘由
写过多年的博客,积累了花费许多时光写出来的一些札记。但为知笔记目前只能单篇单篇地导出,不支持批量导出笔记。恼人。面对几百篇的札记,难道要一篇一篇地导出吗? 懒惰的程序员可不愿这么干!
于是,开始思考。。。可以从博客园的博客上入手,狡兔三窟嘛!
网上搜了下,博客园竟然提供了博客备份能力。强赞啊!登录博客园后台管理界面,有个“博客备份”的功能。如下所示:
点击后,可以选择时间段,然后导出这个时间段的博客。导出的是一个 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()
小结
程序员有啥本事呢? 即是运用编程来结构化处理数据的能力。只要给定数据,就能够批量地、自动化、快速地处理任意数量的数据。这借助了工具的优势。君子生非异也,善假于物也!希望广大程序员珍惜这个本事,不是仅仅拿来给别人打工。事实上,如果不设置访问权限的话,程序员是可以获取自己想要的互联网上的任意内容资源的。