查看原文
其他

【41计划打卡-05】python爬虫帮你百度“相关”的内容

叉烧ZBayes CS的陋室 2022-08-08

往期:

【41计划打卡-01】R语言个人学习笔记

【41计划打卡-02】AvalonJs-前端MVVM框架

【41计划打卡-03】《大数据时代》读后感

【41计划打卡-04】python爬虫基础


上期讲到了python爬虫的基础,了解到上期的python的基本逻辑和原理,今天讲给出一个关于百度百科的爬虫案例,点击阅读原文可查看到项目代码。该案例同样来自于慕课网的教程:

Python开发简单爬虫:http://www.imooc.com/learn/563


爬取前准备:

下面是百度百科关于Python的介绍。除了介绍,Python里面还存在大量的蓝色链接,这些链接能让你进一步对Python的相关内容有更多了解,因此,可以通过这些链接,我们能爬取更多和Python有关的数据。


然后需要对网页的html进行分析,需要了解html中我们需要爬取那些内容。

html下对Python标题,可以通过class进行查询。


而摘要段落同样可以class这个特性来实现查询(一个题外话,lemma似乎是一种百度使用的框架?)。


至于链接,可以看到其herf有一定的规律和格式,利用正则表达式能匹配到相关的链接,方便进一步查询。

目标:

  • 以Python为例,抓取百度百科与之有关的1000个链接页面的数据,并输出到output.html文件。

目标细化:

  • 实例目标:百度百科Python词条相关词条网页、标题和简介

  • 入口页:

  • URL格式:

    • 词条网页URL:/view/125370.htm

  • 数据格式

    • 标题:<dd class='lemmaWgt-lemmaTitle-title'><h1>**</h1></dd>

    • 简介:<div class='lemma-summary'>***<div>

  • 页面编码:UTF-8

需要的运行环境:

pycharm、Python2.7、BeautifulSoup4、urllib2等

组件的简要说明

主程序 

入口程序,用于指导整个爬虫的运行

craw(root_url) 爬取内容

首先需要对相应的变量和其他组件进行初始化,包括URL管理器,html下载器,解析器和输出器。在craw中定义了爬取内容的过程,从定义爬取内容,到运用上述组件进行数据爬取和处理。定义爬取函数之后,即可对开始执行。下面是实现代码:

# coding:utf-8

# spider_main.py: 入口程序,用于指导整个爬虫的运行

# from baike_spider import url_manager, html_downloader, html_parser, html_outputer

import url_manager, html_downloader, html_outputer, html_parser


class SpiderMain(object):

    def __init__(self):

        # 初始化

        self.urls=url_manager.UrlManager()

        self.downloader=html_downloader.HtmlDownloader()

        self.parser=html_parser.HtmlParser()

        self.outputer=html_outputer.HtmlOutputer()


    def craw(self,root_url):

        # 爬取内容

        count=1                             # 爬取的数据量

        self.urls.add_new_url(root_url)     # 添加入口链接

        while self.urls.has_new_url():      # 从url池中爬取数据和添加新的url到url池中

            try:

                new_url=self.urls.get_new_url()

                print 'craw %d : % s'%(count,new_url)

                html_cont=self.downloader.download(new_url)

                new_urls,new_data=self.parser.parse(new_url,html_cont)

                self.urls.add_new_urls(new_urls)

                self.outputer.collect_data(new_data)


                if count==1000:

                    break


                count=count+1

            except:                         # 防止链接失效等其他意外错误

                print 'craw failed'


        self.outputer.output_html()


if __name__=="__main__":                    # 主程序

    root_url="http://baike.baidu.com/view/21087.htm"

    obj_spider=SpiderMain()

    obj_spider.craw(root_url)

url管理器 url_manager.py

url管理器,对新旧url进行管理

__init__() 初始化
add_new_url(url) 添加新链接
add_new_urls(urls) 批量添加新链接
has_new_url() 验证该链接是否已在url池中
get_new_url() 获取新链接

定义一个类作为url管理器,首先需要定义初始化函数,后面的函数就涉及对url的各种处理。url管理器需要设置两个集合,一个放新链接,另一个放已经被爬取过的链接。首先需要接受新的链接,存入,还要给出接口,为主程序新的链接进行爬取。对某些链接,可能在接受时已经在集合里面,这时应不再放入,这点需要设置函数实现。

# coding:utf8

# url_manager.py: url管理器,对新旧url进行管理。


class UrlManager(object):

    # 初始化

    def __init__(self):

        self.new_urls=set()

        self.old_urls=set()


    # 添加新链接

    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:

            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):

        return len(self.new_urls)!=0


    # 获取新链接

    def get_new_url(self):

        new_url=self.new_urls.pop()

        self.old_urls.add(new_url)

        return new_url

网页下载器 html_downloader.py

网页下载器,用urllib2进行下载

download(url) urllib2对网页进行下载

这段代码相对简单,即用urllib2进行网页下载。

# coding:utf8

# html_downloader.py: 网页下载器,用urllib2进行下载

import urllib2


class HtmlDownloader(object):

    # urllib2对网页进行下载

    def download(self,url):

        if url is None:

            return None


        response=urllib2.urlopen(url)


        if response.getcode()!=200:

            return None


        return  response.read()

网页解析器 html_parser.py

网页解析器,运用BeautifulSoup进行网页解析

_get_new_urls(page_url,soup) 获取新url
_get_new_data(page_url,soup) 获取新数据,解析链接内容
parse(page_url,html_cont) 规范化数据

网页解析器需要对网页进行解析,首先是获取新的url和新数据,然后对数据进行规范化,同时在新数据中解析找到新的链接方便下一步的爬取。

# coding:utf8

# html_parser.py: url网页解析器,运用BeautifulSoup进行网页解析


from bs4 import BeautifulSoup

import re

import urlparse


class HtmlParser(object):

    # 获取新url

    def _get_new_urls(self,page_url,soup):

        new_urls=set()

        # /view/123.html

        links=soup.find_all('a',href=re.compile(r"/view/\d+\.htm"))

        for link in links:

            new_url=link['href']

            new_full_url=urlparse.urljoin(page_url,new_url)

            new_urls.add(new_full_url)

        return new_urls


    # 获取新数据,解析链接内容

    def _get_new_data(self,page_url,soup):

        res_data={}


        # url

        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"> <div class="para" label-module="para">

        summary_node=soup.find('div',class_='lemma-summary')

        res_data['summary']=summary_node.get_text()


        return res_data


    # 规范化数据

    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')

        new_urls=self._get_new_urls(page_url,soup)

        new_data=self._get_new_data(page_url,soup)

        return new_urls,new_data

结果输出组件 html_outputer.py

结果输出组件,对爬取的结果进行输出。

__init__() 初始化
collect_data(data) 数据收集
output_html() 结果输出


最后,对爬取得到的数据进行收集和输出。首先获取解析得到的内容,然后放到数据集中,并准备输出。

# coding:utf8

# html_outputer.py: 结果输出器

class HtmlOutputer(object):

    # 初始化

    def __init__(self):

        self.datas=[]


    # 数据收集

    def collect_data(self,data):

        if data is None:

            return

        self.datas.append(data)


    # 结果输出

    def output_html(self):

        fout=open('output.html','w')


        fout.write("<html>")

        fout.write("<body>")

        fout.write("<table>")


        # 补充:需要将ascii转为utf-8

        for data in self.datas:

            fout.write("<tr>")

            fout.write("<td>%s</td>" % data['url'])

            fout.write("<td>%s</td>" % data['title'].encode('utf-8'))

            fout.write("<td>%s</td>" % data['summary'].encode('utf-8'))

            fout.write("</tr>")


        fout.write("</table>")

        fout.write("</body>")

        fout.write("</html>")


        fout.close()

运行结果

最后运行spider_main.py,等待若干时间(如果爬取足够多的数据,可能需要半个小时甚至更多,趁这个时间去转转吧)。运行之后能发现你的文件夹里会多一个文件“output.html”,双击打开即可查看到你爬取到的数据。下面我爬取的结果:

结果以表格形式展现(我没有画线框),第一列是信息来源的链接,中间是主题词,右边是关于该词的摘要或是简单描述。通过这些数据能进一步进行研究。

最后强调一点

从这一整个项目可以看到,简单的爬虫需要的基础知识比较广,如python基础以及相关包的使用,还有html语言和结点,另外还需要正则表达式等。有这些基础知识基本就能实现上述内容了。


但是,这只是最简单的爬虫,在对某些网址,还有登录、验证码、Ajax、服务器防爬虫、多线程、分布式等问题,部分网站还有反爬虫保护,我们若需要爬取信息,则还要进一步研究,从某种程度上说,爬虫算是一种黑客行为,哈哈。


微信:zgr950123
QQ:545281848欢迎关注


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存