周一至周五 09:00 - 18:00(UTC+08:00) ©2026 NST LABS TECH LTD. 保留所有权利。
如何使用OpenAI的代理工具抓取招聘网站
Marcus Chen Product & Network Architect
如何使用OpenAI的智能代理工具抓取招聘网站
TL;DR
OpenAI 的消费 "Operator" 代理于 2025 年 8 月 31 日关闭,其继任者 ChatGPT 代理于 2026 年 7 月被撤回,以支持 ChatGPT Work — 都不是抓取工具,也都不暴露可以从自己代码中调用的公共 API。
"使用 OpenAI 代理抓取职业板" 的实际可构建路径是通过响应 API 调用的 computer_use_preview 工具,使用的是 computer-use-preview 模型 — 它通过屏幕截图和单击/输入/滚动操作驱动真实浏览器,而不是读取页面源。
在完全使用浏览器自动化之前,请检查目标板是否运行在申请者跟踪系统 (Greenhouse、Lever、Ashby) 上,并且是否有免费的、公共的、未经身份验证的 JSON 职位信息源 — 它直接返回结构化数据,完全跳过代理循环。
计算机使用代理只有在板没有公共源且页面 HTML 中没有可访问的 JobPosting 结构化数据时才是合适的工具,因为它比直接的 HTTP 请求更慢、每页更昂贵、且更脆弱。
在美国法庭上,抓取公共可达的职位列表在《计算机欺诈和滥用法》下是有效的,但板的自身服务条款仍可能产生单独的违约责任,并且规避机器人检测或速率限制在反规避法下会产生特定的法律风险。
通过旋转的住宅代理池路由代理的出站浏览器流量,以避开数据中心 IP 阻塞,并在存储之前将每个板的输出规范化为一个共享模式(标题、地点、网址、发布日期、描述)。
Introduction
"OpenAI Operator" 不再指代一个正在运行的产品。OpenAI 于 2025 年 1 月 23 日推出了 Operator 作为研究预览浏览器代理,启动时仅限于 ChatGPT Pro 订阅者,并于 2025 年 8 月 31 日关闭,之后将其能力整合到更广泛的 "ChatGPT agent" 模式中。ChatGPT agent 本身也没有持续太久:OpenAI 的帮助中心现在明确表示 "ChatGPT agent 不再可用。使用 ChatGPT Work 处理较长的、多步骤的任务和完成的交付物",根据 OpenAI 自己的帮助中心文章 ,这篇文章于 2026 年 7 月发布,成为当前的消费者代理接口。
这三种产品 — Operator、ChatGPT agent 或 ChatGPT Work — 都没有提供公共 API。它们是通过输入请求驱动的聊天界面功能,而不是可以连接到定期作业以每天早上将职位发布提取到数据库的东西。如果你想构建一个可重复的管道,OpenAI 的相关工具是 计算机使用工具 ,它位于响应 API 中 — 这是一个面向开发者的功能,扮演着与 Operator 相同的角色(查看屏幕截图,决定点击或输入的位置,并重复),但作为一个可以从你自己的代码中调用的 API。本教程基于该工具构建了一个职业板抓取器,并明确指出在何种情况下完整的浏览器代理是不适合此工作的工具。
Why scrape job boards at all
招聘和市场研究团队出于一些反复出现的原因提取结构化职位数据:按部门跟踪竞争对手的招聘速度,基准对一个行业的薪酬和职称通货膨胀,向人才获取工具提供最新的需求,或者构建一个聚合普通搜索引擎不太有效的职位搜索产品。所有这些最少需要相同的三个字段 — 标题、地点和稳定的源链接 — 以及用例所需的其他内容(发布日期、资历、远程资格、薪资范围(如果披露))。
AI 浏览器代理在那些在繁重的客户端 JavaScript 背后渲染列表、通过无限滚动交互进行分页,或者在每次部署时旋转 CSS 类名的板上,其成本是合理的,因为代理是基于它在屏幕上看到的内容进行推理,而不是固定选择器。它对已经答复请求并提供结构化 JSON 的板而言是错误的工具 — 那种情况下将在下一节中讨论,并且比驱动浏览器要快且便宜。
在编写代理循环之前,花五分钟检查目标板是否使其变得不必要。大多数招聘页面都是建立在少数几个申请人跟踪系统(ATS)之上的,几个最大的系统——Greenhouse、Lever、Ashby——公开提供一个免费的、无身份验证的JSON端点,该端点返回某一公司所有开放职位的列表。例如, 提供的 根本不需要API密钥,返回每个职位的 、 、 、 和 ,并带有一个可选的 参数,可以添加完整的职位描述。如果一家公司的人才招聘页面是由Greenhouse托管的,那么该端点比任何代理更可靠且显著便宜。
GET https://boards-api.greenhouse.io/v1/boards/{board_token}/jobs
id
title
location
absolute_url
updated_at
content=true
第二个后备层次是:许多职位发布页面——包括那些不运行已知ATS的页面——直接在页面的HTML中嵌入一个schema.org/JobPosting块作为JSON-LD,这是因为招聘网站希望其列表能被Google的招聘搜索功能正确识别。该JSON-LD是机器可读的,无需任何浏览器渲染;一个普通的HTTP GET请求和一个HTML解析器就能恢复它。在确认既没有公共ATS馈送也没有嵌入的结构化数据存在后,才可以使用计算机使用代理——在这种情况下,页面确实是交互式的(客户端渲染的结果、滚动触发的分页,或者在结果出现之前必须填写的搜索表单)而仅请求该URL的脚本根本得不到有用的返回。
快速了解一下
当一个板没有公开的馈送但也不需要完全的交互式自动化时,Nstproxy爬虫可以渲染页面的JavaScript,并通过单次API调用返回干净的Markdown或JSON,而不是编写浏览器代理脚本。
先决条件
拥有一个能够访问Responses API和computer-use-preview模型的OpenAI账户——这是与ChatGPT的消费者计划不同的开发者能力,按令牌收费(目前为每百万输入令牌$3.00,每百万输出令牌$12.00),加上每次工具调用的费用;在为生产运行预算之前,请在OpenAI的定价页面上验证当前定价。
安装了requests的Python 3.9+,或者使用您选择的语言的等效HTTP客户端。
一种能够渲染和截屏浏览器页面的方法,并将模型的操作翻译回真实的输入事件——OpenAI的指南指出Playwright作为参考实现;本教程的代码示例假设使用Playwright驱动的浏览器。
有一个轮换的代理池,以便在与超过少量页面交互时使用,因为单个爬虫IP发出重复的自动请求正是招聘网站机器人检测构建的模式。
用五分钟时间查看目标板的服务条款和robots.txt——在将其指向特定网站之前,请参见下面的观察和限制。
第1步:确认没有公共馈送可用 首先检查目标公司的招聘页面是否存在已知的ATS模式。如果招聘页面URL中包含greenhouse.io、lever.co或通过这些域重定向,请尝试直接访问该板的公共职位端点:
curl "https://boards-api.greenhouse.io/v1/boards/{board_token}/jobs?content=true"
如果返回一个jobs数组,提取就完成了——跳到第4步,并规范化该响应,而不是构建代理。board_token通常是公司在招聘网址中显示的slug。如果该端点返回404,该公司可能不在Greenhouse上,或者使用不同于其公共品牌名称的令牌,值得通过页面的外部网络请求(通过浏览器开发工具)进行快速手动检查,以查看是否有JSON API调用,在确定您根本需要代理之前。
第2步:设置计算机使用代理循环 如果没有馈送存在,请使用computer_use_preview工具初始化一次Responses API调用。该工具需要固定的display_width和display_height,与您的Playwright浏览器实际渲染的视口匹配,并且environment设置为"browser":
from openai import OpenAI
client = OpenAI ( ) # 从环境中读取OPENAI_API_KEY
response = client . responses . create (
model = "computer-use-preview" ,
tools = [ {
"type" : "computer_use_preview" ,
"display_width" : 1024 ,
"display_height" : 768 ,
"environment" : "browser" ,
} ] ,
input = [ {
"role" : "user" ,
"content" : [ {
"type" : "input_text" ,
"text" : (
"打开职业页面并列出每个职位名称、"
"地点和在未滚动情况下可见的职位链接。"
) ,
} ] ,
} ] ,
truncation = "auto" ,
)
该模型本身不执行任何操作——它返回一个 computer_call 描述一个操作(在某个坐标上的 click、带有文字的 type、一个 scroll 等等)。你的代码负责实际在真实浏览器中通过 Playwright 执行该操作,捕获新的屏幕截图,并将其作为 computer_call_output 发送回来,以便模型可以决定下一步:
call = response . output [ 0 ] # 计算机调用对象
action = call . action # 例如 {"type": "click", "x": 512, "y": 384}
run_action_in_playwright ( action ) # 执行操作,然后捕获新的屏幕截图
next_response = client . responses . create (
model = "computer-use-preview" ,
previous_response_id = response . id ,
tools = [ {
"type" : "computer_use_preview" ,
"display_width" : 1024 ,
"display_height" : 768 ,
"environment" : "browser" ,
} ] ,
input = [ {
"call_id" : call . call_id ,
"type" : "computer_call_output" ,
"output" : {
"type" : "input_image" ,
"image_url" : f"data:image/png;base64, { screenshot_base64 } " ,
} ,
} ] ,
truncation = "auto" ,
)
这种交换重复进行——操作、截图、发送、读取下一个操作——直到返回的响应中没有 computer_call,这表明模型认为任务已完成。这个请求/响应结构是为了说明文档模式,而不是在此环境中捕获到的实时 OpenAI 帐户的运行;在发布之前,请将变量名和确切字段顺序视为当前 API 参考的主题,因为 computer-use-preview 仍然是一个预览标签的模型。
第 3 步:分页并保持运行中的状态 职位公告板以三种常见方式进行分页,每种方式需要不同的循环条件:带有 "next" 控制的编号页面(单击它,截图,重复,直到控制消失时停止)、无限滚动(发送 scroll 操作,截图,并在两个连续的屏幕截图未产生新列表时停止),或 "load more" 按钮(单击,等待新的 DOM 渲染,截图)。因为代理只能看到像素,所以在模型之外自行跟踪去重:对每个提取的列表的标题加 URL 对进行哈希,并跳过您已经记录的任何项目,因为代理如果重新阅读部分滚动的页面,将会重新报告已列出的职位。
为每次运行设置一个硬分页限制和一个时间限制。计算机使用循环没有内置的“这个网站有40页而太多”的感觉——这个界限由你的代码负责,而不是模型的。
第 4 步:标准化为稳定的输出模式 无论数据来自 ATS JSON 提要、JSON-LD 块还是代理转录,都必须在存储之前将其格式化为相同的形状:
{
"id" : "8077887" ,
"title" : "数据平台工程师" ,
"location" : "远程 - 美国" ,
"url" : "https://boards.example.com/jobs/8077887" ,
"updated_at" : "2026-08-06T12:10:17-04:00" ,
"summary" : "构建和维护数据管道..." ,
"source" : "greenhouse-api" , # 或 "jsonld" / "computer-use-agent"
}
以下是针对返回此确切字段布局的实时 JSON 端点运行标准化的示例——利用一个本地 fixture 来替代真实的 ATS 主机,因为此环境的出站网络访问无法直接到达任意外部域(该模式已对 Greenhouse 的公共 API 进行了实时确认):
import requests
from html . parser import HTMLParser
class TextExtractor ( HTMLParser ) :
def __init__ ( self ) :
super ( ) . __init__ ( )
self . text = [ ]
def handle_data ( self , data ) :
stripped = data . strip ( )
if stripped :
self . text . append ( stripped )
resp = requests . get ( "http://127.0.0.1:8099/jobs.json" , timeout = 10 )
resp . raise_for_status ( )
payload = resp . json ( )
rows = [ ]
for job in payload [ "jobs" ] :
extractor = TextExtractor ( )
extractor . feed ( job [ "content" ] )
summary = " " . join ( extractor . text ) [ : 80 ]
rows . append ( {
"id" : job [ "id" ] ,
"title" : job [ "title" ] ,
"location" : job [ "location" ] [ "name" ] ,
"url" : job [ "absolute_url" ] ,
"updated_at" : job [ "updated_at" ] ,
"summary" : summary ,
} )
print ( rows )
输出:[{'id': 8077887, 'title': '数据平台工程师', 'location': '远程 - 美国', ...}, {'id': 8077888, 'title': '高级后端工程师,搜索', 'location': '纽约,纽约', ...}]
这在本地固定装置上成功运行,使用两个示例列表,确认了解析逻辑与Greenhouse的实际字段名(id,title,location.name,absolute_url,updated_at,content)的一致性,然后再将其指向实际板块。
第5步:通过旋转代理池路由请求 在短时间内向同一板块发出几十个自动化请求的单个IP,是机器人检测系统调整以标记的确切特征,无论这些请求是来自简单的requests.get()循环,还是来自计算机用户代理驱动的浏览器。对于ATS-feed方法,这意味着通过旋转池路由你的HTTP客户端;对于计算机用户代理,这意味着在浏览器上下文中启动Playwright并配置代理,以便每次页面加载——不仅仅是API调用——都来自于在会话之间变化的住宅IP。
Nstproxy Residential Prime Proxies 直接承担这一角色:它们通过一个大型国家池中的真实住宅IP路由流量,这在求职板的风险控制系统中读作普通浏览流量,而不是高度集中的数据中心请求。对于那些真正瓶颈在提取步骤本身而不是代理IP上的团队——需要JavaScript渲染、重试和干净结构输出的页面,而根本不维护Playwright/计算机用户循环——Nstproxy Crawl 值得评估,作为完全取代第2步和第3步在不严格要求交互式自动化的板块上的选项。Crawl:
渲染JavaScript并返回干净输出 ——单个API调用返回Markdown、干净的HTML或屏幕截图,而无需你自己启动浏览器进程。
默认支持代理 ——每次获取都通过Nstproxy自己的代理基础设施,带有浏览器指纹处理,涵盖本节所述的IP多样性问题。
根据成功获取计费,而不是尝试次数 ——获得真实响应的请求(包括404或403)计费一次;只有系统端无法检索到任何内容才不收费,这使得在一批职业页面中成本可预测。
Crawl目前并没有像某些竞争对手那样进行自然语言字段提取——你仍然需要根据返回的Markdown或HTML自己编写第4步的规范化——但它消除了对于任何计算机用户代理可能显得过于复杂的板块的浏览器编排负担。Crawl API参考 涵盖了单页面和站点级爬虫的确切请求和响应形状,而Crawl的当前订阅定价 是根据成功获取计费,而不是根据尝试计费,这在你决定使用它而不是自托管浏览器循环之前,值得与预期的页面量进行对比。Nstproxy的Crawl启动公告 涵盖了更全面的功能集,包括站点级爬虫和多格式输出,如果这个特定用例超出了单一职业页面。
观察和限制 相对于直接请求,计算机用户代理的速度慢且昂贵:每一个操作都需要一个模型往返加上一个全分辨率的屏幕截图上传,所以一个包含40个列表项的页面在你获得全部数据之前可能会进行数十次API调用。相应预算,尽可能选择ATS-feed或JSON-LD路径,只要两者中的任何一个可用——将代理保留给那些确实需要交互式导航的板块。
在法律上,这里的基础比感觉上更为稳固。在hiQ Labs诉LinkedIn案 中,第九巡回法院裁定——在上诉和重审中都裁定——抓取一个网站已公开可访问的数据并不违反计算机欺诈和滥用法案,因为CFAA针对的是对非公开系统的未经授权访问,而不是自动收集任何人已经可以在浏览器中看到的内容。这并不意味着抓取是没有风险的:一个板块自己的服务条款可以独立禁止自动收集,违反该协议即使没有CFAA的主张也会产生单独的违约风险。一个更新且可以说更加尖锐的风险存在于反规避法中——Reddit针对Perplexity的2025年诉讼 中心围绕着DMCA § 1201的主张,特别是对于规避速率限制、CAPTCHA和机器人检测系统的议题,这与“数据是否公开”是不同的法律理论。在对任何爬虫运行前,请阅读目标板的服务条款,并将“网站设置了CAPTCHA”视为停止的信号,而不是要解决的难题。
职位列表也可以携带个人数据——例如,发布中嵌入的某个指定招聘者的直接电子邮件或电话号码——这会触发普通的数据保护义务(包括GDPR),无论页面本身是否公开。大规模存储招聘经理的联系信息而没有特定用途的法律依据,是与存储职位名称和位置 materially不同的活动,而此工作流程不应随意越过这条界限,通过捕获发布内容中超出实际用例需求的部分。
任何指定招聘板上的标记和页面结构会在没有通知的情况下发生变化,而基于代理的方式比脆弱的CSS选择器脚本对这种变化更具容忍度——但如果招聘板更换ATS提供商或重新设计其职业页面,双方的方法都会退化,因此应预算定期重新验证,而不是使用“设置后就忘”的管道。
结论 “使用OpenAI Operator进行抓取”描述了一个不再存在的产品;今天可以构建的真实等价物是OpenAI的computer_use_preview工具,该工具通过响应API调用,并与您自己的浏览器自动化配对。只有在排除了公共ATS源或嵌入的JobPosting结构化数据后,才应使用此工具,因为这两者都比操作浏览器更快、更便宜且更稳定。无论选择哪种提取方法,请将输出规范化为一个模式,明确限制分页,通过住宅代理池或诸如Nstproxy Crawl之类的渲染API路由流量,以避免基于IP的阻止,并在对目标招聘板进行任何自动化操作之前阅读其服务条款。
常见问题 问:OpenAI Operator 是否仍可用于抓取招聘板?
不可以。Operator 于 2025 年 8 月 31 日关闭。它的继任者 ChatGPT agent 也被退役——OpenAI 的帮助中心现在将用户引导至 ChatGPT Work。Operator、ChatGPT agent 和 ChatGPT Work 都不公开API;用于自定义管道的可构建等价物是响应API中computer_use_preview模型上的computer_use_preview工具。
问:我需要为每个招聘板使用计算机使用代理吗?
不需要。首先检查招聘板是否运行在带有公共JSON源的ATS上(Greenhouse、Lever和Ashby都有),或直接在页面HTML中嵌入schema.org/JobPosting结构化数据。这两者都比驱动浏览器更快、更便宜且更稳定,只有在这两者都不存在时,计算机使用代理才值得额外的成本和延迟。
问:抓取公开可见的职位列表是否合法?
美国法院在hiQ Labs诉LinkedIn案中裁定,抓取网站公开可访问的数据本身并不违反计算机欺诈和滥用法。这并不能消除所有法律风险:招聘板的服务条款可以分别禁止自动收集作为合同事项,绕过速率限制或机器人检测会带来独特的反规避风险。在抓取之前阅读特定招聘板的服务条款,并将其视为每个网站的决定,而不是一个普遍的法律事实。
问:如果一个招聘板更改其页面布局,会发生什么?
计算机使用代理对布局和标记变化的容忍度高于固定的CSS选择器脚本,因为它是根据屏幕上可视内容进行推理,而不是特定的DOM路径。它对ATS迁移或整个网站重新设计没有光滑的适应能力——无论使用哪种方法,都应预算定期重新验证您的提取逻辑。
问:这个过程一次可以处理多少页面或列表?
在您自己的代码中设置明确的页面计数和实时时间限制;无论是ATS源方法还是计算机使用循环,均不会自行强制执行合适的停止点。具体对于代理循环,也要通过标题和URL去重提取的列表,因为重新滚动部分阅读的页面可能导致模型重新报告已经找到的条目。
问:这个工作流程是否完全需要代理才能发挥作用?
不需要——本教程中的代码可以不使用代理运行。一旦您在短时间内对同一招聘板发出重复的自动请求,代理池就变得必要,这是大多数招聘板机器人检测被调校标记的模式,无论这些请求是来自普通HTTP客户端还是由计算机使用代理驱动的浏览器。
问:这种方法是否可以从列表中提取薪水和联系信息?
从技术上讲,可以,只要该数据出现在页面上。请小心对待:发布中的招聘者电子邮件或电话号码属于个人数据,受普通数据保护规则(包括GDPR)的约束,即使页面本身是公开的,因此请仅捕获和存储您实际用例所需的字段。
立即访问住宅、数据中心、IPv6 与 ISP 高质量代理池。 创建免费账号并立即试用 ->