程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

  • Python 进阶

  • Python爬虫

    • requests 库 - HTTP for Humans
    • Beautiful Soup - HTML解析利器
    • Selenium - 动态网页抓取神器
    • Scrapy - 工业级爬虫框架
      • 1. Scrapy 核心架构
      • 2. 安装 Scrapy
      • 3. 创建你的第一个 Scrapy 项目
      • 4. 定义要抓取的数据 (items.py)
      • 5. 编写爬虫 (Spider)
      • 6. 运行爬虫并保存数据
      • 7. 实现翻页 (生成新的请求)
      • 8. 使用 Item Pipeline 处理数据
  • Scrapy 爬虫框架

  • Python
  • Python爬虫
scholar
2025-07-22
目录

Scrapy - 工业级爬虫框架

# Scrapy - 工业级爬虫框架

当我们从简单的脚本小子成长为专业的爬虫工程师时,就需要一个更强大、更规范的工具来应对大规模、高效率的爬取任务。Scrapy 就是 Python 世界中当之无愧的王者级爬虫框架。

Scrapy 是一个为了爬取网站数据、提取结构性数据而编写的应用程序框架。它内置了异步处理机制,拥有高效的并发性能,并提供了一整套完整的架构,包括请求调度、数据处理管道、中间件等,极大地提升了开发效率和爬虫性能。


# 1. Scrapy 核心架构

理解 Scrapy 的数据流和组件是掌握它的关键。

Scrapy Architecture

  • 引擎 (Engine): 整个框架的核心,负责控制所有组件之间的数据流,并在特定事件发生时触发相应的动作。
  • 调度器 (Scheduler): 接收引擎发来的请求 (Request),将它们放入一个队列中,并在引擎请求时提供下一个要抓取的 URL。
  • 下载器 (Downloader): 负责获取页面数据。它接收引擎发来的请求,执行下载,然后将响应 (Response) 返回给引擎。
  • 爬虫 (Spiders): 这是我们编写主要逻辑的地方。它负责创建初始请求,并根据服务器的响应解析数据、提取出我们需要的条目 (Item),以及生成新的请求。
  • 项目管道 (Item Pipeline): 负责处理由 Spider 提取出的 Item。典型的应用场景包括数据清洗、验证和持久化(如存入数据库)。
  • 中间件 (Middlewares): 位于引擎和各个组件之间的钩子,可以自定义修改 Scrapy 的请求和响应。例如,设置随机 User-Agent、使用代理 IP 等。

# 2. 安装 Scrapy

通过 pip 可以轻松安装 Scrapy。

pip install scrapy
1

# 3. 创建你的第一个 Scrapy 项目

Scrapy 提供了命令行工具来快速生成项目骨架。

  1. 打开你的终端,进入你想要创建项目的目录。

  2. 执行 startproject 命令:

    scrapy startproject my_first_scraper
    
    1

    这个命令会创建一个名为 my_first_scraper 的文件夹,其内部结构如下:

    my_first_scraper/
    ├── scrapy.cfg            # 项目的配置文件
    └── my_first_scraper/
        ├── __init__.py
        ├── items.py          # 定义要抓取的数据结构 (Item)
        ├── middlewares.py    # 中间件
        ├── pipelines.py      # 项目管道
        ├── settings.py       # 项目的全局设置
        └── spiders/          # 存放所有爬虫 (Spider) 的目录
            └── __init__.py
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# 4. 定义要抓取的数据 (items.py)

在 items.py 文件中,我们通过定义一个 scrapy.Item 的子类,来声明我们需要从网页中提取哪些字段。这就像是为你的数据创建了一个结构化的模板。

例如,我们要爬取名言警句网站,需要提取“内容”、“作者”和“标签”。

# my_first_scraper/items.py

import scrapy

class QuoteItem(scrapy.Item):
    # 使用 scrapy.Field() 来定义每一个你想要抓取的字段
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()
1
2
3
4
5
6
7
8
9

# 5. 编写爬虫 (Spider)

爬虫是 Scrapy 的核心,是我们定义爬取逻辑的地方。

  1. 在终端中,进入项目的主目录 (包含 scrapy.cfg 的那层)。

  2. 使用 genspider 命令创建一个新的爬虫:

    # scrapy genspider <爬虫名字> <允许爬取的域名>
    scrapy genspider quotes quotes.toscrape.com
    
    1
    2

    这会在 spiders 目录下创建一个 quotes.py 文件。

  3. 编辑 quotes.py 文件:

    # my_first_scraper/spiders/quotes.py
    
    import scrapy
    from ..items import QuoteItem # 从 items.py 导入我们定义的 QuoteItem
    
    class QuotesSpider(scrapy.Spider):
        # 爬虫的唯一标识名,在项目中不能重复
        name = 'quotes'
        
        # (可选) 允许爬虫爬取的域名列表。如果请求的 URL 不在此列表中,将被忽略。
        allowed_domains = ['quotes.toscrape.com']
        
        # 爬虫启动时请求的第一个 URL 列表
        start_urls = ['http://quotes.toscrape.com/']
    
        def parse(self, response):
            """
            这是 Scrapy 默认的回调方法。
            当 start_urls 中的请求完成后,下载器返回的响应 (Response) 会作为参数传递给这个方法。
            这个方法的核心任务是:
            1. 解析响应内容,提取数据。
            2. 找到新的链接,并生成新的请求。
            """
            
            # response 对象内置了强大的选择器 (CSS 和 XPath)
            # 我们使用 CSS 选择器来定位所有包含名言的 div 标签
            all_quotes = response.css('div.quote')
    
            # 遍历所有找到的名言 div
            for quote in all_quotes:
                # 创建一个我们之前定义的 Item 实例
                item = QuoteItem()
    
                # 使用选择器提取数据,并存入 item 对应的字段
                # .css('span.text::text') 表示选择 class="text" 的 span 标签,并提取其文本内容
                # .get() 获取第一个匹配项,如果没有则返回 None
                item['text'] = quote.css('span.text::text').get()
                
                # .css('small.author::text').get() 提取作者
                item['author'] = quote.css('small.author::text').get()
                
                # .css('div.tags a.tag::text') 提取所有标签
                # .getall() 获取所有匹配项,返回一个列表
                item['tags'] = quote.css('div.tags a.tag::text').getall()
                
                # 使用 yield 将填充好的 item 交给 Scrapy 引擎,引擎会将其送入 Pipeline 处理
                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

# 6. 运行爬虫并保存数据

回到终端,确保你还在项目的根目录下。

# scrapy crawl <爬虫名字>
scrapy crawl quotes
1
2

你会在终端看到大量的日志输出,包括你提取出的数据。

如果想将数据保存到文件,Scrapy 提供了极其方便的 Feed Exports 功能,无需编写任何代码。

# 保存为 JSON 文件 (-o 表示输出文件)
scrapy crawl quotes -o quotes.json

# 保存为 CSV 文件
scrapy crawl quotes -o quotes.csv

# 保存为 XML 文件
scrapy crawl quotes -o quotes.xml
1
2
3
4
5
6
7
8

# 7. 实现翻页 (生成新的请求)

目前我们的爬虫只能抓取第一页。要实现自动翻页,我们需要在 parse 方法中找到“下一页”的链接,并生成一个新的 scrapy.Request。

修改 parse 方法:

# my_first_scraper/spiders/quotes.py

# ... (前面的代码不变) ...

class QuotesSpider(scrapy.Spider):
    # ... (name, allowed_domains, start_urls 不变) ...
    
    def parse(self, response):
        # ... (提取当前页数据的 for 循环不变) ...
        for quote in response.css('div.quote'):
            # ... (yield item 的代码不变) ...
            yield { # 也可以直接 yield 字典
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
            }

        # --- 新增翻页逻辑 ---
        
        # 1. 使用 CSS 选择器找到“下一页”的 a 标签
        next_page_link = response.css('li.next a::attr(href)').get()
        
        # 2. 检查是否找到了链接
        if next_page_link is not None:
            # 3. response.follow() 是一个快捷方式,用于创建对相对 URL 的请求。
            #    它会自动处理拼接完整 URL 的工作。
            #    我们指定 callback=self.parse,意味着当这个新请求完成后,
            #    其响应会再次由 parse 方法来处理,从而形成一个循环。
            yield response.follow(next_page_link, 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

现在再次运行 scrapy crawl quotes,你会发现它会自动一页一页地抓取下去,直到最后一页。


# 8. 使用 Item Pipeline 处理数据

虽然 -o 参数很方便,但对于复杂的数据处理(如去重、存入数据库),我们需要使用 Item Pipeline。

一个 Pipeline 就是一个 Python 类,它必须实现一个 process_item(self, item, spider) 方法。

让我们来写一个简单的 Pipeline,它会打印出作者和内容。

  1. 编辑 pipelines.py 文件:

    # my_first_scraper/pipelines.py
    
    class MyFirstScraperPipeline:
        def process_item(self, item, spider):
            # item 就是爬虫 yield 出来的对象
            # spider 就是产生这个 item 的爬虫实例
            print("="*20 + " [Pipeline] " + "="*20)
            print(f"作者: {item['author']}")
            print(f"内容: {item['text']}")
            print("="*52)
            
            # 必须返回 item,这样后续的 Pipeline (如果有的话) 才能继续处理
            return item
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  2. 在 settings.py 中启用 Pipeline: 找到 ITEM_PIPELINES 设置,取消它的注释,并设置一个 1-1000 的优先级(数字越小,越先执行)。

    # my_first_scraper/settings.py
    
    # ...
    ITEM_PIPELINES = {
       'my_first_scraper.pipelines.MyFirstScraperPipeline': 300,
    }
    # ...
    
    1
    2
    3
    4
    5
    6
    7

现在再次运行 scrapy crawl quotes,你不仅会看到 Scrapy 的日志,还会看到我们 Pipeline 打印出的格式化信息。在这里,你可以加入连接数据库、写入文件的代码,实现任何你想要的数据持久化逻辑。

掌握了 Scrapy,你就从一个“爬虫工匠”迈向了“爬虫架构师”。虽然入门曲线比 requests 陡峭,但它带来的工程化、高性能和高扩展性是无与伦比的。

编辑此页 (opens new window)
上次更新: 2025/07/27, 04:30:11
Selenium - 动态网页抓取神器
Scrapy 框架核心:深入理解其工作流程

← Selenium - 动态网页抓取神器 Scrapy 框架核心:深入理解其工作流程→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式