# Crawlab 网络爬虫管理

## 概述

Crawlab 是强大的 **网络爬虫管理平台（WCMP）**，它能够运行多种编程语言（包括 Python、Go、Node.js、Java、C#）或爬虫框架（包括 Scrapy、Colly、Selenium、Puppeteer）开发的网路爬虫。它能够用来运行、管理和监控网络爬虫，特别是对可溯性、可扩展性以及稳定性要求较高的生产环境。

### 基本组成

```mermaid
graph TD;
Spider -->|belongs to| Project;
Spider -->|has| Schedule;
Spider -->|runs| Task;
Schedule -->|triggers| Task;
Task -->|runs on| Node;
```

- Crawlab 中的基本单位是`Spider`，一个`Spider`代表一个爬虫项目

- 多个`Spider`可以组成一个`Project`，代表同类爬虫项目，`Spider`也可以单独运行

- `Spider`可以直接手动运行，生成一个`Task`，也可以创建`Schedule`，通过`Schedule`触发运行生成`Task`

- `Task`运行在`Node`上，一个`Node`代表一台服务器，`Node`由一台`Master`服务器和若干`Worker`服务器组成

- 通常任务仅需一台`Master`服务器即可，官方不建议在一台服务器上搭建多个`Node`

- 在一台服务器上搭建多个`Node`可以较为简单地实现多进程爬虫，对于爬虫任务比较多或者CPU密集型的任务可能会有作用


### 数据集成

#### Scrapy

在 `settings.py` 文件中，将 `crawlab.CrawlabPipeline` 添加到 `Item_PIPELINES` 中，可以自动存储爬取到的数据：

```python
ITEM_PIPELINES = {
    'crawlab.CrawlabPipeline': 300,
}
```

去`item.py`中新增一个`Item`，并且`yield item`即可。

#### Python

将爬取到的数据通过以下方式手动保存：

```python
from crawlab import save_item
save_item({'title': 'example', 'url': 'https://example.com'})
```

#### Selenium

selenium 中和 python 一样需要手动保存数据，此外还需要无头浏览器等设置以保证正常运行：

```python
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
```

### 数据库

目前 Crawlab 支持`MongoDB`、`MySQL`、`PostgreSQL`、`SQL Server`、`SQLite`、`CockroachDB`、`ElasticSearch`、`Kafka`等多种数据库。

对于`MongoDB`这种 NoSQL 的数据库，Crawlab 处理起来是非常简单的，直接使用上面所说的数据集成方法，无需手动创建数据库，就可以一步到位实现数据存储，并且可以实现数据的扩展，灵活性较好。但是，由于没有数据类型，实际进行数据分析时，会遇到一些问题。

所以就本人经验而言，对于结构化的数据，为了数据分析时更加轻松，还是尽可能使用关系型数据库会更好一些。使用关系型数据库需要提前构建数据表，Crawlab并不支持自动创建关系型数据表，并且类型推断结果也不准确。

![](https://img.papergate.top:5000/i/2025/01/6783ba16636c8.webp)

需要手动额外创建的字段有两个`_id`和`_tid`

- `_id`是主键，需要设置成**自增**，比如在 `MySQL` 中可以设置数据类型为`bigint`
- `_tid`是任务的 ID 号，相同 ID 号的数据表明是在同一次任务中添加的，数据值由 Crawlab 来添加，数据类型为字符串，对于是否为主键没有要求，比如在 `MySQL` 中可以设置数据类型为`varchar`

### 定时任务

定时任务采用 `Cron` 表达式来表示执行任务的周期：

```text
*    *    *   *    *  Command_to_execute
|    |    |    |   |       
|    |    |    |    Day of the Week ( 0 - 6 ) ( Sunday = 0 )
|    |    |    |
|    |    |    Month ( 1 - 12 )
|    |    |
|    |    Day of Month ( 1 - 31 )
|    |
|    Hour ( 0 - 23 )
|
Min ( 0 - 59 )
```

![](https://img.papergate.top:5000/i/2024/12/676c3f6085ee5.webp)

## Crawlab 运行 Scrapy 项目

### 创建项目

```shell
scrapy startproject PROJECT_NAME
cd PROJECT_NAME
scrapy genspider SPIDER_NAME URL
git init
curl -L -o .gitignore https://www.toptal.com/developers/gitignore/api/python,scrapy
touch README.md
git add .
git commit -m "Initial commit for Scrapy project"
git remote add origin http://git.papergate.top:5000/aphros/PROJECT_NAME.git
git push -u origin main
```

### 编写爬虫程序

这里通过一个官方示例进行说明：[快速教程](https://docs.crawlab.cn/zh/guide/basic-tutorial/)

打开 `scrapy_quotes/scrapy_quotes/spiders/quotes.py` 并将如下内容替换掉原文件内容。

```python
# scrapy_quotes/scrapy_quotes/spiders/quotes.py

# 导入 scrapy 库，这是一个用于编写网络爬虫的 Python 框架
import scrapy

# 定义一个名为 QuotesSpider 的爬虫类，继承自 scrapy.Spider 类
class QuotesSpider(scrapy.Spider):
    # 为爬虫指定一个名称，这个名称在 Scrapy 项目中是唯一的
    name = 'quotes'
    # 指定允许爬取的域名列表，这里只有一个域名 quotes.toscrape.com
    allowed_domains = ['quotes.toscrape.com']
    # 设置爬虫的起始 URL 列表，爬虫将从这些 URL 开始抓取数据
    start_urls = ['http://quotes.toscrape.com/']

    # 定义一个名为 parse 的方法，这是爬虫的主要处理逻辑
    def parse(self, response):
        # 使用 CSS 选择器选择页面中所有 div.quote 元素，并遍历这些元素
        for quote in response.css("div.quote"):
            # 生成一个包含名言警句、作者和标签信息的字典
            yield {
                # 提取名言警句文本
                'text': quote.css("span.text::text").extract_first(),
                # 提取作者姓名
                'author': quote.css("small.author::text").extract_first(),
                # 提取标签列表，然后使用 ','.join(...) 将标签列表连接成一个字符串
                'tags': ','.join(quote.css("div.tags > a.tag::text").extract())
            }

        # 使用 CSS 选择器选择下一页链接，并提取链接 URL
        next_page_url = response.css("li.next > a::attr(href)").extract_first()
        # 检查下一页链接是否存在
        if next_page_url is not None:
            # 如果下一页链接存在，创建一个新的 scrapy.Request 对象，并将其提交给 Scrapy 引擎，以便继续爬取下一页
            yield scrapy.Request(response.urljoin(next_page_url))

```

然后打开文件 `scrapy_quotes/scrapy_quotes/settings.py` 并将如下代码加入到文件最后。

```python
# 加入到 scrapy_quotes/scrapy_quotes/settings.py 最后
ITEM_PIPELINES = {
    'crawlab.CrawlabPipeline': 300,
}
```

### 创建 Crawlab 爬虫

`爬虫->新建爬虫`

![](https://img.papergate.top:5000/i/2024/12/676c2b51bf416.webp)

```shell
# 名称
CRAWLAB_SPIDER_NAME
# 执行命令
scrapy crawl SCRAPY_SPIDER_NAME
```

### 从 Git 拉取 Scrapy 项目

![](https://img.papergate.top:5000/i/2024/12/676c2c8946566.webp)

### 运行爬虫

![](https://img.papergate.top:5000/i/2024/12/676c2e71554e0.webp)

### 查看执行情况

爬取到的数据如下：

![](https://img.papergate.top:5000/i/2024/12/676c36e5e03b0.webp)

---

> 作者: Aphros  
> URL: https://blog.papergate.top/posts/crawlab-%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E7%AE%A1%E7%90%86/  

