apify-generate-output-schema

apify-generate-output-schema

熱門

透過分析 Apify Actor 的原始碼,為其生成輸出 Schema(dataset_schema.json、output_schema.json、key_value_store_schema.json)。適合在建立或更新 Actor 輸出 Schema 時使用。

2231星標
244分支
更新於 2026/6/25
SKILL.md
唯讀
名稱
apify-generate-output-schema
描述

透過分析 Apify Actor 的原始碼,為其生成輸出 Schema(dataset_schema.json、output_schema.json、key_value_store_schema.json)。適合在建立或更新 Actor 輸出 Schema 時使用。

生成 Actor 輸出 Schema

您正在為 Apify Actor 生成輸出 Schema 檔案。輸出 Schema 會告知 Apify Console 如何顯示執行結果。您將分析 Actor 的原始碼,建立 dataset_schema.jsonoutput_schema.jsonkey_value_store_schema.json(若 Actor 有使用 Key-Value Store),並更新 actor.json

核心原則

  • 先分析程式碼:閱讀 Actor 的原始碼以瞭解它實際上推送到 Dataset 的資料——絕不盲目猜測
  • 所有欄位皆可為 null:API 與網站具有不可預測性——務必設定 "nullable": true
  • 範例資料去識別化:切勿在範例中使用真實的使用者 ID、使用者名稱或個人資料
  • 對照程式碼驗證:若存在 TypeScript 型別,請同時對照型別定義與產生該值的程式碼來核對 Schema
  • 複用既有模式:在生成 Schema 之前,先檢查同一儲存庫中的其他 Actor 是否已有輸出 Schema——維持相同的結構、命名慣例、描述風格與格式
  • 避免重複造輪子:複用程式碼庫中既有的型別定義、介面與工具函式,而非建立重複的定義

階段 1:探索 Actor 結構

目標:定位 Actor 並瞭解其輸出內容

初始請求:$ARGUMENTS

動作

  1. 建立包含所有階段的工作清單(todo list)
  2. 找到包含 actor.json.actor/ 目錄
  3. 閱讀 actor.json 以瞭解 Actor 的設定
  4. 檢查 dataset_schema.jsonoutput_schema.jsonkey_value_store_schema.json 是否已存在
  5. 在儲存庫中搜尋既有的 Schema:尋找其他 .actor/ 目錄或 Schema 檔案(例如 **/dataset_schema.json**/output_schema.json**/key_value_store_schema.json),學習該專案的慣例——維持相同的描述風格、欄位命名、範例格式與整體結構
  6. 找出所有將資料推送到 Dataset 的位置:
    • JavaScript/TypeScript:搜尋 Actor.pushData(dataset.pushData(Dataset.pushData(
    • Python:搜尋 Actor.push_data(dataset.push_data(Dataset.push_data(
  7. 找出所有將資料儲存至 Key-Value Store 的位置:
    • JavaScript/TypeScript:搜尋 Actor.setValue(keyValueStore.setValue(KeyValueStore.setValue(
    • Python:搜尋 Actor.set_value(key_value_store.set_value(KeyValueStore.set_value(
  8. 找出輸出型別定義——直接複用而非重新建立:
    • TypeScript:尋找輸出型別介面/型別(例如在 src/types/src/types/output.ts 中)。若介面或型別已定義輸出結構,直接從中推導 Schema 欄位——不要建立平行重複的定義
    • Python:尋找 TypedDict、dataclass 或 Pydantic 模型定義。使用既有的欄位名稱、型別與 docstring 作為權威資料來源
  9. 檢查程式碼庫中是否有處理 Schema 生成或驗證的既有共用 Schema 工具或輔助函式——進行複用而非撰寫新邏輯
  10. actor.json 中存在行內的 storages.datasetstorages.keyValueStore 設定,請標記以供後續遷移

向使用者呈現探索結果:列出所有發現的 Dataset 輸出欄位、Key-Value Store 鍵值、其型別以及來源位置。


階段 2:生成 dataset_schema.json

目標:建立包含欄位定義與顯示檢視(views)的完整 Dataset Schema

檔案結構

{
    "actorSpecification": 1,
    "fields": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "properties": {
            // 此處包含所有輸出欄位——即 Actor 可能產生的每一個欄位,
            // 不僅限於概覽(overview)檢視中顯示的欄位
        },
        "required": [],
        "additionalProperties": true
    },
    "views": {
        "overview": {
            "title": "Overview",
            "description": "Most important fields at a glance",
            "transformation": {
                "fields": [
                    // 8-12 個最重要的欄位名稱
                ]
            },
            "display": {
                "component": "table",
                "properties": {
                    // 每個概覽欄位的顯示設定
                }
            }
        }
    }
}

與既有 Schema 保持一致

如果在階段 1(步驟 5)中於儲存庫內找到了既有的輸出 Schema,請遵循其慣例:

  • 符合 描述撰寫風格(句首大寫 vs. 全小寫、結尾加句號 vs. 不加句號等)
  • 符合 欄位命名慣例(camelCase vs. snake_case)——這也必須與 Actor 程式碼實際產生的鍵值一致
  • 符合 範例值風格(例如日期格式、URL 模式、預留位置名稱)
  • 符合 檢視結構(概覽中的欄位數量、顯示格式選擇)
  • 符合 JSON 格式化(縮排、屬性排序、空格)——同一儲存庫中的所有 Schema 必須使用完全相同的格式,包含獨立的 Actor

當 Actor 程式碼已有定義良好的 TypeScript 介面或 Python 型別類別時,直接從這些型別推導欄位,而不是重新從頭分析 pushData/push_data 呼叫。型別定義即為權威來源。

硬性規則(無例外)

規則 細節
所有欄位皆需放入 properties fields.properties 物件必須包含 Actor 可能輸出的所有欄位,不僅限於概覽檢視中顯示的欄位。views 區段僅選取子集供顯示——properties 區段必須是完整的全集
"nullable": true 設定在每一個欄位上——API 具有不可預測性
"additionalProperties": true 設定在最外層的 fields 物件以及 properties 內部的每一個巢狀物件。這是最容易遺漏的規則——兩個層級都必須具備
"required": [] 恆為空陣列——設定在最外層的 fields 物件以及 properties 內部的每一個巢狀物件
範例值去識別化 不可包含真實的使用者 ID、使用者名稱或內容
"type" 需搭配 "nullable" 若未在同一欄位指定 type,AJV 會拒絕 nullable

警告——最常見的錯誤

  1. 僅包含顯示在概覽檢視中的欄位。即使未出現在 views 區段中,fields.properties 也必須列出所有輸出欄位。
  2. 僅在巢狀物件型別的屬性中添加 "required": []"additionalProperties": true,卻忘記在最外層的 fields 物件上添加。兩個層級都需要。

附註nullable 是 JSON Schema draft-07 的 Apify 特定擴充。這是刻意設計且正確的。

欄位型別模式

字串欄位:

"title": {
    "type": "string",
    "description": "Title of the scraped item",
    "nullable": true,
    "example": "Example Item Title"
}

數字欄位:

"viewCount": {
    "type": "number",
    "description": "Number of views",
    "nullable": true,
    "example": 15000
}

布林值欄位:

"isVerified": {
    "type": "boolean",
    "description": "Whether the account is verified",
    "nullable": true,
    "example": true
}

陣列欄位:

"hashtags": {
    "type": "array",
    "description": "Hashtags associated with the item",
    "items": { "type": "string" },
    "nullable": true,
    "example": ["#example", "#demo"]
}

巢狀物件欄位:

"authorInfo": {
    "type": "object",
    "description": "Information about the author",
    "properties": {
        "name": { "type": "string", "nullable": true },
        "url": { "type": "string", "nullable": true }
    },
    "required": [],
    "additionalProperties": true,
    "nullable": true,
    "example": { "name": "Example Author", "url": "https://example.com/author" }
}

列舉(Enum)欄位:

"contentType": {
    "type": "string",
    "description": "Type of content",
    "enum": ["article", "video", "image"],
    "nullable": true,
    "example": "article"
}

聯合型別(例如 TypeScript ObjectType | string):

"metadata": {
    "type": ["object", "string"],
    "description": "Structured metadata object, or error string if unavailable",
    "nullable": true,
    "example": { "key": "value" }
}

去識別化的範例值

使用逼真但通用的數值。遵循平台的 ID 格式慣例:

欄位型別 範例處理方式
ID 符合平台的格式與長度(例如 YouTube 影片 ID 為 11 個字元)
使用者名稱 "exampleuser", "sampleuser123"
顯示名稱 "Example Channel", "Sample Author"
URL 使用平台的標準 URL 格式並搭配虛構的 ID
日期 "2025-01-15T12:00:00.000Z"(ISO 8601)
文字內容 通用的描述性文字,例如 "This is an example description."

檢視(Views)區段

  • transformation.fields:列出 8–12 個最重要的欄位名稱(順序 = UI 中的欄位順序)
  • display.properties:概覽欄位中每個項目對應一筆設定,包含 labelformat
  • 可用格式:"text""number""date""link""boolean""image""array""object"

挑選能讓使用者一目瞭然掌握資料全貌的最實用欄位。


階段 3:生成 key_value_store_schema.json(若適用)

目標:若 Actor 在 Key-Value Store 中儲存資料,請定義 Key-Value Store 集合(collections)

跳過此階段:如果在階段 1 未找到任何 Actor.setValue() / Actor.set_value() 呼叫(預設的 INPUT 鍵除外)。

檔案結構

{
    "actorKeyValueStoreSchemaVersion": 1,
    "title": "<描述性標題——Key-Value Store 包含的內容>",
    "description": "<單句描述儲存的資料>",
    "collections": {
        "<collectionName>": {
            "title": "<易於閱讀的標題>",
            "description": "<此集合包含的內容>",
            "keyPrefix": "<prefix->"
        }
    }
}

如何識別集合

將發現的 setValue / set_value 呼叫按 Key 模式進行分組:

  1. 固定 Key(例如 "RESULTS""summary")——使用 "key"(完全比對)
  2. 具前綴的動態 Key(例如 "screenshot-${id}"f"image-{name}")——使用 "keyPrefix"

每個分組各自成為一個集合。

集合屬性

屬性 必填 描述
title 顯示於 UI 分頁中
description 顯示於 UI 提示文字中
key 視情況 單一 Key 集合的精確 Key(keykeyPrefix 擇一使用,不可同時使用)
keyPrefix 視情況 多 Key 集合的前綴(keykeyPrefix 擇一使用,不可同時使用)
contentTypes 限制允許的 MIME 型別(例如 ["image/jpeg"]["application/json"]
jsonSchema 用於驗證 application/json 內容的 JSON Schema draft-07

範例

單一檔案輸出(例如報告):

{
    "actorKeyValueStoreSchemaVersion": 1,
    "title": "Analysis Results",
    "description": "Key-value store containing analysis output",
    "collections": {
        "report": {
            "title": "Report",
            "description": "Final analysis report",
            "key": "REPORT",
            "contentTypes": ["application/json"]
        }
    }
}

具前綴的多個檔案(例如螢幕截圖):

{
    "actorKeyValueStoreSchemaVersion": 1,
    "title": "Scraped Files",
    "description": "Key-value store containing downloaded files and screenshots",
    "collections": {
        "screenshots": {
            "title": "Screenshots",
            "description": "Page screenshots captured during scraping",
            "keyPrefix": "screenshot-",
            "contentTyp