• 爬虫 — Scrapy 框架(一)


    一、介绍

    Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

    点击进入官网

    1、同步与异步

    同步:指的是按照代码的顺序依次执行,每个任务都要等待上一个任务完成后才能执行,处理大量任务或耗时操作时可能导致程序性能下降。

    异步一个任务的执行不会影响到后续任务的执行,允许程序在等待某个操作完成的同时执行其它任务,提高了程序的并发性和性能。

    2、阻塞与非阻塞

    阻塞:指的是当一个任务执行一个 I/O 操作时,任务会一直等待直到操作完成才能继续执行后续代码,当任务发起一个 I/O 操作(如读取文件、发送网络请求等),任务会被挂起,直到操作完成后才能恢复执行,可能会造成资源浪费和程序响应性下降。

    非阻塞:指的是当一个任务执行一个 I/O 操作时,任务不会等待操作完成,而是立即返回并继续执行后续代码,当任务发起一个 I/O 操作,如果操作不能立即完成,任务不会被挂起,而是继续执行后续代码,提高了程序的并发性和响应性。

    二、工作流程

    在这里插入图片描述

    各组件作用

    组件作用是否需要手写
    引擎(Scrapy Engine)总指挥:负责数据和信号的在不同模块间的传递Scrapy 已经实现
    调度器(Scheduler)一个队列,存放引擎发过来的 request 请求Scrapy 已经实现
    下载器(Downloader)下载把引擎发过来的 request 请求,并返回给引擎Scrapy 已经实现
    爬虫(Spider)处理引擎发过来的 request,提取数据,提取 url,并交给引擎需要手写
    管道(Item Pipline)处理引擎传过来的数据,比如存储需要手写
    下载中间件(Downloader Middlewares)可以自定义的下载扩展,比如设置 User-Agent 代理一般不用手写
    爬虫中间件(Spider Middlewares)可以自定义 requests 请求和进行 requests 过滤一般不用手写

    大概流程

    • 爬虫(Spider)发起初始请求。
    • 下载器(Downloader)下载网页并将响应返回给爬虫(Spider)。
    • 爬虫(Spider)解析响应,提取数据和新的请求。
    • 新的请求由调度器(Scheduler)进行调度,并交给下载器(Downloader)下载。
    • 数据由爬虫(Spider)交给管道(Item Pipline)进行处理。

    三、项目结构

    1、安装

    在终端输入命令:

    pip install scrapy==2.5.1

    2、项目文件夹

    2.1、方式一

    在目标文件夹地址栏直接输入 cmd 后,按回车。

    在这里插入图片描述

    2.2、方式二

    按 win + r 弹出一个窗口,输入 cmd 命令后按回车,会进入终端,输入命令,进入目标文件夹。

    切换盘符:

    f:

    切换到目标文件夹:

    cd F:\Python

    在这里插入图片描述

    3、创建项目

    scrapy startproject mySpider

    scrapy startproject 是创建一个爬虫项目的固定命令,mySpider 是项目名称,可更改。

    cd mySpider

    切换到项目文件夹

    scrapy genspider demo baidu.com

    scrapy genspider 是生成爬虫文件的固定命令,demo 是爬虫文件名,可更改,baidu.com 是爬取的域名,可更改。

    在这里插入图片描述

    4、项目文件组成

    4.1、piders/__ init __.py

    这是一个空的 __ init __.py 文件,用于标识 spiders 目录为一个 Python 包。在该目录中,通常存放着 Scrapy 框架中的爬虫(Spider)模块文件。

    4.2、spiders/demo.py

    这是一个爬虫(Spider)模块文件,包含了定义一个名为 demo 的 Spider 类的代码。该 Spider 类定义了如何发起请求、解析响应和提取数据的逻辑。

    4.3、__ init __.py

    这是一个空的 __ init __.py 文件,用于标识当前目录为一个 Python 包。

    4.4、items.py

    这是一个模型(Model)模块文件,用于定义抓取的数据结构。通常,可以在该文件中定义一个名为 Item 的类,描述要抓取的数据的字段和结构。

    4.5、middlewares.py

    这是一个中间件(Middleware)模块文件,用于定义 Scrapy 框架中的中间件组件。中间件可以在请求和响应的处理过程中进行自定义操作,例如修改请求头、处理代理等。

    4.6、pipelines.py

    这是一个管道(Pipeline)模块文件,用于定义 Scrapy 框架中的数据处理管道组件。管道负责对爬取的数据进行处理,例如数据清洗、验证和存储等操作。

    4.7、settings.py

    这是一个配置(Settings)模块文件,包含了 Scrapy 框架的配置选项。可以在该文件中设置爬虫的参数、中间件、管道以及其它框架相关的设置。

    4.8、scrapy.cfg

    这是 Scrapy 项目的配置文件,包含了项目的基本配置信息,如项目名称、启用的爬虫、管道和中间件等。

    5、运行项目

    5.1、方式一

    在终端运行

    scrapy crawl demo  # demo 是爬虫文件的名字
    
    • 1

    5.2、方式二

    在当前项目下创建一个 py 文件

    from scrapy import cmdline
    
    # demo 是爬虫文件的名字
    cmdline.execute('scrapy crawl demo'.split())
    
    • 1
    • 2
    • 3
    • 4

    四、入门案例

    目标网站:https://quotes.toscrape.com/

    需求:翻页爬取每页的名人,名言,标签

    页面分析

    1、先获取第一页数据,再实现翻页爬取

    2、确定 url,通过分析,可以在源码中看到数据,确定数据是静态加载,所以目标 url 为 https://quotes.toscrape.com/

    3、确定数据在网页中的位置,通过 xpath 解析

    3.1、每一条数据都存放在

    标签里面,所以 xpath 语法://div[@class="quote"],返回一个元素列表,进行遍历

    3.2、名言 xpath 语法为:.//span[1]/text()

    3.3、作者 xpath 语法为:.//span[2]/small[1]/text()

    3.4、标签 xpath 语法为:.//div[1]/a/text()

    项目实现

    1、打开终端,进入对应的文件目录下

    2、创建 Scrapy 项目:scrapy startproject my_scrapy

    3、进入项目:cd my_scrapy

    4、创建爬虫文件:scrapy genspider spider quotes.toscrape.com

    代码实现

    1、在项目目录下创建一个 start.py 文件,用来运行项目。

    注意:一定要在 start.py 文件下运行,在其它项目文件下运行,该项目不生效。

    # start.py
    # 使用 cmdline 模块来执行命令行命令
    from scrapy import cmdline
    
    # 使用 Scrapy 执行名为 spider 的爬虫
    cmdline.execute('scrapy crawl spider'.split())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行后会打印红色的日志信息,可在 settings.py 文件里设置隐藏日志信息。

    # settings.py
    # 日志级别调整为警告
    LOG_LEVEL = 'WARNING'
    
    • 1
    • 2
    • 3

    2、获取网页源代码,在 spider.py 文件里做相关操作。

    # spider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    
    # 定义一个爬虫类
    class SpiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'spider'
        # 允许爬取的域名
        allowed_domains = ['quotes.toscrape.com']
        # 起始 url
        start_urls = ['https://quotes.toscrape.com/']
    
        # 解析函数,处理响应并提取数据
        def parse(self, response):
            # 打印响应结果
            print(response.text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3、创建项目的相关数据结构,在 items.py 文件里做相关操作。

    # items.py
    import scrapy  # 导入Scrapy库,用于构建爬虫
    
    # 自定义的Item类,用于存储爬取的数据
    class MyScrapyItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
    
        # 名言
        text = scrapy.Field()  # 用于存储名言文本内容的字段
        # 名人
        author = scrapy.Field()  # 用于存储名人文本内容的字段
        # 标签
        tags = scrapy.Field()  # 用于存储标签文本内容的字段
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、确定获取到源码之后,在 spider.py 文件里做解析。

    # spider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    from my_scrapy.items import MyScrapyItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    # 定义一个爬虫类
    class SpiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'spider'
        # 允许爬取的域名
        allowed_domains = ['quotes.toscrape.com']
        # 起始 url
        start_urls = ['https://quotes.toscrape.com/']
    
        # 解析函数,处理响应并提取数据
        def parse(self, response):
            # 使用 XPath 选取所有 class 为 quote 的 div 元素
            divs = response.xpath('//div[@class="quote"]')
            # 遍历每个 div 元素
            for div in divs:
                # 创建一个 MyScrapyItem 实例,用于存储爬取的数据
                item = MyScrapyItem()
                # 获取名言文本
                item['text'] = div.xpath('.//span[1]/text()').get()
                # 获取名人文本
                item['author'] = div.xpath('.//span[2]/small[1]/text()').get()
                # 获取标签文本
                item['tags'] = div.xpath('.//div[1]/a/text()').getall()
                # 打印数据
                print(item)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    注意:在 Scrapy 框架里,get() 返回一条数据,getall() 返回多条数据。

    5、确定当前数据获取到之后,进行翻页获取其它数据。

    # spider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    from my_scrapy.items import MyScrapyItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    # 定义一个爬虫类
    class SpiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'spider'
        # 允许爬取的域名
        allowed_domains = ['quotes.toscrape.com']
        # 起始 url
        start_urls = ['https://quotes.toscrape.com/']
    
        # 解析函数,处理响应并提取数据
        def parse(self, response):
            # 使用 XPath 选取所有 class 为 quote 的 div 元素
            divs = response.xpath('//div[@class="quote"]')
            # 遍历每个 div 元素
            for div in divs:
                # 创建一个 MyScrapyItem 实例,用于存储爬取的数据
                item = MyScrapyItem()
                # 获取名言文本
                item['text'] = div.xpath('.//span[1]/text()').get()
                # 获取名人文本
                item['author'] = div.xpath('.//span[2]/small[1]/text()').get()
                # 获取标签文本
                item['tags'] = div.xpath('.//div[1]/a/text()').getall()
                # 返回 item,将其传递给引擎
                yield item
    
            # 翻页爬取,获取下一页按钮
            next = response.xpath('//li[@class="next"]/a/@href').get()
            # 拼接下一页链接
            # 方法一:
            # url = self.start_urls[0] + next
            # 方法二:
            url = response.urljoin(next)
            # 发起一个新的请求,url 为 next 的绝对 url,并将响应交给 parse 方法处理
            yield scrapy.Request(url, callback=self.parse)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    注意:
    正常操作运行项目,代码可能会有报错,这个时候可以考虑是不是允许爬取的域名做了限制,可以将 allowed_domains =[‘quotes.toscrape.com’] 注释掉。

    6、保存数据

    6.1、方法一

    可以在 start.py 文件直接进行保存。

    # start.py
    # 使用 cmdline 模块来执行命令行命令
    from scrapy import cmdline
    
    # 使用 Scrapy 执行名为 spider 的爬虫
    # cmdline.execute('scrapy crawl spider'.split())
    
    # 使用 Scrapy 执行名为 spider 的爬虫,并将结果保存到 demo.csv 文件中
    cmdline.execute('scrapy crawl spider -o demo.csv'.split())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6.2、方法二

    可以在管道里面保存数据。

    # pipelines.py
    # 自定义的管道类
    class MyScrapyPipeline:
        # 处理 Item 的方法,负责将数据存储到文件中
        def process_item(self, item, spider):
            # 保存数据
            with open('demo.txt', 'a', encoding='utf-8') as f:
                # 将 item 中的 text 字段和 author 字段拼接为一个字符串
                s = item['text'] + item['author']
                # 将拼接后的字符串写入文件,并在末尾添加换行符
                f.write(s + '\n')
            # 返回 item,继续后续的处理过程
            return item
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意:在管道里面保存数据,要记得在 setting.py 里启用管道,找到以下代码并取消注释。

    ITEM_PIPELINES = {
       'my_scrapy.pipelines.MyScrapyPipeline': 300,
    }
    
    • 1
    • 2
    • 3

    五、翻页

    目标网站:https://quotes.toscrape.com/

    需求:翻页爬取前4页的名人,名言,标签

    分析

    需要重新构造 url

    第一页:https://quotes.toscrape.com/page/1/

    第二页:https://quotes.toscrape.com/page/2/

    第三页:https://quotes.toscrape.com/page/3/

    第四页:https://quotes.toscrape.com/page/4/

    方法一:

    # spider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    from my_scrapy.items import MyScrapyItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    # 定义一个爬虫类
    class SpiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'spider'
       # 爬虫的名称
        allowed_domains = ['quotes.toscrape.com']
        # 页码
        page = 1
        # 链接 url
        base_url = 'https://quotes.toscrape.com/page/{}/'
        # 起始 url
        start_urls = [base_url.format(page)]
    
        # 解析函数,处理响应并提取数据
        def parse(self, response):
            # 使用 XPath 选取所有 class 为 quote 的 div 元素
            divs = response.xpath('//div[@class="quote"]')
            # 遍历每个 div 元素
            for div in divs:
                # 创建一个 MyScrapyItem 实例,用于存储爬取的数据
                item = MyScrapyItem()
                # 获取名言文本
                item['text'] = div.xpath('.//span[1]/text()').get()
                # 获取名人文本
                item['author'] = div.xpath('.//span[2]/small[1]/text()').get()
                # 获取标签文本
                item['tags'] = div.xpath('.//div[1]/a/text()').getall()
                # 返回 item,将其传递给引擎
                yield item
    
            # 判断页码
            if self.page <= 4:
                # 页码
                self.page = self.page + 1
                # 获取数据
                yield scrapy.Request(self.base_url.format(self.page), callback=self.parse) # callback是回调函数,相当于是发完请求,在那个方法中解析
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    方法二:
    重写内部的方法实现翻页。

    # spider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    from my_scrapy.items import MyScrapyItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    # 定义一个爬虫类
    class SpiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'spider'
        # 允许爬取的域名
        allowed_domains = ['quotes.toscrape.com']
        # 页码
        page = 1
        # 链接 url
        base_url = 'https://quotes.toscrape.com/page/{}/'
        # 起始 url
        start_urls = [base_url.format(page)]
    
        # start_reqeusts 重写的父类方法,优先执行自己
        def start_requests(self):
            # 翻页
            for page in range(1, 5):
                # 确定 url
                url = self.base_url.format(page)
                # 获取数据
                yield scrapy.Request(url, callback=self.parse)
    
        # 解析函数,处理响应并提取数据
        def parse(self, response):
            # 使用 XPath 选取所有 class 为 quote 的 div 元素
            divs = response.xpath('//div[@class="quote"]')
            # 遍历每个 div 元素
            for div in divs:
                # 创建一个 MyScrapyItem 实例,用于存储爬取的数据
                item = MyScrapyItem()
                # 获取名言文本
                item['text'] = div.xpath('.//span[1]/text()').get()
                # 获取名人文本
                item['author'] = div.xpath('.//span[2]/small[1]/text()').get()
                # 获取标签文本
                item['tags'] = div.xpath('.//div[1]/a/text()').getall()
                # 返回 item,将其传递给引擎
                yield item
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    六、parsel 第三方库

    内置了 css 选择器,xpath,re,必须通过 get、getall 获取内容。

    模拟数据

    import parsel
    
    html_doc = """
    The Dormouse's story
    
    

    The Dormouse's story

    Once upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well.

    ...

    """
    # 创建对象 selector = parsel.Selector(html_doc)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1、css 选择器

    # 解析数据,查找 a 标签
    print(selector.css('a').get())
    print(selector.css('a').getall())
    
    • 1
    • 2
    • 3

    2、xpath

    # xpath语法
    print(selector.xpath('//a[@class="sister"]/text()').get())
    print(selector.xpath('//a[@class="sister"]/text()').getall())
    print(selector.xpath('//a[@class="sister"]/@href').get())
    print(selector.xpath('//a[@class="sister"]/@href').getall())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、re

    注意:正常解析数据是可以的,但是 sub() 这个方法在这里不能用,如需调用方法,建议使用 import re。

    # re
    print(selector.re('.*?(.*?)'))  # 默认返回的数据类型是list
    
    • 1
    • 2

    七、案例

    目标网站:https://fabiaoqing.com/biaoqing/lists/page/1.html

    需求:翻页爬取图片链接、图片,并以图片名字保存。

    页面分析

    先爬取第一页数据

    确定 url:https://fabiaoqing.com/biaoqing/lists/page/1.html

    先获取整个页面的 img 标签

    遍历获取每一个属性值

    代码实现

    1、创建项目

    在这里插入图片描述

    2、编写代码

    在 settings.py 文件中修改一些参数。

    # settings.py
    # 不打印日志信息
    LOG_LEVEL = 'WARNING'
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = False
    # Override the default request headers:
    DEFAULT_REQUEST_HEADERS = {
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      'Accept-Language': 'en',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    修改 imgspider.py 文件中的网址,并打印网站源代码。

    # imgspider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    
    class ImgspiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'imgspider'
        # 允许爬取的域名
        allowed_domains = ['fabiaoqing.com']
        # 起始 url
        start_urls = ['https://fabiaoqing.com/biaoqing/lists/page/1.html']
    
        def parse(self, response):
            print(response.text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    新建一个 start.py 用来运行代码。

    # start.py
    # 使用 cmdline 模块来执行命令行命令
    from scrapy import cmdline
    
    # 使用 Scrapy 执行名为 spider 的爬虫
    cmdline.execute('scrapy crawl imgspider'.split())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    确定源码拿到后,开始解析数据。

    # imgspider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    import re  # 导入 re 模块,用于进行正则表达式匹配
    from Img_Download.items import ImgDownloadItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    class ImgspiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'imgspider'
        # 允许爬取的域名
        # allowed_domains = ['fabiaoqing.com']
        # 起始 url
        start_urls = ['https://fabiaoqing.com/biaoqing/lists/page/1.html']
    
        def parse(self, response):
            # 解析数据,找所有的 img 标签
            images = response.xpath('//img[@class="ui image lazy"]')
            # 遍历获取每一个 img 标签,解析里面的图片 url 以及标题
            for img in images:
                # 图片 url
                img_url = img.xpath('@data-original').get()
                # 标题
                title = img.xpath('@title').get()
                # 正则表达式替换标题特殊字符
                title = re.sub(r'[?/\\<>*:(), ]', '', title)
                # 打印图片 url 和标题,验证内容是否获取到
                # print(img_url, title)
                # break
                # 对获取到的图片 url,再次构造请求,cb_kwargs 传递参数
                yield scrapy.Request(img_url, callback=self.save_img, cb_kwargs={'title': title})
    
        # 重新创建一个方法,获取图片二进制的内容
        def save_img(self, response, **title):
            # 写入到文件,保存
            item = ImgDownloadItem()
            # 图片 url,在框架获取二进制内容用.body
            item['content'] = response.body
            # 标题
            item['title'] = title['title']
            yield item
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在 items.py 文件里创建项目的相关数据结构。

    # items.py
    import scrapy # 导入Scrapy库,用于构建爬虫
    
    # 自定义的Item类,用于存储爬取的数据
    class ImgDownloadItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        
        # 标题
        title = scrapy.Field()
        # 图片内容
        content = scrapy.Field()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在 pipelines.py 文件里保存数据。

    # pipelines.py
    # 自定义的管道类
    class ImgDownloadPipeline:
        # 处理 Item 的方法,负责将数据存储到文件中
        def process_item(self, item, spider):
            # 保存数据
            with open(f'images/{item["title"]}.jpg', 'wb') as f:
                # 写入数据
                f.write(item['content'])
            # 打印信息
            print(f'{item["title"]}下载成功')
            # 返回 item,继续后续的处理过程
            return item
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在 settings.py 文件里找到以下代码,取消注释,开启使用管道。

    # settings.py
    # Configure item pipelines
    # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    ITEM_PIPELINES = {
       'Img_Download.pipelines.ImgDownloadPipeline': 300,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    提前在文件夹里创建 images 文件夹,运行代码,获取第一页数据。

    第一页数据获取到后,进行翻页获取数据。

    分析翻页 url

    第一页:https://fabiaoqing.com/biaoqing/lists/page/1.html

    第二页:https://fabiaoqing.com/biaoqing/lists/page/2.html

    第三页:https://fabiaoqing.com/biaoqing/lists/page/3.html

    翻页获取数据

    # imgspider.py
    import scrapy  # 导入 Scrapy 库,用于构建爬虫
    import re  # 导入 re 模块,用于进行正则表达式匹配
    from Img_Download.items import ImgDownloadItem  # 导入自定义的 Item 类,用于存储爬取的数据
    
    class ImgspiderSpider(scrapy.Spider):
        # 爬虫的名称
        name = 'imgspider'
        # 允许爬取的域名
        # allowed_domains = ['fabiaoqing.com']
        # 链接 url
        base_url = 'https://fabiaoqing.com/biaoqing/lists/page/{}.html'
        # 页码
        page = 1
        # 起始 url
        start_urls = [base_url.format(page)]
    
        def parse(self, response):
            # 解析数据,找所有的 img 标签
            images = response.xpath('//img[@class="ui image lazy"]')
            # 遍历获取每一个 img 标签,解析里面的图片 url 以及标题
            for img in images:
                # 图片 url
                img_url = img.xpath('@data-original').get()
                # 标题
                title = img.xpath('@title').get()
                # 正则表达式替换标题特殊字符
                title = re.sub(r'[?/\\<>*:(), ]', '', title)
                # 打印图片 url 和标题,验证内容是否获取到
                # print(img_url, title)
                # break
                # 对获取到的图片 url,再次构造请求,cb_kwargs 传递参数
                yield scrapy.Request(img_url, callback=self.save_img, cb_kwargs={'title': title})
    
            # 翻页
            if self.page <= 10:
                self.page += 1
                # 获取数据
                yield scrapy.Request(self.base_url.format(self.page), callback=self.parse)
    
        # 重新创建一个方法,获取图片二进制的内容
        def save_img(self, response, **title):
            # 写入到文件,保存
            item = ImgDownloadItem()
            # 图片 url,在框架获取二进制内容用.body
            item['content'] = response.body
            # 标题
            item['title'] = title['title']
            yield item
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    如果爬取的速度过快,会被服务器识别是一个程序,可以设置一下爬取的速度。

    在 settings.py 文件里找到以下代码,取消注释。

    # settings.py
    # Configure a delay for requests for the same website (default: 0)
    # See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
    # See also autothrottle settings and docs
    # 设置爬取时间
    DOWNLOAD_DELAY = 0.5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

  • 相关阅读:
    2023_Spark_实验十八:安装FinalShell
    Java设计模式-状态模式
    Docker—苹果Mac安装Docker的两种方式
    来自云仓酒庄品牌雷盛红酒分享为什么高海拔的酒价格更高?
    Android MVI架构的深入解析与对比
    深度学习之基于YoloV5安检仪危险品识别系统
    VR全景打造亮眼吸睛创意内容:三维模型、实景建模
    zephyr的启动流程
    注解在Java中有什么用?请给出示例
    Cute老师手摸手带你搞百度旋转验证码
  • 原文地址:https://blog.csdn.net/muyuhen/article/details/132982152