备份CSDN博客(下)

背景

在上一篇文章 备份 CSDN 博客(上)中,已经解决了第一个问题——获取所有博文的 URL,这篇博文就讨论如何根据 URL 把文章下载下来,并转换成 markdown 格式。

fileinput 模块

python 中的 fileinput 模块可以对一个或多个文件中的内容进行迭代、遍历等操作。该模块的 input() 函数有点类似操作文件的 readlines() 方法,区别在于:前者是一个迭代对象,即每次只生成一行,需要用 for 循环迭代;后者是一次性读取所有行。

用 fileinput 对文件进行循环遍历,格式化输出,查找、替换等操作,非常方便。

典型用法为:

import fileinput
for line in fileinput.input():
    process(line)

此程序会迭代 sys.argv[1:] 中列出的所有文件内的行,如果列表为空则会使用 sys.stdin

详细的说明可以在官网查询: https://docs.python.org/zh-cn/3/library/fileinput.html

这里举个例子。

假设我已经得到了每篇文章的 URL,保存在 url.txt 中

cat url.txt
https://blog.csdn.net/u013490896/article/details/113796436
https://blog.csdn.net/u013490896/article/details/113075606
https://blog.csdn.net/u013490896/article/details/113074860
https://blog.csdn.net/u013490896/article/details/113062803

我想保留每一行最后的编号。

import fileinput


for line in fileinput.input():
	a = line.replace('\n', '').split('/')
	print(a[-1]) # 获取文章的 ID

运行:$ python3 id.py url.txt

$ python3 id.py url.txt
113796436
113075606
113074860
113062803

代码第 5 行:replace(’\n’, ‘’) 表示要去掉原来文件中每一行后面的换行;.split(’/’) 表示用 “/” 分割字符串

第 6 行,a[-1] 表示取数组的最后一个元素,因为被分割后的结果是一个数组,比如第一行被分割成

['https:', '', 'blog.csdn.net', 'u013490896', 'article', 'details', '113796436']

再举个例子,利用 fileinput 对多文件操作,并原地修改内容。

我们把 url.txt 复制 2 个,一个是 1.txt,一个是 2.txt

 cat 1.txt
https://blog.csdn.net/u013490896/article/details/113796436
https://blog.csdn.net/u013490896/article/details/113075606
https://blog.csdn.net/u013490896/article/details/113074860
https://blog.csdn.net/u013490896/article/details/113062803

$ cat 2.txt
https://blog.csdn.net/u013490896/article/details/113796436
https://blog.csdn.net/u013490896/article/details/113075606
https://blog.csdn.net/u013490896/article/details/113074860
https://blog.csdn.net/u013490896/article/details/113062803

把代码修改一下,保存成 id2.py

import fileinput

def process(line):
	return line.replace('\n', '').split('/')[-1]

for line in fileinput.input(['1.txt','2.txt'], inplace=1):
	print(process(line))

运行结果是

$ python3 id2.py 
$ cat 1.txt
113796436
113075606
113074860
113062803
$ cat 2.txt
113796436
113075606
113074860
113062803

代码第 6 行,inplace=1 表示要原地修改内容,官方的解释是“将标准输出定向到输入文件”

如果给出了 backup 形参 (通常形式为 backup='.<some extension>'),它将指定备份文件的扩展名,并且备份文件会被保留;默认情况下扩展名为 '.bak'

其实不指定 inplace = 1,利用命令行的重定向,也是可以起到备份的作用。

好了,fileinput 就介绍到这里,总之利用 fileinput 可以很容易地遍历文件中的每一行。

安装 clean-mark

在博文 网页转 markdown 的工具 中,我介绍了一个工具,可以非常方便地把网页转换成 markdown 格式。

所以留给我们的工作很简单,几行代码就搞定

以下代码保存为 get_blogs1.py

import fileinput
import os

for line in fileinput.input():
	# 去掉末尾的换行
	url = line.replace('\n', '')
	# 下载文章
	os.system("clean-mark "+ url) 

第 8 行需要解释一下,system 函数可以将字符串转化成命令在系统上运行;其原理是每一条 system 函数执行时,都会创建一个子进程来执行命令行,子进程的执行结果无法影响主进程。

需要提醒的是:

import os

os.system('cd /usr/local')
os.mkdir('aaa.txt)

上述程序运行后会发现 .txt 文件并没有创建在 /usr/local 文件夹下,而是在当前的目录下,这是为什么呢?就是因为上面说的,‘cd /usr/local’ 是一个子进程,它的结果无法影响第 4 行创建文件。

为了保证 system 执行多条命令可以成功,多条命令需要在同一个子进程中运行:

import os

os.system('cd /usr/local && mkdir aaa.txt')
# 或者
os.system('cd /usr/local ; mkdir aaa.txt')

再回到 get_blogs1.py,我们试运行一下

$ cat url.txt 
https://blog.csdn.net/u013490896/article/details/113796436
https://blog.csdn.net/u013490896/article/details/113075606
https://blog.csdn.net/u013490896/article/details/113074860
https://blog.csdn.net/u013490896/article/details/113062803


$ python3 get_blogs1.py url.txt
=>  Processing URL ...
> 113796436.md
=>  URL converted!
=>  Processing URL ...
> 113075606.md
=>  URL converted!
=>  Processing URL ...
> 113074860.md
=>  URL converted!
=>  Processing URL ...
> 113062803.md
=>  URL converted!

在这里插入图片描述

可以看到,已经下载了,且以文章的 ID 命名。

打开一篇文章看看

在这里插入图片描述

基本上符合要求,但是图片并没有下载下来

在这里插入图片描述

点击图片,看到的是从 CSDN 官网上得到的图片,图片并不在本地。为了把图片下载到本地,我们需要添加功能。对了,下载的 .md 文件是以文章 ID 命名的,我希望以文章标题命名。

所以,接下来的任务可以细化为:

迭代 url.txt 的每一行,对于每一行:

  1. 通过 URL 下载文章,假设下载后得到文件 111.md
  2. 打开 111.md,解析出标题,假设标题是 abc
  3. 创建文件夹 abc
  4. 把下载的 111.md 移动到文件夹 abc 里
  5. 在 abc 文件夹里面创建文件夹 img
  6. 打开 111.md,解析出所有图片的 URL
  7. 下载所有图片到文件夹 img

功能明确了,我们看代码

import fileinput
import os
import linecache

for line in fileinput.input():
	# 去掉末尾的换行
	url = line.replace('\n', '')
	# 下载文章
	os.system("clean-mark "+ url) 
	
	a = url.split('/')
	#print(a[-1])	# 获取文章的 ID
	file_path = a[-1] + ".md" # 获取文件名
	title = linecache.getline(file_path, 3).\
	replace(' ', '').replace('title:', '').replace('\n', '')
	#print(title) # 获取文章标题
	os.makedirs(title, exist_ok = True) # 以文章标题为目录名称,创建目录
	os.system("mv " + file_path + " ./" + title) # 移动下载的 .md 文件到目录
	os.chdir(title) # 切换目录
	
	# 下载图片, TODO
	
	os.chdir('../') # 切换目录

第 14 行,使用了 linecache 模块

linecache 模块

该模块允许从任何文件里得到任何的行,并且使用缓存进行优化,常见的情况是从单个文件读取多行。

linecache.getlines(filename)
从名为 filename 的文件中得到全部内容,输出为列表格式,以文件每行为列表中的一个元素

linecache.getline(filename,lineno)

从名为 filename 的文件中得到第 lineno 行(换行符将包含在找到的行里)。我们用的就是这个函数。

下载后的 .md,都有一个文件头,第 3 行 “title:xxxxx” 就是标题

在这里插入图片描述

代码第 14 行:

title = linecache.getline(file_path, 3).\ replace(' ', '').replace('title:', '').replace('\n', '')

首先,读取文件的第三行,得到的是 title:xxxxx;去掉空格,去掉前面的’title:’,再去掉末尾的换行,最后就得到了标题。

代码第 17 行:

os.makedirs(title, exist_ok = True)

创建目录,exist_ok = True 表示只有在目录不存在时创建目录,目录已存在时不会抛出异常。

到了这里,就差图片下载了。

下载图片

下载图片的函数是

def get_img_url(file_path):
	pattern = "![](https://"
	fd = open(file_path, 'r')
	lines = fd.readlines()
	os.makedirs('img', exist_ok = True) # 创建 img 目录
	for line in lines:
		if pattern in line:
			a = line.split("?")
			url_img = a[0].replace('![](','')  # 去除前面的字符 “![](”
			#print(url_img)
			name = url_img.split('/')[-1] 
			filename = '{}{}{}'.format('img', os.sep, name)
			urlretrieve(url_img, filename) # 下载图片

参数是 .md 文件的路径

第 3 行:open() 函数用于打开一个文件,创建一个 file 对象,“r” 表示以只读方式打开文件。

第 4 行:readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for… in … 结构进行处理。

第 7 行:in 是成员运算符,用来测试给定值是否为序列中的成员。通过研究下载的 .md 文件,我发现图片链接是以"![](https://"开头的

举例:

![](https://img-blog.csdn.net/20180414233743206?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM0OTA4OTY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

8-9 行,得到的是 https://img-blog.csdn.net/20180414233743206

11 行,得到的是 20180414233743206

12 行:字符串格式化,os.sep 根据你所处的平台,自动采用相应的路径分隔符号,因为我在 Linux 上实验,所以得到的是 img/20180414233743206

13 行,urlretrieve() 方法将远程数据下载到本地

urlretrieve(url, filename=None, reporthook=None, data=None)

参数 filename 指定了保存的路径。

完整代码

import fileinput
import os
import linecache
from urllib.request import urlretrieve

def get_img_url(file_path):
	pattern = "![](https://"
	fd = open(file_path, 'r')
	lines = fd.readlines()
	os.makedirs('img', exist_ok = True) # 创建 img 目录
	for line in lines:
		if pattern in line:
			a = line.split("?")
			url_img = a[0].replace('![](','')  # 去除前面的字符 “![](”
			#print(url_img)
			name = url_img.split('/')[-1] 
			filename = '{}{}{}'.format('img', os.sep, name)
			urlretrieve(url_img, filename) # 下载图片

for line in fileinput.input():
	# 去掉末尾的换行
	url = line.replace('\n', '')
	# 下载文章
	os.system("clean-mark "+ url) 
	
	a = url.split('/')
	#print(a[-1])	# 获取文章的 ID
	file_path = a[-1] + ".md" # 获取文件名
	title = linecache.getline(file_path, 3).\
	replace(' ', '').replace('title:', '').replace('\n', '')
	#print(title) # 获取文章标题
	os.makedirs(title, exist_ok = True) # 以文章标题为目录名称,创建目录
	os.system("mv " + file_path + " ./" + title) # 移动下载的 .md 文件到目录
	os.chdir(title) # 切换目录	
	# 下载图片
	get_img_url(file_path)
	os.chdir('../') # 切换目录

总结

容错性差。比如:

  1. clean-mark 这个工具不完美,转换效果有时候特别不好,比如目录混乱,代码片乱码等;有时候这个工具还报错,比如

在这里插入图片描述

  1. 图片下载的时候,很多时候会报错,因为有的图片链接不按照牌理出牌

如何解决呢?

  1. 寻找其他的 HTML 转 Markdown 的工具
  2. 图片链接似乎有 2 种格式,要分情况处理

其他备份博客的思路

利用浏览器,提取博客的主体。
在这里插入图片描述

div class=“blog-content-box”

把这个元素拷贝出来

在这里插入图片描述

拷贝后保存为 .html 文件,然后用浏览器打开,这时候页面会清爽很多。下面是效果图。

在这里插入图片描述

在这里插入图片描述

这样也可以达到备份的效果,但是图片还是不在本地,需要提取链接并下载。

我尝试用代码实现上述过程

import  urllib.request
from bs4 import BeautifulSoup

url = 'https://blog.csdn.net/longintchar/article/details/43193289'

def get_content(url):
	res = urllib.request.urlopen(url) 
	html = res.read().decode('utf-8')
	soup = BeautifulSoup(html,'html.parser')
	divs = soup.find_all('div', attrs={'class':'blog-content-box'})	
	print(divs[0])
		
get_content(url)

但是输出的东西(第 11 行)和前面保存下来的不一样。

为什么不一样,如何才能一样?这里留个坑。

其实还有简单粗暴的备份办法,就是利用浏览器的 “另存为”

在这里插入图片描述

这样可以把整个网页(包括图片等)保存到本地。

肯定不能手工操作,我有 200 多篇博文,这样操作太累了。自动化的方法还在探索验证中…

【End】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MSDE(Microsoft SQL Server Desktop Engine)是微软提供的免费轻量级关系型数据库管理系统。下面是MSDE的下载安装和创建管理数据库的步骤。 1. 下载MSDE:首先,打开浏览器,搜索“MSDE下载”。在搜索结果中选择Microsoft官方网站或者可信赖的第三方网站下载MSDE的安装程序。 2. 安装MSDE:运行下载好的安装程序,按照安装向导的指示进行安装。在安装过程中,可以选择安装位置、实例名称和身份验证模式等选项,根据需求进行设置。 3. 配置MSDE:安装完成后,打开“SQL Server Configuration Manager”工具。在工具中,可以设置MSDE的各项配置,如网络配置、服务配置和安全性配置等。根据需求进行相应的配置。 4. 创建数据库:打开SQL Server Management Studio(SSMS),使用MSDE的身份验证模式登录到数据库服务器。在SSMS中,可以通过“新建查询”或者“对象资源管理器”创建数据库。在创建数据库时,指定数据库的名称和相关的设置,如文件组、文件路径和初始大小等。 5. 管理数据库:通过SSMS,可以对已创建的数据库进行管理。可以执行各种操作,如创建表、插入数据、修改表结构、执行查询和备份数据库等。此外,还可以监视数据库的性能和运行状况,以及设置数据库的安全性和权限等。 总结起来,MSDE的下载安装和创建管理数据库的步骤大致包括下载MSDE、安装MSDE、配置MSDE、创建数据库和管理数据库。根据这些步骤,我们可以轻松地使用MSDE进行数据库开发和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值