【Python】 Scrapy 爬虫:如何设置深度优先与广度优先采集策略

14 篇文章 0 订阅

我听见有人猜
你是敌人潜伏的内线
和你相知多年
我确信对你的了解
你舍命救我画面
一一在眼前浮现
司空见惯了鲜血
你忘记你本是娇娆的红颜
感觉你我彼此都那么依恋
                     🎵 许嵩《内线》


在 Web 爬虫中,深度优先搜索(DFS) 和 广度优先搜索(BFS) 是常见的网页采集策略。不同的策略适用于不同的爬取场景,例如,当我们想更快地抓取某个页面的所有关联内容时,广度优先可能更合适;而深度优先则更适合用于逐层深入网站结构,抓取嵌套得较深的网页内容。

在 Scrapy 框架中,默认的爬取方式是广度优先(BFS),但 Scrapy 也支持通过设置参数来切换到深度优先(DFS)爬取。本篇博客将详细介绍如何在 Scrapy 中设置深度优先和广度优先策略。

1. 什么是深度优先和广度优先?

广度优先(BFS):广度优先算法从起始点开始,优先访问与其直接相连的所有节点,然后再访问这些节点的相邻节点,依次展开。广度优先的特点是“先横向再纵向”,即会优先遍历当前层的所有页面,再继续遍历下一层。

深度优先(DFS):深度优先算法则是优先访问当前节点的子节点,然后依次深入。深度优先的特点是“先纵向再横向”,即会一直深入遍历下一级页面,直到达到某个终点才返回遍历下一个节点。

示例对比:
广度优先:Level 1 -> Level 2 -> Level 3 -> …
深度优先:Level 1 -> Level 1.1 -> Level 1.1.1 -> …

2. Scrapy 默认的采集策略

Scrapy 默认使用广度优先搜索(BFS)来进行页面爬取。这意味着它会从起始页面开始,依次抓取该页面上的所有链接,然后再逐层抓取下一层的页面。

在 Scrapy 中,这种采集策略是通过请求队列的管理实现的。Scrapy 使用一个优先级队列来存储要抓取的请求,而默认情况下,新发现的请求会被添加到队列的尾部,从而实现广度优先采集。

3. 切换到深度优先采集

为了在 Scrapy 中使用深度优先搜索(DFS),我们需要调整请求的优先级策略。通过为新的请求设置较高的优先级,Scrapy 会优先处理新发现的请求,从而达到深度优先的效果。

Scrapy 提供了 DEPTH_PRIORITY 和 SCHEDULER_DISK_QUEUE 设置来实现这一点。

3.1 修改 Scrapy 配置为深度优先

我们可以通过修改 Scrapy 项目的配置文件 settings.py 来设置深度优先采集:

# settings.py

# 设置为深度优先
DEPTH_PRIORITY = 1

# 优先从队列顶部抓取请求(即从深层先抓)
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'

在这里:

DEPTH_PRIORITY = 1:设置深度优先采集策略,优先处理新发现的请求。
SCHEDULER_DISK_QUEUE 和 SCHEDULER_MEMORY_QUEUE 分别指定了磁盘队列和内存队列的处理方式。Fifo 表示 “First In, First Out”(先进先出),用以保证新请求先被处理,从而达到深度优先效果。

3.2 控制爬取深度

Scrapy 还提供了一个配置项 DEPTH_LIMIT 来限制爬取的最大深度。如果你想控制爬虫不爬得太深,可以设置这个参数。例如,限制爬虫最多爬取 3 层深度:

# 限制爬取深度为3
DEPTH_LIMIT = 3

当设置了 DEPTH_LIMIT 后,Scrapy 在到达指定深度后将不会继续抓取更深的页面。

4. 切换回广度优先采集

如果你想使用广度优先采集(BFS),实际上 Scrapy 默认就是使用这种策略。因此,回到默认的配置即可。

4.1 恢复广度优先的配置

广度优先采集的配置如下:

# settings.py

# 设置为广度优先
DEPTH_PRIORITY = -1

# 优先从队列尾部抓取请求(即从表层抓取)
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleLifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.LifoMemoryQueue'

在这里:

DEPTH_PRIORITY = -1:设置广度优先采集策略,优先处理先加入队列的请求。
SCHEDULER_DISK_QUEUE 和 SCHEDULER_MEMORY_QUEUE 分别指定了磁盘队列和内存队列的处理方式。Lifo 表示 “Last In, First Out”(后进先出),用以保证先发现的页面优先被处理。

5. 自定义请求优先级

除了全局的深度优先和广度优先配置外,Scrapy 还允许我们通过 Request 对象手动控制单个请求的优先级。

5.1 为请求设置优先级

在 Scrapy 中,priority 参数可以用于控制每个请求的优先级。优先级高的请求会被优先处理。默认情况下,所有请求的优先级都是 0。我们可以通过修改这个值来改变请求的处理顺序。

示例:手动控制某些请求的优先级,使其优先处理:

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        urls = [
            'https://example.com/level1',
            'https://example.com/level2'
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse, priority=10)

    def parse(self, response):
        # 对子页面设置更高的优先级
        for href in response.css('a::attr(href)').getall():
            yield scrapy.Request(url=response.urljoin(href), callback=self.parse, priority=20)

在这个示例中,起始页面的优先级设置为 10,而子页面的优先级设置为 20,子页面会被优先处理。

6. 完整示例:深度优先 vs 广度优先

以下是一个完整的示例,演示如何在 Scrapy 中通过设置来实现深度优先和广度优先爬取。

6.1 深度优先示例
# 深度优先爬虫配置 settings.py

DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
DEPTH_LIMIT = 3  # 限制爬取深度为3
6.2 广度优先示例
# 广度优先爬虫配置 settings.py

DEPTH_PRIORITY = -1
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleLifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.LifoMemoryQueue'
6.3 爬虫代码
import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'
    start_urls = ['https://example.com']

    def parse(self, response):
        self.log(f"正在爬取:{response.url}")
        for href in response.css('a::attr(href)').getall():
            yield scrapy.Request(url=response.urljoin(href), callback=self.parse)

7. 总结

通过调整 Scrapy 的配置,我们可以灵活地在 深度优先 和 广度优先 爬取策略之间切换。深度优先适合深入探索网页的层次结构,而广度优先适合快速覆盖网站的广泛区域。

要实现深度优先,只需设置 DEPTH_PRIORITY = 1 并使用 Fifo 队列来优先处理新发现的请求;而广度优先可以通过默认配置或设置 DEPTH_PRIORITY = -1 并使用 Lifo 队列来实现。此外,通过 priority 参数,你还可以自定义不同请求的优先级,控制它们的处理顺序。

根据实际业务需求选择合适的爬取策略,可以让你的 Scrapy 爬虫更加高效、灵活地完成数据抓取任务。

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值