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_outputer

class 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 = 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-8

class 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) !=0

    def 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-8


import urllib2


class 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-8

from bs4 import BeautifulSoup
import re
import urlparse


class HtmlParser(object): 
    
    def _get_new_urls(self, page_url, soup):
        new_urls = set()
        
        links = soup.find_all("a",href=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_urls
    
    def _get_new_data(self, page_url, soup):
        res_data = {}#字典数据类型,里面存放的是键值对。url= ??title = ??就像C中的结构体
        #url
        res_data["url"] = page_url 
        #

Python

title_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和summary def 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 = self._get_new_data(page_url,soup)#解析得到当页的数据 return new_urls, new_data




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

# coding: utf-8


class 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爬虫,系统配置)