050_Scrapy 爬虫框架 & 案例四大名著爬取

文章目录

      • 1. 认识 Scrapy
      • 2. Scrapy 项目——四大名著爬取
        • 2.1 items
        • 2.2 spiders
        • 2.3 Scrapy shell
        • 2.4 Item Loaders
        • 2.5 pipelines
        • 2.6 settings

1. 认识 Scrapy

Scrapy爬虫框架的优势:

  • 用户只需要定制开发几个模块, 就可以轻松实现爬虫,用来抓取网页内容和图片, 非常方便。
  • Scrapy 使用了 Twisted 异步网络框架来处理网络通讯, 加快网页下载速度, 不需要自己实现异步框架和多线程等, 并且包含了各种中间件接口, 灵活完成各种需求。

Scrapy架构流程:
只有当调度器中不存在任何request时,整个程序才会停止。(注:对于下载失败的URL,
Scrapy也会重新下载.。)
050_Scrapy 爬虫框架 & 案例四大名著爬取_第1张图片
Scrapy主要包括了以下组件:

  • 引擎(Scrapy):用来处理整个系统的数据流,触发事务(框架核心)
  • 调度器(Scheduler):用来接受引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回。可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列,由它来决定下一个要抓取的网址是什么,同时去除重复的网址
  • 下载器(Downloader):用于下载网页内容,并将网页内容返回给蜘蛛(Scrapy下载器是建立在 twisted 这个高效的异步模型上的)

安装 Scrapy

pip install scrapy

Scrapy 爬虫步骤:

  • 新建爬虫项目 ScrapyProject
scrapy startproject ScrapyProject
  • 明确抓取目标 —> 编写item.py
  • 制作spider,爬取页面 ----> spiders/xxspider.py
# 创建一个名为book的spider用于爬取网络小说,所爬取的网址暂定为book.com,后续可修改
scrapy genspider book book.com
  • 存储爬虫,设置管道存储爬取内容 —> pipelines.py
  • 项目编写完成后,启动爬虫功能 book
scrapy crawl book

项目结构大体如下图所示:
050_Scrapy 爬虫框架 & 案例四大名著爬取_第2张图片

2. Scrapy 项目——四大名著爬取

Scrapy 项目介绍并分析:

  1. 爬取网站http://shicimingju.com下的四大名著
  2. 分析后可知,四大名著的 url 信息分别为
    ‘http://shicimingju.com/book/sanguoyanyi.html’,
    ‘http://shicimingju.com/book/hongloumeng.html’,
    ‘http://shicimingju.com/book/shuihuzhuan.html’,
    ‘http://shicimingju.com/book/xiyouji.html’,
  3. 在对每一本书对应的页面信息进行爬取时发现,要获取书籍内容必须要继续对页面下的章节url 进行数据爬取,分析如下图所示:
    050_Scrapy 爬虫框架 & 案例四大名著爬取_第3张图片
  4. 继续对章节页面分析
    050_Scrapy 爬虫框架 & 案例四大名著爬取_第4张图片

爬虫流程:

  1. 确定 start_url
  2. 引擎将起始的 url 交给调度器(存储到队列、去重)
  3. 调度器将 url 发送给 Downloader,Downloader 发起 Requests 从互联网上下载页面信息(Response)
  4. 将下载的内容交给 Spider,进行解析(parse函数),yield数据
  5. 将处理好的数据(items)

2.1 items

抓取的主要目的是从非结构化源(通常是网页)中提取结构化数据。 Scrapy Spider可以将提取的数据作为 Python 字典返回。 Python 字典虽然方便且熟悉,但缺乏结构容易在字段名称中输入错误或返回不一致的数据,尤其是在具有许多 spider 的大型项目中。

为了定义常见的输出数据格式,Scrapy提供了Item类。 项目对象是用于收集抓取数据的简单容器。 它们提供了类似于字典的API,并带有方便的语法来声明其可用字段

示例:

# ScrapyProject/items.py
import scrapy
from scrapy.loader.processors import TakeFirst

class BookItem(scrapy.Item):
    """
    定义Item类:
        1. 继承scrapy.Item类
        2. 每个属性指定为scrapy.Field(不管是什么类型)
    """
    # name = scrapy.Field()
    # content = scrapy.Field()
    # bookname = scrapy.Field()
    name = scrapy.Field(output_processor=TakeFirst())
    content = scrapy.Field(output_processor=TakeFirst())
    bookname = scrapy.Field(output_processor=TakeFirst())

2.2 spiders

BookSpider(如下2.4节示例代码) 是你定义的类,是Scrapy用于从网站(或一组网站)中获取信息的,必须继承 Spider 的子类 (scrapy.Spider) ,并定义要发出的初始请求,可以选择如何跟随页面中的链接,以及如何解析 (parse) 下载的页面内容以提取数据

Spider 子类 scrapy.Spider 中定义了一些属性和方法:

  • name:标识 spider,它在一个项目中必须是唯一的,即不能为不同的Spider设置相同的名称。

  • start_requests():必须返回一个可迭代的请求(可以返回请求列表或编写一个生成器函数),Spider将从此开始。 随后的请求将根据这些初始请求连续生成。

  • parse():调用该方法来处理为每个请求下载的响应。 response 参数是 TextResponse 的一个实例,该实例保存页面内容并具有其他有用的方法来处理它。
    parse()方法通常解析响应,提取数据并生成一个字典,并且能够查找要遵循的新URL从中创建新请求(Request)。

2.3 Scrapy shell

Scrapy shell是一个交互式shell,在其中运行可以非常快速的调试爬虫代码,而不必运行Spider。 它是用于测试代码提取数据,但是实际上也可以将其用于测试任何类型的代码,因为它也是常规的 Python shell。

Scrapy shell 主要用于测试 XPath 或 CSS 表达式,并查看它们的工作方式以及从要抓取的网页中提取数据。 可以在编写 spider 程序时以交互方式测试你的表达式,而不必运行spider 程序来测试所有更改。

运行:

scrapy shell url

050_Scrapy 爬虫框架 & 案例四大名著爬取_第5张图片
050_Scrapy 爬虫框架 & 案例四大名著爬取_第6张图片
在这里插入图片描述

2.4 Item Loaders

Item Loaders 提供了一种方便的机制来填充爬取的 Items。 虽然,可使用它们自己的类似于字典的API填充Item,但 Item Loader 提供了更方便的 API,用于在 scrapy 过程中将数据填充到item对象中,自动执行一些常见任务(例如在分配原始数据之前解析原始提取的数据)。

换句话说,项目提供了已抓取数据的容器,而项目 Item Loaders 则提供了填充该容器的机制

Item Loaders 旨在提供一种灵活,高效且容易的机制,以扩展或覆盖不同的字段解析规则方便后续的维护。

基于 2.2、2.3、2.4的介绍,spider 的代码示例(请结合对页面的分析食用)如下所示:

# ScrapyProject/spiders/book.py
import scrapy
from scrapy import Request
from scrapy.loader import ItemLoader
from ScrapyProject.items import BookItem


class BookSpider(scrapy.Spider):
    # 爬虫名称必须唯一
    name = 'book'
    base_url = "http://shicimingju.com"
    # 起始的url地址,可以指定多个,有两种方式确定
    #   1. start_urls=[] 属性设置
    #   2. 通过 start_requests 方法生成起始url地址 --> 使用方法详见https://doc.scrapy.org/en/latest/intro/tutorial.html#our-first-spider
    start_urls = [
        'http://shicimingju.com/book/sanguoyanyi.html',
        'http://shicimingju.com/book/hongloumeng.html',
        'http://shicimingju.com/book/shuihuzhuan.html',
        'http://shicimingju.com/book/xiyouji.html',
    ]

    def parse(self, response):
        """
        图书详情页解析
        1). 如何编写好的解析代码?可以使用 Scrapy 的交互式工具 scrapy shell url
        2). 如何处理解析后的数据? 通过 yield 返回解析数据的字典格式
        3). 如何获取下载小数章节详情页的链接并下载到本地
        :param response:
        :return:
        """

        # 1). 获取所有章节的li标签
        chapters = response.xpath('//div[@class="book-mulu"]/ul/li')
        # 2). 遍历每一个li标签, 提取章节的详细网址和章节名称
        for chapter in chapters:
            # -). 创建ItemLoader对象, 将item对象和selector/response关联
            l = ItemLoader(item=BookItem(), selector=chapter)
            # -). 根据xpath进行提取数据信息并填充到item对象的name属性中
            l.add_xpath('name', './a/text()')
            # -). 将数据信息(书籍名称)填充到item对象的bookname属性中
            l.add_value('bookname', response.url.split('/')[-1].strip('.html'))
            detail_url = chapter.xpath('./a/@href').extract_first()  # ....extract_first()获得列表第一个值并转换为字符串
            # 将章节详情页url提交到调度队列,通过Downloader下载器下载并提交给self.parse_chater_detail解析器进行解析处理数据
            yield Request(url=self.base_url + detail_url,
                          callback=self.parse_chater_detail,
                          # meta={"name": name, "bookname": bookname}
                          # -). load_item获取item对象
                          meta={'item': l.load_item()}
                          )

    def parse_chater_detail(self, response):
    	"""章节详情页解析"""
        # 1. .xpath('string(.)') 获取该标签及子孙标签所有的文本信息
        # 2. 如何将对象转换为字符串?
        #      - ....extract_first()/get() 获得列表中第一个值并转换为字符串
        #      - ....extract()/get_all() 获得列表中所有对象并将其转换为字符串
        item = response.meta['item']
        content = response.xpath(".//div[@class='chapter_content']")[0].xpath('string(.)').get()
        item['content'] = content
        yield item

2.5 pipelines

spider 抓取了一个项目后,将其发送到项目管道(piplines),该管道通过依次执行的几个组件对其进行处理。

每个项目管道组件(有时仅称为“项目管道”)都是一个实现简单方法的 Python 类。 他们接收到一个项目并对其执行操作,还决定该项目是否应该继续通过管道或被删除并不再处理。

piplines 的典型用途是:

  • 清理HTML数据
  • 验证抓取的数据(检查项目是否包含某些字段)
  • 检查重复项(并将其删除)
  • 将 scrapy 的 items 存储在数据库中

组件 process_item(self, item, spider)
每个项目管道组件均调用此方法。 process_item() 必须执行以下操作之一:返回带有数据的字典;返回Item(或任何后代类)对象;返回Deferred或引发DropItem异常。
删除的项目不再由其他管道组件处理。

参数:

  • item (Item object or a dict) – the item scraped
  • spider (Spider object) – the spider which scraped the item

代码示例:

import os


class ScrapyprojectPipeline(object):
    """设置管道存储爬取内容"""

    def process_item(self, item, spider):
        # books/xiyouji
        dirname = os.path.join("books", item["bookname"])
        if not os.path.exists(dirname):
            os.makedirs(dirname)  # 递归创建目录
        name = item["name"]
        # 文件名的相对路径用join方法拼接:linux路径拼接符是/;windows是\
        filename = os.path.join(dirname, name)
        # 写入文件以 w 方式打开,并指定编码格式为 utf-8 写入中文
        with open(filename, "w", encoding="utf-8") as f:
            f.write(item["content"])
            # print("写入文件%s成功" % name)
        return item

2.6 settings

项目的设置文件 settings.py
在这里插入图片描述

最后,执行 scrapy crael book 后可以获得:
050_Scrapy 爬虫框架 & 案例四大名著爬取_第7张图片

你可能感兴趣的:(爬虫,python,爬虫,scrapy)