Python爬虫|Python爬虫爬取百度百科内容实例


博主将来想从事数据挖掘算法相关的工作,数据挖掘的前提是有数据可用,于是想学些与爬虫有关的技术。前几天从imooc中学习了Python开发简单爬虫课程(课程网址),功能是爬取百度百科的内容,如果网页上还有相关链接,把相关链接的网页的内容也爬取下来。感觉老师讲的非常好,对于刚接触爬虫的、对面向对象编程有一定了解的同学非常合适,详细程度可以说是手把手教学了。这里记录一下我的学习过程。只是个人理解,说的不对欢迎批评指正。
首先介绍我的Python编程环境:WIN7+eclipse+PyDev+Python2.7 虽然Python已经有了更高版本Python3.5.*但是它相对Python2.7有较大的调整,网上关于3.5的教程也有限。我刚开始的时候就装了3.5,编程时遇到问题去百度,发现很多问题是由2.7和3.5两个版本编程兼容性导致的,在这方面吃了些亏,才重新安装了Python2.7,感觉不错。
下面是学习过程的记录。
爬虫的架构:爬虫调度端,URL管理器,网页下载器,网页解析器,有价值信息输出与存储。
1.爬虫调度端。这部分因该具有的功能有输入要爬取的首页,还有爬虫的整体调度,如启动爬虫、url管理器的启动,网页下载器的启动,网页解析的启动,网页输出、存储等。下面直接看代码。

# coding: utf-8 from baike_spider import html_downloader, url_manager, html_parser, html_outputerclass SpiderMain(object): def __init__(self):#构造方法 self.urls = url_manager.UrlManager()#初始化URL管理器 self.downloader = html_downloader.HtmlDownloader()#初始化网页下载器 self.parser = html_parser.HtmlParser()#初始化网页解析器 self.outputer = html_outputer.HtmlOutputer()#初始化输出器def craw(self, root_url):#开始执行爬虫的方法 count = 1#计数器,计数爬取页面的总数量 count2 = 0#计数器,计数爬取失败的网页个数 self.urls.add_new_url(root_url)#传入网页入口 while self.urls.has_new_url():#对网页内包括的连接网页循环抓取,先判断URL管理器不空 try:#有些页面可能失效了,要有异常处理 new_url = self.urls.get_new_url()#获取URL管理器中的一个URL print "craw %d : %s \n"%(count,new_url)#打印当前爬去的页面 html_cont = self.downloader.download(new_url)#下载该页面为String new_urls, new_data = https://www.it610.com/article/self.parser.parse(new_url,html_cont)#把页面解析为新连接和网页数据两部分,其中new_data 中含有当页的链接、title和summary,new_url是当前页面中的所有链接的集合 print new_data["title"]+"\n", new_data["summary"] self.urls.add_new_urls(new_urls)#新链接存入URL管理器 self.outputer.collect_data(new_data)#网页数据收集 if count == 10:#控制打印页面的数量 break count = count+1 except Exception,e: count2 = count2+1 print e print "craw failed"self.outputer.output_html() print str(count-count2)+" successful,"," while "+str(count2)+" failed "if __name__=="__main__": #主函数 root_url = "http://baike.baidu.com/view/21087.htm" #入口页 obj_spider = SpiderMain()#创建对象 obj_spider.craw(root_url)#启动爬虫


2.URL管理器。这部分要由两个set:new_urls和old_urls,new_urls存放还未爬取的url,old_urls存放已经爬取的url。这一模块功能有:可以添加url,判断未爬取的url集中是否还有url,当一个url被爬过后应当从new_urls移动到old_urls中。代码如下:

# coding: utf-8class UrlManager(object):def __init__(self): self.new_urls = set() self.old_urls = set()def add_new_url(self,url):#一个url的 if url is None: return#如果没有url就不存了 if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url)#如果还没有存储这一个就存下 def add_new_urls(self,urls): if urls is None or len(urls) == 0: return#没有就不添加 for url in urls: self.add_new_url(url)#调用一个url存储的方法def has_new_url(self):#判断new_urls中是否还有url return len(self.new_urls) !=0def get_new_url(self):#从new_urls中取出一个url,同时把取出的url方法old_urls中 new_url = self.new_urls.pop() self.old_urls.add(new_url) return new_url


3.url下载器。这部分只要求能把某网页的源代码下载到本地就好,以字符串的形式存放在了response变量中:
# coding: utf-8import urllib2class HtmlDownloader(object):def download(self,url): if url is None: return None #没给出页面 #request = urllib2.Request(url) #request.add_header("user-agent", "Mozilla/5.0")#把爬虫伪装为一个浏览器 response = urllib2.urlopen(url)if response.getcode() != 200:#请求是否成功 return None return response.read()#返回的是网页的字符串


4.网页解析器。这一部分把下载到的网页用beautifulsoup进行结构化解析,得到网页中的所有关于百科的链接(放在new_urls中)、该网页中的title和summary放在new_data中。代码如下

# coding: utf-8from bs4 import BeautifulSoup import re import urlparseclass HtmlParser(object): def _get_new_urls(self, page_url, soup): new_urls = set()links = soup.find_all("a",href=https://www.it610.com/article/re.compile(r"/view/\d+\.htm"))#获取所有标签名称为a的链接,这里用re嵌入了正则表达式 for link in links: new_url = link["href"]#获取不完全链接 new_full_url = urlparse.urljoin(page_url,new_url)#page_url与不完全的url整合成与page_url相似的url new_urls.add(new_full_url)#完全的url加入到新url集合中 return new_urlsdef _get_new_data(self, page_url, soup): res_data = https://www.it610.com/article/{}#字典数据类型,里面存放的是键值对。url= ??title = ??就像C中的结构体 #url res_data["url"] = page_url #
Pythontitle_node = soup.find("dd",class_="lemmaWgt-lemmaTitle-title").find("h1")#先找到标题为dd的节点,再找大它的子节点中标题为h1的节点 res_data["title"] = title_node.get_text()#获取title内容 # summary_node = soup.find("div", class_="lemma-summary")#找到包含summary的节点 res_data["summary"] = summary_node.get_text()#获取summary的内容 return res_data #返回数据,包括页面地址,该页面title和summarydef parse(self,page_url,html_cont): if page_url is None or html_cont is None: return soup = BeautifulSoup(html_cont,"html.parser",from_encoding="utf-8")#建立beautifulsoup对象,进行页面解析 new_urls = self._get_new_urls(page_url,soup)#解析得到的新url new_data = https://www.it610.com/article/self._get_new_data(page_url,soup)#解析得到当页的数据 return new_urls, new_data







5.有价值信息的输出与存储。这里把获取的信息存放在了output.html中:


# coding: utf-8class HtmlOutputer(object): def __init__(self): self.datas = []#网页的data数据暂时存放在datas中,最后在写入html文件def collect_data(self,data): if data is None: return self.datas.append(data)#ascii是python的默认编码方式,这里要指定编码方式为utf-8 #下面以网页格式输出 def output_html(self): fout = open("output.txt","w")#打开要写入的文件 fout.write("")#网页格式输出 fout.write("") fout.write("")for data in self.datas: fout.write("") fout.write(""% data["url"]) fout.write(""% data["title"].encode("utf-8")) fout.write(""% data["summary"].encode("utf-8")) fout.write("")fout.write("
%s%s%s
")#标签都是成对出现的,结尾标签是/*格式。如,对应结尾是
fout.write("") fout.write("") fout.close()#关闭文件


除了记录自己学到的内容,这篇博文还有一个目的,就是希望为和我一样学习了这门课的同学提供一个代码的校对版本。以上代码是我运行过的,完全没问题。如果大家谁的代码运行出错的话,可以过来对比一下,便于更快的找到错误。






















【Python爬虫|Python爬虫爬取百度百科内容实例】

    推荐阅读