# JSON 模式 - 结构化结果 (/zh/features/llm-extract)

<!-- agent-signals: reading_time_min: 6 · est_tokens: 3361 · updated: 2026-07-30 -->
Related: [搜索](/zh/features/search.md), [搜索高亮](/zh/features/search-highlights.md), [研究索引](/zh/features/research.md), [抓取](/zh/features/scrape.md), [更快的抓取](/zh/features/fast-scraping.md), [批量抓取](/zh/features/batch-scrape.md)

**选择合适的工具。** 当你只有**一个 URL**，并且想从该页面提取字段时，JSON 模式 (本页) 就是合适的选择。

* 对于**任何超出单个 URL 的场景**——例如多个 URL、URL 模式或代理发现——请参见 [代理](/zh/features/agent)。
* 完整对比： [如何选择数据提取器](/zh/developer-guides/usage-guides/choosing-the-data-extractor)。

<Note>
  **v2 API 变更：** v2 已完全支持 JSON schema 提取，但 API 格式有所调整。在 v2 中，schema 直接嵌入到 format 对象中，写法为 `formats: [{type: "json", schema: {...}}]`。v1 的 `jsonOptions` 参数在 v2 中已被移除。
</Note>

<Note>
  对于 schema 验证失败及其他提取错误，请参见 

  [Errors](/zh/api-reference/errors)

  ——提取相关问题通常会表现为 

  `400`

   或 

  `422`

   响应。
</Note>

<div id="scrape-and-extract-structured-data-with-firecrawl">
  ## 使用 Firecrawl 抓取并提取结构化数据 [#使用-firecrawl-抓取并提取结构化数据]
</div>

Firecrawl 借助 AI 通过 3 个步骤从网页获取结构化数据：

1. **设置 Schema (可选) ：**
   定义一个 JSON Schema (采用 OpenAI 的格式) 来明确所需数据；如果不需要严格的 Schema，也可仅提供一个 `prompt`，并附上网页 URL。

2. **发起请求：**
   使用 JSON 模式将你的 URL 和 Schema 发送到我们的 /scrape 端点。查看方法：
   [Scrape Endpoint Documentation](https://docs.firecrawl.dev/api-reference/endpoint/scrape)

3. **获取数据：**
   返回与你的 Schema 匹配的干净、结构化数据，可直接使用。

这使你能快速、轻松地按所需 formats 获取网页数据。

<div id="extract-structured-data">
  ## 提取结构化数据 [#提取结构化数据]
</div>

<div id="json-mode-via-scrape">
  ### 通过 /scrape 的 JSON 模式 [#通过-scrape-的-json-模式]
</div>

用于从抓取的页面中提取结构化数据。

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="curl+node+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Node">
        Node
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="cURL">
        cURL
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from firecrawl import Firecrawl
      from pydantic import BaseModel

      app = Firecrawl(
        # 无需 API 密钥即可开始使用 — 添加一个以获得更高的限流额度：
        # api_key="fc-YOUR-API-KEY",
      )

      class CompanyInfo(BaseModel):
          company_mission: str
          supports_sso: bool
          is_open_source: bool
          is_in_yc: bool

      result = app.scrape(
          'https://firecrawl.dev',
          formats=[{
            "type": "json",
            "schema": CompanyInfo.model_json_schema()
          }],
          only_main_content=False,
          timeout=120000
      )

      print(result)
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Node">
      ```js  
      import { Firecrawl } from "firecrawl";
      import { z } from "zod";

      const app = new Firecrawl({
        // 无需 API 密钥即可开始使用——添加一个以获得更高的限流额度：
        // apiKey: "fc-YOUR_API_KEY",
      });

      // Define schema to extract contents into
      const schema = z.object({
        company_mission: z.string(),
        supports_sso: z.boolean(),
        is_open_source: z.boolean(),
        is_in_yc: z.boolean()
      });

      const result = await app.scrape("https://firecrawl.dev", {
        formats: [{
          type: "json",
          schema: schema
        }],
      });

      console.log(result);
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash  
      # 无需 API 密钥即可开始使用 — 添加 -H "Authorization: Bearer YOUR_API_KEY" 以获得更高的限流额度：
      curl -X POST https://api.firecrawl.dev/v2/scrape \
          -H 'Content-Type: application/json' \
          -d '{
            "url": "https://firecrawl.dev",
            "formats": [ {
              "type": "json",
              "schema": {
                "type": "object",
                "properties": {
                  "company_mission": {
                            "type": "string"
                  },
                  "supports_sso": {
                            "type": "boolean"
                  },
                  "is_open_source": {
                            "type": "boolean"
                  },
                  "is_in_yc": {
                            "type": "boolean"
                  }
                },
                "required": [
                  "company_mission",
                  "supports_sso",
                  "is_open_source",
                  "is_in_yc"
                ]
              }
            } ]
          }'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

输出：

```json title="JSON"
{
    "success": true,
    "data": {
      "json": {
        "company_mission": "AI 赋能的网页抓取与数据抽取",
        "supports_sso": true,
        "is_open_source": true,
        "is_in_yc": true
      },
      "metadata": {
        "title": "Firecrawl",
        "description": "AI 赋能的网页抓取与数据抽取",
        "robots": "follow, index",
        "ogTitle": "Firecrawl",
        "ogDescription": "AI 赋能的网页抓取与数据抽取",
        "ogUrl": "https://firecrawl.dev/",
        "ogImage": "https://firecrawl.dev/og.png",
        "ogLocaleAlternate": [],
        "ogSiteName": "Firecrawl",
        "sourceURL": "https://firecrawl.dev/"
      },
    }
}
```

<div id="structured-data-without-schema">
  ### 无需 schema 的结构化数据 [#无需-schema-的结构化数据]
</div>

你也可以只向端点传入一个 `prompt`，在没有 schema 的情况下进行提取。LLM 会自行确定数据结构。

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="curl+node+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Node">
        Node
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="cURL">
        cURL
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from firecrawl import Firecrawl

      app = Firecrawl(
        # 无需 API 密钥即可开始使用 — 添加一个以获得更高的限流额度：
        # api_key="fc-YOUR-API-KEY",
      )

      result = app.scrape(
          'https://firecrawl.dev',
          formats=[{
            "type": "json",
            "prompt": "Extract the company mission from the page."
          }],
          only_main_content=False,
          timeout=120000
      )

      print(result)
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Node">
      ```js  
      import { Firecrawl } from "firecrawl";

      const app = new Firecrawl({
        // 无需 API 密钥即可开始使用 — 添加一个以获得更高的限流上限：
        // apiKey: "fc-YOUR_API_KEY",
      });

      const result = await app.scrape("https://firecrawl.dev", {
        formats: [{
          type: "json",
          prompt: "Extract the company mission from the page."
        }]
      });

      console.log(result);
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash  
      # 无需 API 密钥即可开始使用——添加 -H "Authorization: Bearer YOUR_API_KEY" 可获得更高限流：
      curl -X POST https://api.firecrawl.dev/v2/scrape \
          -H 'Content-Type: application/json' \
          -d '{
            "url": "https://firecrawl.dev",
            "formats": [{
              "type": "json",
              "prompt": "Extract the company mission from the page."
            }]
          }'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

输出：

```json title="JSON"
{
    "success": true,
    "data": {
      "json": {
        "company_mission": "AI 驱动的网页抓取与数据抽取",
      },
      "metadata": {
        "title": "Firecrawl",
        "description": "AI 驱动的网页抓取与数据抽取",
        "robots": "follow, index",
        "ogTitle": "Firecrawl",
        "ogDescription": "AI 驱动的网页抓取与数据抽取",
        "ogUrl": "https://firecrawl.dev/",
        "ogImage": "https://firecrawl.dev/og.png",
        "ogLocaleAlternate": [],
        "ogSiteName": "Firecrawl",
        "sourceURL": "https://firecrawl.dev/"
      },
    }
}
```

<div id="real-world-example-extracting-company-information">
  ### 真实案例：提取公司信息 [#真实案例提取公司信息]
</div>

下面是一个从网站提取结构化公司信息的完整示例：

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="curl+node+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Node">
        Node
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="cURL">
        cURL
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from firecrawl import Firecrawl
      from pydantic import BaseModel

      app = Firecrawl(
        # 无需 API 密钥即可开始使用 — 添加一个以获得更高的限流额度：
        # api_key="fc-YOUR-API-KEY",
      )

      class CompanyInfo(BaseModel):
          company_mission: str
          supports_sso: bool
          is_open_source: bool
          is_in_yc: bool

      result = app.scrape(
          'https://firecrawl.dev/',
          formats=[{
              "type": "json",
              "schema": CompanyInfo.model_json_schema()
          }]
      )

      print(result)
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Node">
      ```js  
      import { Firecrawl } from "firecrawl";
      import { z } from "zod";

      const app = new Firecrawl({
        // 无需 API 密钥即可开始使用 — 添加一个以获得更高的限流额度：
        // apiKey: "fc-YOUR_API_KEY",
      });

      const companyInfoSchema = z.object({
        company_mission: z.string(),
        supports_sso: z.boolean(),
        is_open_source: z.boolean(),
        is_in_yc: z.boolean()
      });

      const result = await app.scrape("https://firecrawl.dev/", {
        formats: [{
          type: "json",
          schema: companyInfoSchema
        }]
      });

      console.log(result);
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash  
      # 无需 API 密钥即可开始使用——添加 -H "Authorization: Bearer YOUR_API_KEY" 可获得更高限流额度：
      curl -X POST https://api.firecrawl.dev/v2/scrape \
          -H 'Content-Type: application/json' \
          -d '{
            "url": "https://firecrawl.dev/",
            "formats": [{
              "type": "json",
              "schema": {
                "type": "object",
                "properties": {
                  "company_mission": {
                    "type": "string"
                  },
                  "supports_sso": {
                    "type": "boolean"
                  },
                  "is_open_source": {
                    "type": "boolean"
                  },
                  "is_in_yc": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "company_mission",
                  "supports_sso",
                  "is_open_source",
                  "is_in_yc"
                ]
              }
            }]
          }'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

输出：

```json title="Output"
{
  "success": true,
  "data": {
    "json": {
      "company_mission": "将网站转换为 LLM 可用数据",
      "supports_sso": true,
      "is_open_source": true,
      "is_in_yc": true
    }
  }
}
```

<div id="json-format-options">
  ### JSON 格式选项 [#json-格式选项]
</div>

在 v2 中使用 JSON 模式时，需要在 `formats` 中直接包含一个内嵌 schema 的对象：

`formats: [{ type: 'json', schema: { ... }, prompt: '...' }]`

参数：

* `schema`: 描述所需结构化输出的 JSON Schema (基于 schema 的提取为必填) 。
* `prompt`: 可选提示，用于引导提取 (也用于无 schema 的提取) 。

**重要说明：** 与 v1 不同，v2 中没有单独的 `jsonOptions` 参数。schema 必须直接包含在 `formats` 数组中的 format 对象内。

<Note>
  **JSON 提取中不支持 HTML 属性。** JSON 提取是基于页面的 Markdown 转换结果工作的，该转换只保留可见文本内容。HTML 属性 (例如 `data-id`、元素上的自定义属性) 会在转换过程中被去除，大语言模型无法看到这些属性。如果你需要提取 HTML 属性值，请使用 `rawHtml` format 并在客户端解析属性，或者使用 `executeJavascript` 动作为在提取前将属性值注入到可见文本中。
</Note>

<div id="tips-for-consistent-extraction">
  ## 保持提取一致性的技巧 [#保持提取一致性的技巧]
</div>

如果你在使用 JSON 提取时遇到结果不一致或不完整的情况，可以参考以下做法：

* **让 prompt 简短且聚焦。** 带有大量规则的长 prompt 会增加结果的不确定性。将具体约束 (如允许值) 移入 schema 本身。
* **使用简洁的属性名。** 避免在属性名中嵌入说明或枚举列表。用类似 `"installation_type"` 这样的简短键名，并把允许值放在 `enum` 数组中。
* **为受限字段添加 `enum` 数组。** 当某个字段只有固定取值时，将它们列在 `enum` 中，并确保与页面上显示的文本完全匹配。
* **在字段描述中包含 null 处理逻辑。** 在每个字段的 `description` 中添加 `"Return null if not found on the page."`，以避免模型猜测缺失值。
* **添加位置信息提示。** 告诉模型在页面上哪里查找数据，例如 `"Flow rate in GPM from the Specifications table."`。
* **将大型 schema 拆分成多个请求。** 字段很多 (例如 30+) 的 schema 通常会产生更不稳定的结果。将其拆成 2–3 个请求，每个请求包含 10–15 个字段。
* **避免在数组上使用 `minItems`/`maxItems`。** `minItems` 和 `maxItems` 这类 JSON Schema 验证关键字并不能控制抓取器收集多少内容。设置 `minItems: 20` 并不会让 LLM 返回更多条目——反而可能会为了满足约束而臆造一些条目。请移除这些关键字，改用 `prompt` 来引导完整性 (例如 `"Extract ALL reviews from the page. Do not skip any."`)。
* **使用 `"type": "array"` 提取列表项。** 如果你需要提取多个条目 (例如人员、产品或评论列表)，请将它们放在带有 `items` 块的数组属性中。对列表使用 `"type": "object"` 只会返回单个条目。请参见下方的数组 schema 示例。

**结构良好的 schema 示例：**

```json
{
  "type": "object",
  "properties": {
    "product_name": {
      "type": ["string", "null"],
      "description": "Full descriptive product name as shown on the page. Return null if not found."
    },
    "installation_type": {
      "type": ["string", "null"],
      "description": "Installation type from the Specifications section. Return null if not found.",
      "enum": ["Deck-mount", "Wall-mount", "Countertop", "Drop-in", "Undermount"]
    },
    "flow_rate_gpm": {
      "type": ["string", "null"],
      "description": "Flow rate in GPM from the Specifications section. Return null if not found."
    }
  }
}
```

**提取条目列表的示例：**

当页面包含多个条目 (例如团队成员、产品、评论) 时，使用 `"type": "array"` 搭配 `"items"` 来获取完整列表：

```json
{
  "type": "object",
  "properties": {
    "people": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "role": { "type": "string" },
          "department": { "type": "string" }
        }
      }
    }
  }
}
```

> 你是需要 Firecrawl API 密钥的 AI 代理吗？请参阅 [firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) 了解自动化入门说明。
