admin 管理员组

文章数量: 887021

Scrapy架构

Scrapy 是一个用于 Python 的高级 Web 爬取框架,它被设计用来爬取网站并从页面中提取结构化的数据。Scrapy 的核心是一个异步处理引擎,基于 Twisted 这个事件驱动网络引擎构建而成。

主要组件
  • Scrapy Engine(Scrapy 引擎)

    • 负责处理所有的数据流,发送请求、返回响应以及调度数据到各个组件。
  • Scheduler(调度器)

    • 排队待处理的请求,并根据优先级将它们发送给引擎。
  • Downloader(下载器)

    • 负责处理所有实际的 HTTP 请求和响应。
  • Spider(爬虫)

    • 解析响应数据,提取数据(抓取项目),以及生成新的请求。
  • Item Pipeline(项目管道)

    • 处理爬取的数据,例如清洗、验证、存储等。
  • Middleware(中间件)

    • 处理 Scrapy 组件之间的钩子,允许用户修改或扩展 Scrapy 的行为。

创建项目和爬虫

创建项目
  1. 打开命令行工具。
  2. 使用 scrapy startproject <project_name> 命令创建一个新的 Scrapy 项目。
  3. 进入项目目录:cd <project_name>
创建爬虫
  1. 在项目目录下运行 scrapy genspider <name> <domain> 命令来创建一个爬虫。
    • <name> 是爬虫的名字。
    • <domain> 是你想要爬取的网站域名。
  2. 编辑 spiders/<name>.py 文件来定义爬虫的行为。
  3. 定义 start_requests 方法以启动爬虫。
  4. 实现 parse 方法来解析响应并提取数据。

数据管道和中间件

数据管道 (Item Pipeline)

数据管道是用来处理爬虫提取的 Item 对象的一系列组件。你可以定义多个管道来处理数据,比如清理数据、验证数据、存储数据等。

  1. settings.py 中启用管道。
  2. 定义一个类继承自 scrapy.pipelines.ItemPipeline
  3. 实现 process_item 方法,该方法接收 Item 和 Spider 并返回 Item 或抛出异常。
中间件 (Middleware)

中间件允许用户拦截 HTTP 请求和响应,可以用来处理各种需求,如添加 HTTP 头、处理 cookies、设置代理等。

  • Downloader Middlewares

    • 这些中间件位于下载器与 Scrapy 引擎之间,可以修改请求和响应。
    • 需要在 settings.py 中配置中间件列表 DOWNLOADER_MIDDLEWARES
  • Spider Middlewares

    • 这些中间件位于爬虫与 Scrapy 引擎之间,可以过滤响应和提取的 Item。
    • 配置在 settings.py 中通过 SPIDER_MIDDLEWARES 字典。

这些是 Scrapy 框架的核心概念和使用方法。你可以根据具体需求进行定制和扩展。如果你需要更详细的代码示例或者有其他具体问题,请告诉我!

下面我将展示如何创建一个简单的 Scrapy 项目,并编写一个爬虫来抓取一个网站上的数据。同时,我会介绍如何定义数据管道和中间件。

首先,确保你已经安装了 Scrapy。如果还没有安装,可以通过 pip 安装 Scrapy:

pip install scrapy

然后,按照以下步骤创建项目和爬虫:

创建 Scrapy 项目

打开终端或命令提示符,执行以下命令来创建一个新的 Scrapy 项目:

scrapy startproject myproject
cd myproject

这将在当前目录下创建一个名为 myproject 的文件夹,其中包含了项目的基本结构。

创建爬虫

接下来,我们将创建一个爬虫来抓取一个假设的博客站点 example 上的文章标题和链接。

在项目目录中,执行以下命令创建爬虫:

scrapy genspider example example

这将创建一个名为 example.py 的文件在 myproject/spiders 目录下。打开这个文件并编辑它:

# myproject/spiders/example.py

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    allowed_domains = ['example']
    start_urls = ['http://example']

    def parse(self, response):
        # 提取文章标题和链接
        for article in response.css('div.article'):
            yield {
                'title': article.css('h2.title::text').get(),
                'link': article.css('a::attr(href)').get(),
            }

        # 提取下一页的链接
        next_page = response.css('div.pagination a.next::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

定义数据管道

为了保存爬取到的数据,我们需要定义一个数据管道。在 myproject/pipelines.py 文件中定义一个简单的数据管道:

# myproject/pipelines.py

import json

class MyprojectPipeline:
    def open_spider(self, spider):
        self.file = open('items.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

接下来,在 settings.py 文件中激活这个管道:

# myproject/settings.py

ITEM_PIPELINES = {
    'myproject.pipelines.MyprojectPipeline': 300,
}

定义中间件

我们可以定义一个中间件来处理请求头。在 myproject/middlewares.py 文件中定义一个简单的中间件:

# myproject/middlewares.py

class CustomUserAgentMiddleware:
    def process_request(self, request, spider):
        request.headers['User-Agent'] = 'MyCustomUserAgent'

然后在 settings.py 中激活这个中间件:

# myproject/settings.py

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomUserAgentMiddleware': 543,
}

运行爬虫

现在,我们可以通过以下命令来运行爬虫:

scrapy crawl example

这将开始爬取 example 网站,并将数据保存到 items.json 文件中。

以上就是创建一个简单的 Scrapy 项目、爬虫、数据管道和中间件的基本过程。你可以根据需要对这些代码进行修改和扩展。如果有任何疑问或需要进一步的帮助,请随时告诉我!

让我们继续扩展代码,以便更好地理解 Scrapy 的工作原理。我们将添加错误处理、日志记录、更复杂的管道功能以及更多的中间件功能。

错误处理

在爬虫中,我们应该处理可能发生的错误,比如网页找不到的情况。我们可以为 parse 方法添加异常处理逻辑:

# myproject/spiders/example.py

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    allowed_domains = ['example']
    start_urls = ['http://example']

    def parse(self, response):
        if response.status != 200:
            self.logger.error(f"Failed to load page {response.url}, status code: {response.status}")
            return
        
        # 提取文章标题和链接
        for article in response.css('div.article'):
            yield {
                'title': article.css('h2.title::text').get(),
                'link': article.css('a::attr(href)').get(),
            }

        # 提取下一页的链接
        next_page = response.css('div.pagination a.next::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

更复杂的管道

让我们在管道中增加一些额外的功能,比如检查是否有重复的项,并且添加一些基本的日志记录。

# myproject/pipelines.py

import json
import logging

class MyprojectPipeline:
    def __init__(self):
        self.seen_urls = set()
        self.file = None

    def open_spider(self, spider):
        self.file = open('items.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        url = item.get('link')
        if url and url not in self.seen_urls:
            self.seen_urls.add(url)
            line = json.dumps(dict(item)) + "\n"
            self.file.write(line)
            logging.info(f"Processed item: {item}")
            return item
        else:
            logging.warning(f"Duplicated link found: {url}")
            return item

更多的中间件功能

我们可以在中间件中添加一些额外的功能,比如随机选择 User-Agent 或者处理重试机制。

# myproject/middlewares.py

from scrapy import signals
import random

class CustomUserAgentMiddleware:
    USER_AGENTS = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0",
    ]

    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(self.USER_AGENTS)

    def process_response(self, request, response, spider):
        if response.status == 404:
            self.logger.error(f"Received 404 for URL: {request.url}")
            # 可以在此处实现重试机制
            return request
        return response

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

运行爬虫

最后,再次运行爬虫以测试新添加的功能:

scrapy crawl example

这些更改增加了错误处理、日志记录、去重功能和更复杂的中间件功能。这应该能够帮助你更好地理解和应用 Scrapy 的各个组件。如果你还有其他具体的需求或者想了解更多的细节,请告诉我!

本文标签: 爬虫 框架 技术 python scrapy