美文网首页Python新世界
Python3 开发轻量级爬虫教程!

Python3 开发轻量级爬虫教程!

作者: 919b0c54458f | 来源:发表于2018-09-30 13:30 被阅读8次

    爬虫又被称为网页蜘蛛,网络机器人。是一种按照一定的规则,自动地抓取互联网上信息的程序或者脚本。

    一、爬虫算法

    在写爬虫时候有两种常用的算法可使用,即深度优先算法、广度优先算法。

    深度优先算法

    进群:548377875   即可获取数十套PDF哦!

    对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。直到访问完成后再返回到最上层,然后重复上述步骤。

    广度优先算法

    从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。

    负载均衡

    当爬取量很大的话,需要负载到多台服务器同时运行(搜索引擎都是这么做的)。但这样会出现一个问题,当 A 服务器已经爬取完成的 URL,但 B 服务器并不知道 A 是否爬取完成,这样会造成资源的浪费,那怎么办呢?如何突破爬虫的瓶颈?

    其中最简单的便是 URL 分类。举个栗子:现在有 A、B、C、D、X 五台服务器同时运行爬虫,X 为负载均衡服务器。所有的 URL 都要经过 X 服务器进行分配, X 服务器遇到域名是 .com 结尾的就分配给 A,遇到 .cn 结尾就分配给 B,遇到 .net 结尾就分配给 C,其他域名都分配给 D。这样就解决了爬虫瓶颈的问题,这个问题可是谷歌的面试题。

    二、爬虫逻辑

    爬虫可大致分为五个部分:

    调度器:引擎,是爬虫逻辑实现的模块

    管理器:URL 管理器,负责新增、删除、获取、存储、计数等功能,避免爬取重复的 URL。

    下载器:HTML 下载器,将 URL 地址中的 HTML 内容获取到

    解析器:HTML 解析器,将 HTML 获取到的内容进行分析

    输出器:将分析完成后的数据进行输出、存储、利用等

    爬虫逻辑可分解为如下几个部分:

    查询管理器中是否有待爬取的 URL

    调度器从管理器中获取一个待爬取 URL

    将获取到的 URL 交给下载器处理

    将下载器获取到的网页数据交给解析器处理

    将解析器处理后的 URL 集合交给管理器

    将解析器处理后的数据交给输出器

    重复上述步骤

    三、开发轻量级爬虫

    1. 调度器

    spider.py

    #!/usr/bin/env python3

    # -*- coding: UTF-8 -*-

    #

    # 【调度器】

    #

    # 调度器又称为引擎,是爬虫逻辑实现的模块。

    #

    # 爬虫逻辑可分解为如下几个部分:

    #

    # 1. 查询管理器中是否有待爬取的 URL

    # 2. 调度器从管理器中获取一个待爬取 URL

    # 3. 将获取到的 URL 交给下载器处理

    # 4. 将下载器获取到的网页数据交给解析器处理

    # 5. 将解析器处理后的 URL 集合交给管理器

    # 6. 将解析器处理后的数据交给输出器

    # 7. 重复上述步骤

    #

    import manager, download, parser, output

    class Spider(object):

    def __init__(self):

    # 实例化 管理器、下载器、解析器、输出器

    self.manager = manager.Manager()

    self.download = download.Download()

    self.parser = parser.Parser()

    self.output = output.Output()

    def spider(self, url):

    # 爬虫计数器

    count = 0

    # 将第一个 URL 放入管理器中

    self.manager.add_url(url)

    # 判断管理器中 URL 的数量是否为 0

    while self.manager.num_url():

    try:

    # 从管理器中获取一个 URL

    new_url = self.manager.get_url()

    # 将获取到的 URL 交给下载器处理

    html_cont = self.download.download(new_url)

    # 将 URL 和 下载器处理后的网页数据交给解析器处理

    new_manager, new_data = self.parser.parser(new_url, html_cont)

    # 将解析器处理后的数据和新的 URL 分别交给管理器和输出器

    self.manager.add_urls(new_manager)

    self.output.add_data(new_data)

    # 最多爬取 100 次

    if count == 100:

    break

    count += 1

    print('爬虫运行状态 ==> %d : %s' % (count, new_url))

    except:

    print('爬虫爬取失败')

    # 当爬虫爬取完所有数据后,输出器将数据输出到文件

    self.output.output()

    if __name__ == '__main__':

    # URL 入口(爬虫爬取的第一个 URL)

    url = 'http://www.cnblogs.com/peida/archive/2012/12/05/2803591.html'

    # 实例化调度器并启动爬虫

    run = Spider()

    run.spider(url)

    2. 管理器

    manager.py

    #!/usr/bin/env python3

    # -*- coding: UTF-8 -*-

    #

    # 【管理器】

    #

    # 对外提供四个方法:

    #

    # 1. add_url(url)

    # 添加一个 URL,接收一个参数 URL

    #

    # 2. add_urls(url)

    # 批量添加 URL,接收一个参数 URL

    #

    # 3. num_url()

    # 管理器中URL 的数量

    #

    # 4. get_url()

    # 从管理器中获取一个 URL

    #

    class Manager(object):

    def __init__(self):

    # 待爬取的 URL 集合

    self.new_urls = set()

    # 已爬取的 URL 集合

    self.old_urls = set()

    # 添加一个 URL

    def add_url(self, url):

    # 判断 url 是否为空,为空则返回 None

    if url is None:

    return

    # 判断 url 是否存在于【待爬取的 URL 集合】和【已爬取的 URL 集合】,如若都不在将新 url 添加到【待爬取的 URL 集合】中

    if url not in self.new_urls and url not in self.old_urls:

    self.new_urls.add(url)

    # 批量添加 URL

    def add_urls(self, urls):

    if urls is None or len(urls) == 0:

    return

    for url in urls:

    # 将 URL 集合交给 add_url() 函数处理

    self.add_url(url)

    # 返回管理器中 URL 的数量

    def num_url(self):

    return len(self.new_urls) != 0

    # 从管理器中获取一个 URL

    def get_url(self):

    url = self.new_urls.pop()

    self.old_urls.add(url)

    return url

    3. 下载器

    download.py

    #!/usr/bin/env python3

    # -*- coding: UTF-8 -*-

    #

    # 【下载器】

    #

    # requests 模块需要安装

    # sudo pip3 install requests

    #

    # 对外提供一个方法:

    #

    # download(url)

    # 下载网页中的内容,接收一个参数 URL

    #

    import requests

    class Download(object):

    def download(self, url):

    # 判断 URL 是否为空,为空直接返回 None

    if url is None:

    return None

    # 请求 URL

    response = requests.get(url = url)

    # 判断 URL 地址是否访问成功,若失败直接返回 None

    if response.status_code != 200:

    return None

    return response.text

    4. 解析器

    parser.py

    #!/usr/bin/env python3

    # -*- coding: UTF-8 -*-

    #

    # 【解析器】

    #

    # bs4 模块需要安装

    # sudo pip3 install bs4

    #

    # 对外提供一个方法:

    #

    # 1. parser(url)

    # BeautifulSoup DOM 树处理,接收两个参数 URL 和 html 内容

    #

    # 对内提供两个方法:

    #

    # 1. _get_urls(url, soup)

    # 获取网页中的 URL,接收两个参数 URL 和 DOM 树

    #

    # 2. _get_data(url, soup)

    # 获取网页中的数据,接收两个参数 URL 和 DOM 树

    #

    import re

    from bs4 import BeautifulSoup

    class Parser(object):

    def _get_urls(self, url, soup):

    urls = set()

    links = soup.find_all('a', href=re.compile(r'/peida/archive/*'))

    for link in links:

    new_url = link['href']

    urls.add(new_url)

    return urls

    def _get_data(self, url, soup):

    res_data = {}

    res_data['url'] = url

    title_node = soup.find('div', class_='post').find('a')

    res_data['title'] = title_node.get_text()

    return res_data

    def parser(self, url, html):

    # 判断 url 是否为空,或网页数据是否为空,为空则返回 None

    if url is None or html is None:

    return

    # 格式化 html 为 BeautifulSoup DOM 树

    soup = BeautifulSoup(html, 'html.parser')

    # 获取网页中的 URL

    urls = self._get_urls(url, soup)

    # 获取网页中的数据

    data = self._get_data(url, soup)

    return urls, data

    5. 输出器

    output.py

    #!/usr/bin/env python3

    # -*- coding: UTF-8 -*-

    #

    # 【输出器】

    #

    # 对外提供两个方法:

    #

    # 1. add_data(data)

    # 存储网页数据,接收一个参数 data

    #

    # 2. output()

    # 将数据输出到 html 文件中

    #

    class Output(object):

    def __init__(self):

    self.datas = []

    def add_data(self, data):

    if data is None:

    return

    self.datas.append(data)

    def output(self):

    head = '''

    '''

    foot = '''

    '''

    with open('CSDN.html', 'w') as f:

    f.write(head)

    for data in self.datas:

    f.write('%s' % (data['url'], data['url']))

    f.write('%s' % data['title'])

    f.write(foot)

    运行结果:

    今天就聊到这里啦,大家记得点赞收藏,分享转发,关注哟!

    相关文章

      网友评论

        本文标题:Python3 开发轻量级爬虫教程!

        本文链接:https://www.haomeiwen.com/subject/splwoftx.html