Python爬虫Csdn系列III
By 白熊花田(http://blog.csdn.net/whiterbear) 转载需注明出处,谢谢。
说明:
在上一篇博客中,我们已经能够获取一个用户所有文章的链接了,那么这一节自然就是要将这些博客下载下来咯。
分析:
有了链接下载文章自然是不难。但是,获取的数据该怎么处理?每一篇文章都带有格式换行这些信息,自然,我们存储它们也是要存储其对应的html格式的数据的(注意,我们编辑的带有格式的博客或者其他文本都是以html代码格式存储的)。如何存?使用数据库,每篇文章字数都挺大的,没必要用数据库,还是存储文件更方便。
这里我将下载的每篇博客都取出文章的div部分,然后给这个部分添加必要的html头部及其尾部,将其封装成一个完整的html文本,最后再保存成html格式的文件。这里要注意的就是在html中一定要添加<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />这句话,否则显示的会是乱码。
核心代码在前两篇文章已经提到了,难度也不是很大。
代码:
#-*- coding:utf-8 -*- import sys import os import codecs import urllib import urllib2 import cookielib import MySQLdb import re from bs4 import BeautifulSoup from article import CsdnArticle reload(sys) sys.setdefaultencoding('utf-8') class CsdnCrawler(object): def __init__(self, author = 'whiterbear'): self.author = author self.domain = 'http://blog.csdn.net/' self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36'} self.articles = [] #给定url,得到所有的文章lists def getArticleLists(self, url= None): req = urllib2.Request(url, headers=self.headers) response = urllib2.urlopen(req) soup = BeautifulSoup(''.join(response.read())) listitem = soup.find(id='article_list').find_all(attrs={'class':r'list_item article_item'}) href_regex = r'href="(.*?)"' for i,item in enumerate(listitem): enitem = item.find(attrs={'class':'link_title'}).contents[0].contents[0] href = re.search(href_regex,str(item.find(attrs={'class':'link_title'}).contents[0])).group(1) art = CsdnArticle() art.author = self.author art.title = enitem.lstrip() art.href = (self.domain + href[1:]).lstrip() self.articles.append(art) def getPageLists(self, url= None): url = url if url else 'http://blog.csdn.net/%s?viewmode=list'%self.author req = urllib2.Request(url, headers=self.headers) response = urllib2.urlopen(req) soup = BeautifulSoup(''.join(response.read())) num_regex = '[1-9]\d*' pagelist = soup.find(id='papelist') self.getArticleLists(url) if pagelist: pagenum = int(re.findall(num_regex, pagelist.contents[1].contents[0])[1]) for i in range(2, pagenum + 1): self.getArticleLists(self.domain + self.author + '/article/list/%s'%i) def getAllArticles(self): #我们创建一个该作者的文件夹来存放作者的文章 if not os.path.exists(self.author): os.mkdir(self.author) for subarticle in self.articles: articleurl = subarticle.href #依次打开每一篇文章并下载 req = urllib2.Request(articleurl, headers=self.headers) response = urllib2.urlopen(req) soup = BeautifulSoup(''.join(response.read())) article_content = soup.find(id='article_content') title = subarticle.title.rstrip().encode('utf-8') #将提取的内容封装成html格式的字符串 article = u'<html><head><title>%s</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>%s</body></html>' % (title, article_content) fobj = codecs.open(u'%s/%s.htm'%(self.author, title),'w','utf-8') fobj.writelines(article.encode('utf-8')) fobj.close() def main(): csdn = CsdnCrawler(author='whiterbear')#'pongba',可以将填入你想下载的博主的博客 csdn.getPageLists() csdn.getAllArticles() if __name__ == '__main__': main()
结果:
生成了该博主命名的文件夹,文件夹中包含该博主的所有文章。如下图:
随便打开一个文章,显示的效果是这样的:(显示的效果很赞。)
感悟:
1> 中文编码问题。虽然已经了解了几种编码问题的解决方式,但是还是常常被这个问题给卡住。
2> 保持代码的正交性。虽然我还没做过大项目,但是已经能够感受到,如果两个模块的正交性提高,即一个模块的改动并不会影响到另一个模块的正常运行。这样子能够迫使你去思考一种清晰的框架,而不会写了一团糟的代码。
3> 常见的错觉,总觉得这个很简单啊,今天就可以做完啊,结果总是遇到这样那样的问题,还是缺少经验。
4> 其他:保持代码的整洁,尝试迭代,从小的代码开始一点点往上累计新的代码,时刻保持两个版本(其中一个含有大量输出来帮你确定每一步发生了什么)。
下个系列可能就要开始做微博的爬虫了,会涉及到相关的数据处理和分析,希望能顺利点。