如何将 Scrapeless 与 ChatGPT 通过自定义 GPT 操作连接起来
Scraping and Proxy Management Expert
TL;DR:
- ChatGPT无法将API密钥MCP服务器作为连接器。开发者模式MCP接受OAuth 2.1或无身份验证,OpenAI自己的文档说明ChatGPT“无法提供自定义API密钥”。
- 可行的路径是自定义GPT 操作:一个OpenAPI架构加上自定义头部的API密钥身份验证。
- 头部是
x-api-token,而不是Authorization: Bearer。将身份验证类型设置为API密钥,然后自定义,然后是该头部名称。 - 请求Markdown,而不是HTML。同一页面在Markdown中为8,676个字符,而在HTML中为50,403个字符——在模型花费于标记的上下文中减少了83%。
response_type仅在js_render: true旁边执行。将js_render排除在外,相同请求返回50,368个HTML字符,状态码为HTTP 200。outputFormat被接受并被静默忽略,返回全部50,403个HTML字符。- 下面的架构在OpenAPI 3.1.0中通过
openapi-spec-validator,并且它描述的请求已实时执行:{code: 200, data: string}。 - 在您开始之前,在Scrapeless免费计划中获取一个密钥。
询问ChatGPT有关其未见过的页面时,您会得到其训练数据的摘要或您无法控制的浏览结果。操作更改了安排:您将一个HTTP操作交给模型调用,并使用您定义的参数,对应您选择的API。
首先要解决的是ChatGPT将实际接受哪种机制,因为明显的答案是错误的。
为什么这是一个操作而不是MCP连接器
每个主要客户端都将Scrapeless MCP服务器视为使用头部中的密钥的远程HTTP连接器。ChatGPT并不这样,值得在围绕它构建之前了解原因。
该端点需要一个静态头部。未带头部调用时:
text
POST https://api.scrapeless.com/mcp (no auth)
-> HTTP 401
body: Unauthorized: Missing x-api-token header
www-authenticate: None
缺少的www-authenticate头部很重要。在HTTP身份验证框架下,401是服务器广播如何进行身份验证的位置,而请求OAuth挑战的客户端发现没有内容可跟随。也没有任何OAuth元数据可供发现:
text
/.well-known/oauth-protected-resource 404
/.well-known/oauth-authorization-server 404
/.well-known/oauth-protected-resource/mcp 404
模型上下文协议规范允许任何一种安排——在头部上的裸令牌是一个完全普通的MCP部署。限制在于ChatGPT方面:其开发者模式连接器支持OAuth 2.1或无身份验证,OpenAI的文档明确说明ChatGPT无法提供自定义API密钥。
因此没有可粘贴的URL。支持的带密钥的HTTP API路径是GPT操作,它确实支持使用您选择的头部名称的API密钥身份验证。
前提条件
- 包括创建GPT的ChatGPT计划。
- Scrapeless API密钥。
- 无托管,无代理,无本地过程。操作直接调用
api.scrapeless.com。
步骤1:OpenAPI架构
操作是描述一个或多个操作的OpenAPI文档。此文档描述一个单个操作:获取渲染的页面并将其作为Markdown返回。
yaml
openapi: 3.1.0
info:
title: Scrapeless Universal Scraping API
description: Fetch a fully rendered web page and return it as Markdown or HTML.
version: "1.0.0"
servers:
- url: https://api.scrapeless.com
paths:
/api/v2/unlocker/request:
post:
operationId: scrapeWebPage
summary: Fetch a web page with JavaScript rendering and return it as Markdown
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [actor, input]
properties:
actor:
type: string
enum: [unlocker.webunlocker]
description: The Scrapeless actor to run.
input:
type: object
required: [url, js_render, response_type]
properties:
url:
type: string
format: uri
description: The page to fetch.
js_render:
type: boolean
enum: [true]
default: true
description: Must be true. response_type only takes effect when JavaScript rendering is on.
response_type:
type: string
enum: [markdown, html]
default: markdown
description: Return the page as Markdown or raw HTML.
responses:
"200":
description: The rendered page.
content:
application/json:
schema:
type: object
properties:
code:
type: integer
data:
type: string
description: The rendered page, as Markdown or HTML.
"401":
description: Missing or invalid API token.
components:
securitySchemes:
scrapelessApiKey:
type: apiKey
in: header
name: x-api-token
security:
- scrapelessApiKey: []
其中有三个故意的选择。
actor是一个enum,而不是一个自由字符串。给定自由文本字段的模型最终会发明一个角色名;枚举使唯一有效的值成为唯一选项。
operationId是scrapeWebPage,这是您在GPT指令中引用的名称。模糊的ID产生模糊的工具选择。
response_type默认为markdown,出于第3步中的原因,它和js_render都被列为必需。模式默认值是文档:这并不意味着模型发送该字段,API自身对于js_render的默认是关闭的。
在粘贴之前验证是值得的三十秒——OpenAPI 3.1.0规范对结构非常严格,构建器的错误消息简短:
bash
pip install openapi-spec-validator
bash
python3 -c "
from openapi_spec_validator import validate
from openapi_spec_validator.readers import read_from_filename
spec, _ = read_from_filename('scrapeless-action.yaml')
validate(spec)
print('valid')"
text
valid
步骤2:身份验证
在GPT构建器中,打开操作的身份验证面板并设置:
| 字段 | 值 |
|---|---|
| 身份验证类型 | API密钥 |
| 身份验证类型 | 自定义 |
| 自定义头名称 | x-api-token |
| API密钥 | 您的Scrapeless密钥 |
API密钥下的默认值是Bearer,发送Authorization: Bearer <key>。Scrapeless读取x-api-token而无其他内容,因此保留默认值会导致401,构建器仅在首次调用操作时显示——在架构已经验证之后。
注意:构建器是一个网络用户界面,因此此步骤未作为本文的验证部分执行。关于 API 本身的所有声明——架构、标题名称、响应形状和下面的大小——均来自针对
api.scrapeless.com的实时调用。
第 3 步:请求 Markdown
此设置决定了连接器在读取任何内容之前消耗多少模型的上下文,并且该差异是可测量的。
同一类别页面,被获取两次:
text
response_type=markdown 8,676 chars
default (html) 50,403 chars
Markdown 小了 83%。GPT Action 的响应进入模型的上下文,因此返回 HTML 在标签、内联脚本和模型将忽略的属性上消耗了大部分预算。
旁边有一个陷阱。 outputFormat 看起来应该有效,并且在没有投诉的情况下被接受:
text
input.response_type = "markdown" -> 8,676 chars (markdown)
input.outputFormat = "markdown" -> 50,403 chars (HTML)
第二次调用成功,返回 HTTP 200,安静地返回 HTML,因为 outputFormat 不是演员读取的参数。一个被忽略而不是被拒绝的未知键是一种更难的bug——没有失败,输出只是形状错误且几乎比你预算的要大六倍。
第二个陷阱比较隐蔽。 response_type 仅在 JavaScript 渲染开启时生效,而 API 的默认设置是关闭的。发送 response_type: "markdown" 而没有 js_render: true,调用返回 HTTP 200,带有 50,368 个字符的 HTML,且没有错误和警告。上面的架构将 js_render 固定到 true,并因这个原因列为必需,下面的说明也命名了这两个字段。
现在就开始构建吗? Scrapeless 免费计划 覆盖了足够的请求以测试 Action 端到端。
第 4 步:调用它的说明
架构给予模型一种能力;说明决定何时使用它。明确命名操作:
text
When the user gives you a URL, or asks about the current contents of a
specific page, call scrapeWebPage with that URL, js_render true and
response_type "markdown". Do not answer from memory when a URL is present.
Return what the page says, and quote the exact figures it contains rather
than paraphrasing them. If scrapeWebPage reports a 401, tell the user the
API key is missing or misconfigured and stop.
第一段将工具绑定到触发器。没有它,拥有自己浏览能力的模型有时会使用该能力,而生成的结果与你的架构无关。
返回的内容
响应封装有两个字段,上面的架构声明了这两个字段:
json
{
"code": 200,
"data": "- [Home](https://books.toscrape.com/index.html)\n- [Books](...)\n..."
}
与实时 API 验证并且完全符合架构描述的请求体:
text
HTTP 200
response keys : ['code', 'data']
code : 200 (int)
data : str, 50403 chars
schema match : code=integer:True data=string:True
code 是 Scrapeless 自己的状态,与 HTTP 状态不同——这里两者都是 200。 data 是一个字符串单元,这就是模型接收文档而不是结构的原因;如果你想要字段,请在说明中请求它们或在下游自己解析。
结论
连接器是一个操作和一个头部。ChatGPT 不会使用 API 密钥 MCP 服务器——这是一个平台限制,由没有 OAuth 挑战的 401 确认,三个 404 表示元数据本应存在,以及 OpenAI 自己的声明——因此机制是一个 Action,机制并不是难点。
决定它是否正常工作的两个选择都是小事。将自定义头设置为 x-api-token,因为 Bearer 默认在调用时失败,而不是在设置时。并将 response_type 设置为 markdown,与 js_render: true 一起,因为 8,676 个 Markdown 字符留下思考的空间,而 50,403 个 HTML 字符则没有——并且看似合理的 outputFormat 被接受、忽略,并返回了更大的那个。
对于通过代码而不是 GPT 驱动的相同 API,我们的 ChatGPT 网络爬虫指南 涵盖了模型加拉取模式,Universal Scraping API 页面描述了这个操作背后的演员,文档 包含完整的参数参考,而 定价 列出了每次调用的费用。
准备好给 ChatGPT 一个你控制的获取了吗? 从 Scrapeless 免费计划开始 并粘贴架构。
常见问题
问:ChatGPT 能连接到 MCP 服务器吗?
是的,但仅使用 OAuth 2.1 或不进行身份验证的一个。开发者模式连接器无法提供静态 API 密钥,OpenAI 的文档直接说明了这一点。像 Scrapeless MCP 端点这样的服务器需要在 x-api-token 头部进行身份验证,并且不发布 OAuth 元数据,因此无法作为 ChatGPT 连接器添加——GPT Action 是支持的路径。
问:为什么我的 GPT Action 返回 401?
最常见的原因是头部名称。API 密钥认证类型默认设置为 Bearer,这会发送 Authorization: Bearer <key>;而 Scrapeless 读取 x-api-token。将身份验证类型设置为自定义,并将头部名称设置为 x-api-token。这种模式无论如何都能验证,因此在第一次调用时会出现,而不是在设置时。
问:GPT Actions 需要什么 OpenAPI 版本?
上面的架构是 OpenAPI 3.1.0,并符合该规范。保持文档简约——一个服务器 URL,明确的 operationId 值,以及不需要的 $ref 间接引用——因为构建者的解析器更严格,其错误也没有专用验证器的具体。
问:我如何阻止 Action 填充模型的上下文?
返回 Markdown。将 response_type 设置为 markdown,在同一请求中使用 js_render: true,将同一页面从 50,403 个字符减少到 8,676,并且 Action 的响应消耗了对话的上下文预算。还要缩小架构:单个操作和较小的参数集使模型有更少的空间构建昂贵的调用。
问:为什么我的 outputFormat 参数没有作用?
因为它不是演员读取的参数。请求仍然返回 HTTP 200 和完整的 HTML——50,403 个字符而不是 8,676。正确的键是 response_type,并且它需要 js_render: true 作为旁边。未知的键在这里会被忽略而不是被拒绝,因此当格式设置似乎没有效果时,请检查返回内容的大小。
问:一个 Action 可以暴露多个 Scrapeless 能力吗?
是的——在同一文档中为每个操作添加一个路径和一个 operationId。保持每个操作简洁,并保持 enum 约束,因为带有自由文本演员字段的单个操作会促使模型进行猜测。最小特权也使得 Action 更容易进行后续审查。
问:这在普通的 ChatGPT 对话中有效还是仅在自定义 GPT 中有效?
Actions 属于您配置的 GPT,因此该能力存在于该 GPT 中,而不是每个对话中。与您共享它的任何人都会获得该操作;他们是否提供自己的密钥取决于您如何设置身份验证。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。



