Crawlab 网络爬虫管理

第 1 节 概述

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

1.1 基本组成

graph TD;
Spider -->|belongs to| Project;
Spider -->|has| Schedule;
Spider -->|runs| Task;
Schedule -->|triggers| Task;
Task -->|runs on| Node;
graph TD;
Spider -->|belongs to| Project;
Spider -->|has| Schedule;
Spider -->|runs| Task;
Schedule -->|triggers| Task;
Task -->|runs on| Node;
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密集型的任务可能会有作用

1.2 数据集成

Scrapy

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

1
2
3
ITEM_PIPELINES = {
    'crawlab.CrawlabPipeline': 300,
}

item.py中新增一个Item,并且yield item即可。

Python

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

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

Selenium

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

1
2
3
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')

1.3 数据库

目前 Crawlab 支持MongoDBMySQLPostgreSQLSQL ServerSQLiteCockroachDBElasticSearchKafka等多种数据库。

对于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

1.4 定时任务

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
*    *    *   *    *  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

第 2 节 Crawlab 运行 Scrapy 项目

2.1 创建项目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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

2.2 编写爬虫程序

这里通过一个官方示例进行说明:快速教程

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

 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
# 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 并将如下代码加入到文件最后。

1
2
3
4
# 加入到 scrapy_quotes/scrapy_quotes/settings.py 最后
ITEM_PIPELINES = {
    'crawlab.CrawlabPipeline': 300,
}

2.3 创建 Crawlab 爬虫

爬虫->新建爬虫

https://img.papergate.top:5000/i/2024/12/676c2b51bf416.webp

1
2
3
4
# 名称
CRAWLAB_SPIDER_NAME
# 执行命令
scrapy crawl SCRAPY_SPIDER_NAME

2.4 从 Git 拉取 Scrapy 项目

https://img.papergate.top:5000/i/2024/12/676c2c8946566.webp

2.5 运行爬虫

https://img.papergate.top:5000/i/2024/12/676c2e71554e0.webp

2.6 查看执行情况

爬取到的数据如下:

https://img.papergate.top:5000/i/2024/12/676c36e5e03b0.webp