一个简单的爬虫程序(爬取百度百科关于python的一千个页面)

最近学了点python基础,本着练手的目的跟着网上一个教程写了一个简单的爬虫程序。python入门还是很轻松的,整个过程也很顺利,几乎算是一次就成功了。

1.爬虫架构及工作流程

一个爬虫程序可以分为四个基本模块,总调度端,URL管理器,网页下载器以及网页解析器。
总调度段负责程序的启动,停止以及监视程序的运行进度。
URL管理器负责管理已经爬取过的URL和未爬取过的URL,它将未爬取过的网页URL发送给网页下载器并将该URL从为爬取URL列表删除。
网页下载器负责下载网页内容,转换成字符串形式(本程序中)发送给网页解析器。
网页解析器负责从爬取的网页内容中提取有价值的数据,本程序中有价值的数据为,网页中的URL以及词条名和词条简介。
2.各模块的实现

2.1 URL管理器的实现
网页URL可以存放到内存中(以set()的形式),MySQL数据库中以及redis缓存数据库中(大型项目)。本项目的URL以set()形式存放在内存中。
代码:

class UrlManager(object):

    def __init__(self):
        #初始化两个url集合
        self.new_urls=set()#存放未爬取过的url
        self.old_urls=set()#存放已爬取过的url
    def add_new_url(self,url):#单个添加
        if url is None:
            return #如果是空的则不进行操作
        if url not in self.new_urls and url not in self.old_urls:#全新的url
            self.new_urls.add(url)



    def has_new_url(self):#判断是否有未爬取的url
        return len(self.new_urls)!=0


    def get_new_url(self):
        new_url = self.new_urls.pop()#从未怕去的url列表获取一个并移除
        self.old_urls.add(new_url)
        return new_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)

2.2 网页下载器的实现
有三种方法下载网页
1.下载最简单的网页(无需登录验证,没有加密…)
response = urllib.request.urlopen(url, data=None, timeout)

  • url: 需要打开的网址

  • data:Post提交的数据

  • timeout:设置网站的访问超时时间
    page = response.read()
    page = page.decode(‘utf-8’)#设置编码
    2.先获取一个请求对象:urllib.request.Request(url, data=None, headers={}, method=None)
    可以给包装请求对象设置header包装请求对象
    header的参数
    User-Agent :这个头部可以携带如下几条信息:浏览器名和版本号、操作系统名和版本号、默认语言

Referer:可以用来防止盗链,如果REFER的信息来自其他网站则禁止访问所需要的资源

Connection:表示连接状态,记录Session的状态。
request.add_header(‘user_agent’, ‘Mozilla/5.0’) 将程序伪装成火狐浏览器
3.处理一些特殊情景
HTTPCookieProcessor 登录验证问题
ProxyHandler 处理代理问题
HTTPRedirectHandler 处理会自动跳转的网页

(还没接触到,以后再说)
本程序使用的第一种方式,代码:

def download(self,url):
        if url is None:

            return None
        request1 =urllib.request.urlopen(url)
        if request1.getcode() !=200:#请求失败
            return None
        return request1.read()

3.网页解析器的实现
用到了BeautifulSoup第三方插件,实现这个功能时要审查待爬取的网页,找到自己要爬取的内容编码,便签,用来筛选数据。代码:

def get_new_urls(self, page_url, soup):
        new_urls = set()
#         https://baike.baidu.com/item/Python
        links = soup.find_all('a',href=re.compile(r"/item/\S"))#查找页面中新的词条url
        for link in links:
            new_url = link['href']
            new_full_url = urllib.parse.urljoin(page_url, new_url)
            new_urls.add(new_full_url)

        return new_urls
    def get_new_data(self, page_url, soup):
        res_data = {}

        res_data['url'] = page_url
        #<dd class="lemmaWgt-lemmaTitle-title"><h1>Python</h1>
        title_node = soup.find('dd', class_="lemmaWgt-lemmaTitle-title").find('h1')
        res_data['title'] = title_node.get_text()
        #<div class="lemma-summary" label-module="lemmaSummary">  
        summary_node = soup.find('div',class_="lemma-summary")
        res_data['summary'] = summary_node.get_text()                               

        return res_data

    def parse(self,page_url,cont):
        print('开始解析')
        if page_url is None or cont is None:      
            return 

        soup = BeautifulSoup(cont,'html.parser',from_encoding='utf-8')
        print('soup')
        new_urls = self.get_new_urls(page_url,soup)
        new_data = self.get_new_data(page_url,soup)

        return new_urls,new_data

4.数据输出
将数据输出为html格式

def collect_data(self,data):
        if data is None:
            return None
        self.datas.append(data)#将爬取的数据集合起来




    def output_html(self):
        fout = open('d:/output.html','w',encoding='utf-8')

        fout.write("<html>")
        fout.write("<body>")
        fout.write("<table>")
        fout.write("<tr>")
        fout.write("<td>%s</td>"%'链接')
        fout.write("<td>%s</td>"%'词条')
        fout.write("<td>%s</td>"%'简介')
        fout.write("</tr>")
        for data in self.datas:
            if data is None:
                return None
            fout.write("<tr>")
            fout.write("<td>%s</td>" % data['url'])
            fout.write("<td>%s</td>" % data['title'])
            fout.write("<td>%s</td>" % data['summary'])
            fout.write("</tr>")
        fout.write("</html>")
        fout.write("</body>")
        fout.write("</table>")

5.程序调度
按顺序调用以上各个方法就好了,代码:

class SpiderMain(object):
    def __init__(self):
        self.url = url_manager.UrlManager()
        self.downloader = html_downloader.HtmlDownLoader()
        self.parser = html_parser.HtmlParser()
        self.outputer = html_outputer.OutPuter()

    def craw(self, root_url):
        count = 1 #记录当前爬取的是第几个url
        self.url.add_new_url(root_url)#把初始url添加到url管理器

        while self.url.has_new_url():#当管理器里仍有未爬取url时
            try:
                new_url=self.url.get_new_url()#从管理器中拿出一个url
                print('craw %d:%s'%(count,new_url))
                html_cont=self.downloader.download(new_url)#下载这个url网页的内容
                new_urls,new_data = self.parser.parse(new_url,html_cont)#得到新的url列表,和爬取到的数据
                self.url.add_new_urls(new_urls) #将新的url添加到管理器,注意于添加root_url的方法不同
                self.outputer.collect_data(new_data)#收集数据

                if count==1000:#只爬取1000条
                    break

                count+=1
            except:
                print('爬取失败')

        self.outputer.output_html()#将收集的数据输出


if __name__ == '__main__':
    root_url='https://baike.baidu.com/item/Python'
    obj_spider = SpiderMain()
    obj_spider.craw(root_url)#启动爬虫程序
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值