一、引言
在昨天完成了:
Web Scraping with Python: 使用 Python 下载 CSDN 博客图片
的实例之后,我开始了思考:
可否实现一个导出 CSDN 博客全部文章以及附带图片资源的爬虫程序?
于是也就有了这篇博客。
这篇博客承接了上一篇博客的程序框架,在实现了 CSDN 指定用户博客的全部文章附带图片保存功能之后,又附带添加了博客文章内容的保存功能。
这将是一个非常令人激动不已的程序:
因为这将实现一个博客内容全部导出的功能!
这已然是一个有实际作用的爬虫程序了!
接下来,让我们开始吧:)
二、关键:怎样保存文章样式?
我们想要保存一篇博客文章的内容,不可能只单纯的保存纯文本吧。
一篇博客文章,有标题有标题有图片有各式各样的样式。我们要实现的这个爬虫程序,最主要的,就是要解决如何保留样式的保存博客文章的问题。
怎么办呢?
我们爬虫看到的永远都是页面的 Html 框架,那么从 Html,怎么样获取到有样式的文章呢?
Markdown
这个单词就像闪电一样划过了我的脑海,对! Html 绝对是可以完美转换成 Markdown 的,通过 Markdown 观看文档是一件非常人性化的事情(这得益于我对于 Markdown 的偏爱,以至于我都是使用 Markdown 写博客的)。
那么,接下来我们要做的,就是如何将 Html 文本转换成阅读人性化的 Markdown 文件了。
三、Tomd 库:从 Html 到 Markdown 的上天之旅
其实从 Html 转换成 Markdown 的过程,我们是可以想象的,比如说:
<h1>This is a title</h1>
上面的 Html 就可以转换成 Markdown 的
# This is a title
文本,这样,就简单实现了 Html 的 h1 标签向 Markdown 标签的转换。
理论上说我们可以这样完成 Html 到 Markdown 的转换,但是我们可是 Pythoner!遇到问题的第一步当然是寻找可以 import 到上天的库呀!
于是我找到了 Tomd。这是它的 GitHub 网址:
gaojiuli/tomd
看了下作者,居然还是中国人!真是由衷的自豪。
通过观看作者的 ReadMe 介绍,我通过:
pip install tomd
安装了 Tomd 库。
然后简单写了一个 TestTomd.py 文件:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import tomd
url = 'http://blog.csdn.net/u012814856/article/details/78470647'
html = urlopen(url)
bsObj = BeautifulSoup(html, 'html.parser')
md = bsObj.find('div', {'class': 'article_content'})
convert = tomd.convert(md.prettify())
with open('TestTomd.md', 'w', encoding='utf-8') as f:
f.write(convert)
这段代码:
1. 我首先使用了 urllib.request.urlopen 获取到了我的一篇博客的 Html 文本
2. 然后调用了 Tomd 库的 convert 方法将其转化成了 Markdown 文本
3. 最后我使用 with open 将这个 Markdown 文本写入了 .md 文件中
最后的结果是喜人的,看到了人性化的爬取结果:
通过寻找到了 Tomd 库以及我们的测试程序,我们已经看到了爬取到博客文章并且保留样式的可能性,接下来,让我们直接导出全部的博客文章吧!
四、展示:简短的代码,强大的功能
由于这篇博客的大部分代码,包括博客全部文章的爬取以及资源的下载,都已经在上一篇博客中解释的非常清楚了,因此这里直接贴出我的代码,若有不清楚的,可以参看我的上一篇博客:
Web Scraping with Python: 使用 Python 下载 CSDN 博客图片
以下是我的全部代码:
# -*- coding:utf-8 -*-
from urllib.request import urlopen
from urllib.request import urlretrieve
from urllib.parse import urljoin
from bs4 import BeautifulSoup
import os
import tomd
# Parse one page's articles.
def parse_page(bsObj, url):
articles = bsObj.findAll('div', {'class': 'article_item'})
links = []
for article in articles:
links.append(article.h1.a.attrs['href'])
print(links[-1])
parse_article(urljoin(url, links[-1]))
# Parse one article.
def parse_article(url):
global blogCount
# 1. Open article site.
html = urlopen(url)
bsObj = BeautifulSoup(html, 'html.parser')
# 2. Parse title and create directory with title.
title = bsObj.h1.get_text()
print('Article title is: %s' % title)
convertTitle = replace_deny_char(title)
blogCount += 1
directory = 'CSDN Blog/%d.%s' % (blogCount, convertTitle)
if os.path.exists(directory) is False:
os.makedirs(directory)
# 3. Parse and download images.
images = bsObj.find('div', {'class': 'article_content'}
).findAll('img')
count = 0
for img in images:
count += 1
imgUrl = urljoin(url, img.attrs['src'])
print('Download image url: %s' % imgUrl)
urlretrieve(imgUrl, '%s//%d.jpg' % (directory, count))
# 4. Parse blog content and convert html to markdown.
parse_article_content(bsObj, directory, convertTitle)
# Parse article content and convert html to markdown.
def parse_article_content(bsObj, directory, title):
# 1. Find html.
html = bsObj.find('div', {'class': 'article_content'})
md = tomd.convert(html.prettify())
# 2. Write to the file.
with open('%s/%s.md' % (directory, title), 'w', encoding='utf-8') as f:
f.write(md)
# Replace deny char, used to name a directory.
def replace_deny_char(title):
deny_char = ['\\', '/', ':', '*', '?', '\"', '<', '>', '|', ':']
for char in deny_char:
title = title.replace(char, ' ')
print('Convert title is: %s' % title)
return title
print('Please input your CSDN name:')
name = input()
url = 'http://blog.csdn.net/%s' % name
blogCount = 0
while True:
# 1. Open new page.
html = urlopen(url)
bsObj = BeautifulSoup(html, 'html.parser')
print('Enter new page: %s' % url)
# 2. Crawl every article.
parse_page(bsObj, url)
# 3. Move to next page.
next_url = bsObj.find('a', text='下一页')
if next_url is not None:
url = urljoin(url, next_url.attrs['href'])
else:
break
一共 90 多行代码,其中实现了 Html 转换成 Markdown 的关键逻辑的函数是 parse_article_content:
# Parse article content and convert html to markdown.
def parse_article_content(bsObj, directory, title):
# 1. Find html.
html = bsObj.find('div', {'class': 'article_content'})
md = tomd.convert(html.prettify())
# 2. Write to the file.
with open('%s/%s.md' % (directory, title), 'w', encoding='utf-8') as f:
f.write(md)
这里尤其要注意写入文档的编码一定要是 utf-8,因此这里在 open 的传参中添加了 encoding 参数。
最后看下我们爬出来的结果吧:
爬出的文件夹(一篇博客一个)
可见,这里我已经爬出了自己的全部的 159 篇博客信息,并且以编号标识,以博客标题命名了文件夹。
接下来,让我们看看文件夹里面有什么:
可见,每一篇博客里面附带的图片都已经下载下来,并且生成了一个博客内容的 Markdown 文件:
结果是非常令人欣喜的!
我们就用短短 90 行的代码,写出了一个强大的博客导出工具!
完结撒花 ^_^
五、总结
这是一个非常令人激动不已的爬虫程序。这意味着以后若是我想要保留我的所有博客内容,只需要跑一下这个爬虫程序即可(我之前还在担心要是 CSDN 停止运营了我的博客内容咋办 T_T)。
实践永远是最令人开心的,尤其是学习爬虫这一块。
当然了,学习爬虫之路远远没有走到尽头,还有好多需要学习和尝试。
Love Python,
To be Stronger:)
ps: 想要获取本博客的项目代码的同学,可以点击我的 GitHub 链接,欢迎 Star 欢迎 Fork 哦
wangying2016/CrawlCsdnBlog