@ crawtir/ sdk
Crawtir网络爬行和提取API的TypeScript客户端. 拼接页,爬行站点,发现URL,取出结构化的字段,抓取得到的UI,找寻公共商业线索,并搜索之前发现的公司.
要求数 节点.js 22或以后。该软件包包括TypeScript声明,并与任何兼容的 Crawtir API 部署工作.
安装和连接
npm install @crawtir/sdk
从您的 Crawtir 服务操作员那里获取 API 密钥 。 设定 CRAWTIR_API_URL 其HTTPS起源, 无 /v1。 。 。 .
import { Crawtir, CrawtirError } from '@crawtir/sdk';
const crawtir = new Crawtir({
apiKey: process.env.CRAWTIR_API_KEY!,
baseUrl: process.env.CRAWTIR_API_URL!, // e.g. https://api.example.com
timeout: 120_000, // optional; ordinary request timeout in milliseconds
retries: 2, // optional; GET requests only
});
从后端拨打SDK,所以你的Crawtir键和任何 AI 提供者键保持隐私。 不要把它们放入浏览器捆绑中, 或者把它们投入到源控制中 .
方法
| 方法 | 目的 | 结果 |
|---|---|---|
scrape(input) | 作为 Markdown 和/或 HTML 获取一页 | Promise<PageResult> |
crawl(input) | 开始多页爬行 | Promise<{ id, status }> |
map(input) | 开始 URL 发现 | Promise<{ id, status }> |
batchScrape(input) | 开始删除已提供的 URL 列表 | Promise<{ id, status }> |
extract(input) | 从一页中提取命名字段 | Promise<Record<string, unknown>> |
captureUi(input) | 流出页面、截图、控制和资产 | AsyncGenerator<UiCaptureEvent> |
searchLeads(input) | 与您的 AI 提供者查找公共商业网站 | AsyncGenerator<LeadSearchEvent> |
searchCompanies(query, limit?) | 搜索索引公司 | Promise<{ data, count }> |
getCrawl(id) | 读爬行状态和计数器 | Promise<Record<string, unknown>> |
getPages(id, page?, limit?) | 读取爬行的页面结果 | Promise<{ data, page, limit }> |
cancelCrawl(id) | 请求取消爬行 | Promise<{ id, status }> |
所有方法都通过您的 Crawtir API 密钥认证 . searchLeads() 额外要求 您的 OpenAI 或 OpenRouter 每次通话的密钥. Crawtir API 键不包括使用服务运营商的AI账户.
打印一页
const page = await crawtir.scrape({
url: 'https://example.com/about',
formats: ['markdown', 'html'],
onlyMainContent: true,
renderJavaScript: 'auto',
timeout: 30_000,
});
console.log(page.title, page.statusCode);
console.log(page.markdown);
console.log(page.links);
scrape() 返回 a PageResult 与 url, (中文(简体) ), canonicalUrl, (中文(简体) ), title, (中文(简体) ), description, (中文(简体) ), metadata, (中文(简体) ), links, (中文(简体) ), statusCode, (中文(简体) ), extractedAt,以及 durationMs。 。 。 . markdown 财务报告和审定财务报表 html 请随时到场。 慢刮可以成为同步工作;SDK的民意调查工作仍然解决到一页.
| 选项 | 默认 | 含义 |
|---|---|---|
url | 需求 | HTTP或HTTPS页面URL. |
formats | ['markdown'] | markdown, (中文(简体) ), html或两者兼有. |
onlyMainContent | true | 主要内容优于导航和页铬. |
renderJavaScript | 'auto' | 'auto', (中文(简体) ), 'always',或 'never'。 。 。 . |
timeout | 30000 | 页面处理超时以毫秒计; 1000–120 000. |
priority | 5 | 优先排序从 1 到 10 . |
建筑师的 timeout 控制SDK的HTTP请求和投票等待. 碎片输入器的 timeout 控制页面处理.
爬行多页
crawl() 启动同步任务并返回其ID。 票价 getCrawl() 直到它的状态是终端,然后页面通过 getPages()。 。 。 .
const job = await crawtir.crawl({
url: 'https://example.com',
limit: 50,
maxDepth: 3,
includePaths: ['/docs'],
excludePaths: ['/docs/archive'],
formats: ['markdown'],
});
let status: Record<string, unknown>;
for (;;) {
status = await crawtir.getCrawl(job.id);
if (['completed', 'failed', 'cancelled'].includes(String(status.status))) break;
await new Promise((resolve) => setTimeout(resolve, 2_000));
}
if (status.status !== 'completed') {
throw new Error(`Crawl ended with status ${String(status.status)}`);
}
for (let pageNumber = 1; ; pageNumber++) {
const result = await crawtir.getPages(job.id, pageNumber, 100);
for (const page of result.data) {
console.log(page.url, page.title, page.markdown);
}
if (result.data.length < result.limit) break;
}
limit 默认为100页(schema范围为1至5,000;部署可能执行下限). maxDepth 默认为 3 (范围 0-20) . includePaths 财务报告和审定财务报表 excludePaths 过滤路径并允许最多100个条目。 Crawl 输入还接受 scrape 选项. getPages() 默认为有20个结果的第1页,并允许每个请求最多100个。 打电话 await crawtir.cancelCrawl(job.id) 请求取消.
Crawls 跟踪起始主机及其上的链接 www 或无www 变种. 它们不自动包括其他子域,例如: blog.example.com。启动 URL 可能会在两个主机变量之间重定向而不会结束爬行.
映射一个网站或刮去已知的 URL
使用 map() 用于 URL 发现和 batchScrape() 用于您已经知道的 URL 。 两张回职身份证.
const mapJob = await crawtir.map({
url: 'https://example.com',
limit: 100,
maxDepth: 2,
});
const batchJob = await crawtir.batchScrape({
urls: [
'https://example.com/about',
'https://example.com/contact',
],
formats: ['markdown'],
});
console.log(mapJob.id, batchJob.id);
map() 默认为 100 个 URL 和 深度 2 ; 计划允许 1– 5,000 个 URL 和 深度 0–5 , 但须遵守部署的上限 . batchScrape() 接受 1–500 个 URL 和 刮擦 选项 url。SDK目前没有 getMap() 或者说 getBatch() 帮手 通过 HTTP API 用相同的无记名密钥读取这些任务 : GET /v1/map/:id, (中文(简体) ), GET /v1/map/:id/pages, (中文(简体) ), GET /v1/batch/:id,以及 GET /v1/batch/:id/pages。 。 。 .
提取结构字段
给 extract() 一个战地计划。 可选 CSS 选择者指定每个字段的读取位置 .
const data = await crawtir.extract({
url: 'https://example.com/contact',
schema: {
heading: 'string',
email: 'string|null',
links: 'string[]',
},
selectors: {
heading: 'h1',
email: 'a[href^="mailto:"]',
links: 'main a',
},
});
console.log(data.heading, data.email, data.links);
字段类型为 string, (中文(简体) ), string|null,以及 string[]. 供应 1-50 字段;名称必须以字母开头,只包含字母、数字或下划线。 结果是提取值的记录. useAI?: boolean 当目标部署已配置取出AI时即可使用;它与使用调用器的提供者是分开的 searchLeads()SDK的民意测验 延缓了采掘工作.
抓取使UI穿过一个地点
captureUi() 访问起始主机及其上的多页 www 或无www 变体,然后在每一页到达时发出. 在抓取一页之前,浏览器会通过它滚动来揭示懒惰的段落和图像. 一个页面包含 html,发现 links可见 controls, JPEG 视图端口 screenshot 编码为 base64, viewport,以及 assets 与 原始绝对 URL,内容类型,和基数64正文. 这些资产包括被获取的图像,CSS,字体,和脚本;截图是一个单独的预览,而不是图像文件的替换. Crawtir还扫描了HTML和CSS,以获取浏览器在该取景口未请求的资源,包括懒惰的图像引用和未使用的字体变体,并在资产限度内取出. Crawtir直接流出这些值,而不存储被捕获的有效载荷.
设定 output: 'project' 以接收每个页面的平面 HTML 文件名 (index.html, (中文(简体) ), about.html, (中文(简体) ), blog--post.html),一个单独的合并样式表,以及被捕获的图像,字体和脚本的本地路径. page.project.html 有当地参考文献; page.html 仍为原制 HTML 。 每个资产 url (原始请求), resolvedUrl (重新定向后的最后URL,或原URL),, path, (中文(简体) ), kind,内容类型,和基数64正文. page.project.assetMap 重复不为导入者提供字节的 URL 到路径映射 。 在这些路径上写入页面、样式表和资产以创建本地项目;没有生成 ZIP 。 样式表保留了 CSS 块顺序,而外部脚本则保留在原标记顺序中作为单独的文件. 默认 output: 'raw' 保留较早的反应形状.
使用 assetPathStyle: 'clean' 分类路径 assets/images/, (中文(简体) ), assets/js/, (中文(简体) ), assets/css/, (中文(简体) ), assets/fonts/,以及 assets/other/默认值 source 样式保持源主机和目录结构,这可以更好地支持运行时加载相对块的脚本. excludeResourceKinds 接受 challenge, (中文(简体) ), analytics,以及 infrastructure。分类是保守的:普通图像、字体和脚本CDN是 site 资产并保留在内。 排除从有效载荷中去除匹配资源并进行 HTML 项目;排除资源报告于 skippedAssets。 。 。 .
import { mkdir, writeFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
const root = './captured-site';
async function save(path: string, bytes: string | Buffer) {
const destination = join(root, path);
await mkdir(dirname(destination), { recursive: true });
await writeFile(destination, bytes);
}
for await (const event of crawtir.captureUi({
url: 'https://example.com',
output: 'project',
assetPathStyle: 'clean',
excludeResourceKinds: ['challenge', 'analytics'],
limit: 20,
maxDepth: 3,
})) {
if (event.type === 'page' && event.page.project) {
const { project, assets } = event.page;
await save(project.path, project.html);
if (project.stylesheet)
await save(project.stylesheet.path, Buffer.from(project.stylesheet.base64, 'base64'));
for (const asset of assets)
if (asset.path) await save(asset.path, Buffer.from(asset.base64, 'base64'));
for (const failure of event.page.skippedAssets ?? [])
console.warn(failure.category, failure.url, failure.reason, failure.contentType, failure.referringPage);
for (const script of project.scripts)
console.log(script.originalUrl, script.path, script.captured, script.locallyReferenced, script.executionStatus);
if (project.warnings.length) console.warn(project.warnings);
}
}
页面链接重写为平面文件名 。 HTML 引用包括了普通和懒惰的图像属性, <picture> 来源, srcset、脚本、图标和预装链接; CSS url() 财务报告和审定财务报表 @import 引用重写为本地资产路径 . project.scripts 按顺序列出文档脚本标记,然后是未作为标记出现的被捕获的网络脚本。 它保存着 async, (中文(简体) ), defer,以及 type 元数据并识别Webflow、GSAP、ScrollTrigger和jQuery信号. captured 表示 Crawtir 有脚本字节; locallyReferenced 指重写的HTML指向文件. executionStatus: 'not_verified' 表示需要本地运行时间检查 。 动态加载的块可不带文档标记而被捕获 。 Clean 路径可以打破一个计算相对 URL 的脚本或动态地加载块;项目报告此案件的警告 。 API的调用,认证,形式,以及站点特定的运行时间逻辑也可能依赖于原始服务. 使用 HTTP 上保存的文件测试行为; 浏览器可能限制直接打开的脚本和字体 file://。 。 。 .
严格完整性报告
设定 output: 'project' 财务报告和审定财务报表 requireComplete: true 以 incomplete 当一个镜像内页失败、发现点击了页数限制、缺少必要的本地文件、资产仍然遥不可及而没有明确的备忘或请求的交互检查失败时。 刚才 page 事件仍可供检查,但 在终端事件到来前不要把它们当作成功的导入。 。 。 . incomplete.report.gaps 解释每一个失败。 成功运行结束 complete 财务报告和审定财务报表 report.status === 'complete'没有严格的模式, complete.status 还可以 incomplete;检查.
for await (const event of crawtir.captureUi({
url: 'https://example.com',
output: 'project',
requireComplete: true,
domains: ['docs.example.net'], // additional exact page host; root and its www variant are included
limit: 50,
maxDepth: 3,
externalAssetHosts: ['video.example.net'], // deliberately left remote
interactionChecks: [{
name: 'mobile-menu',
pagePath: 'index.html',
selector: '.w-nav-button',
action: 'click',
expectSelector: '.w-nav-button.w--open',
}],
})) {
if (event.type === 'page') {
// Collect files, but commit the import only after the terminal result.
}
if (event.type === 'incomplete') {
console.error(event.report.gaps);
// Discard or keep the staged files for debugging.
}
if (event.type === 'complete') console.log(event.report?.status);
}
报告记录了根和额外的页面主机、路径过滤器、页数限制、深度和捕获状态(initial_render, (中文(简体) ), scroll_reveal,并命名为支票). 它列出资源成果(captured_locally, (中文(简体) ), intentionally_external, (中文(简体) ), excluded, (中文(简体) ), blocked, (中文(简体) ), failed, (中文(简体) ), not_verified),并附有URL和理由,外加当地证明人查询. 附加域是精确的主机名;没有通配符或自动的兄弟-域爬行被暗示. externalAssetHosts 是一种对远程设备的明确允许 资产,与页面域分离。 在所有页面到达后,本地预览会运行每个列出的点击或盘旋检查所收集的项目文件,外部请求被屏蔽. 检查只在 expectSelector 变得明显。 预览校验有128 MB 内存预算;报告超出预算的检查 not_verified. 未列入清单的互动依然存在 not_verified; 此模式不承诺服务器支持的行为或未发现的路径 。 进口商还应在写完完整的项目后自行进行预览.
每个 skippedAssets 条目有 URL 、 理由、 内容类型 (unknown 如果没有收到答复,则提及页面和类别: blocked, (中文(简体) ), unsupported_format, (中文(简体) ), size_limit, (中文(简体) ), capture_failure,或 excluded。检查这些条目和 missingAssetUrls 在依赖离线副本之前。 对于困难的导入,请保留一个页面事件 project.html, (中文(简体) ), project.assetMap, (中文(简体) ), project.scripts, (中文(简体) ), skippedAssets,并列出在本地预览中失败的相互作用。 在共享诊断前删除符号和私人 URL .
for await (const event of crawtir.captureUi({
url: 'https://example.com',
limit: 20,
maxDepth: 3,
width: 1440,
height: 900,
excludePaths: ['/private'],
})) {
switch (event.type) {
case 'page':
console.log(event.sequence, event.depth, event.page.url);
console.log(event.page.controls.length, event.page.assets.length);
for (const asset of event.page.assets) {
const bytes = Buffer.from(asset.base64, 'base64'); // Node.js example
console.log(asset.url, asset.contentType, bytes.length);
// Use asset.url to match references in page.html or CSS.
}
if (event.page.missingAssetUrls.length)
console.warn('Uncaptured references:', event.page.missingAssetUrls);
// Persist or transform page.html, page.screenshot, and assets in your app.
break;
case 'page_error':
console.warn(event.url, event.error);
break;
case 'complete':
console.log(event.pages, event.errors, event.discovered);
break;
}
}
活动是 started, (中文(简体) ), page, (中文(简体) ), page_error, (中文(简体) ), heartbeat, (中文(简体) ), complete,严格模式 incomplete。流中输出错误 CrawtirError。 。 。 . limit 缺省至20页并允许长达100页; maxDepth 默认为 3 并允许 0–10 。 Viewport宽为320–1,920像素(默认为1,440),高为480–1,200像素(默认为900). 资产机构上限为每页8 MB和每页40 MB;参考扫描检查为每页最多增加320个URL. page.assetReferences 列出 HTML 和 CSS 引用的 URL, page.missingAssetUrls 列表未引用的引用 page.assets,以及 page.skippedAssets 解释资源失败或过大的原因. resolvedUrl 等于重定向后的最后 URL 或没有重定向时的原始 URL 。 这可以捕捉公共的UI和文件,而不是服务器侧面的行为,认证的页面,或者通过用户交互可以达到的每个状态.
在公共网站上查找线索
searchLeads() 描述搜索业务和目标市场。 Crawtir 计划搜索,发现公共网站,检查与 您提供的 AI 提供者,以及具有源链接的流的限定结果。 覆盖范围取决于现有的搜索来源和可爬行的页面. 领先者是观察到的匹配,而不是身份、当前就业或电子邮件交付的保障.
for await (const event of crawtir.searchLeads({
business: 'We supply event venues and fundraising payment tools to organizations',
location: 'United Kingdom',
limit: 5,
provider: {
name: 'openrouter',
apiKey: process.env.OPENROUTER_API_KEY!,
model: 'openai/gpt-4.1-mini',
},
})) {
switch (event.type) {
case 'plan':
console.log('Searches:', event.plan.searches);
break;
case 'search':
console.log(event.query, event.found);
break;
case 'lead':
console.log(event.lead.name, event.lead.website, event.lead.sourceUrl);
break;
case 'warning':
console.warn(event.source, event.error);
break;
case 'complete':
console.log('Leads:', event.leads, 'Pages used:', event.pages);
break;
}
}
用于 OpenAI, 使用 provider.name: 'openai' 使用您的 OpenAI 密钥和被支持的模型。 供应 provider 打开 每个 SDK或API领先搜索. SDK和API在发送提供者密钥时需要HTTPS. Crawtir 为它的短寿命处理队列加密了该密钥,而不将其存储于PostgreSQL. 保存在您自己的秘密存储中,并避免包含它的伐木请求机构.
| 选项 | 默认 | 含义 |
|---|---|---|
business | 需求 | 描述您的业务销售内容; 20-2 000个字符. |
location | 需求 | 目标国家,地区,或市场; 2–120个字符. |
limit | 10 | 最大合格线索返回; 1–20. |
provider | API 消费者要求 | { name: 'openai' | 'openrouter', apiKey, model }。 。 。 . |
fields | 所有牵头字段 | 每条线索都要包括字段. |
requiredFields | [] | 如果缺少列出的字段, 请丢弃线索 . |
contactPageLimit | 1 | 同一站点联系页在匹配后检查; 0–3. |
流出流出 started, (中文(简体) ), plan, (中文(简体) ), search, (中文(简体) ), warning, (中文(简体) ), lead, (中文(简体) ), heartbeat,以及 complete。 。 。 . plan.searches 显示生成的查询. complete.pages 包括没有成为线索的候选人。 保持流经 complete; SDK如果早结束会扔出. 服务器可以运行任何一种流线方式,最长可达15分钟,因此可以在您的应用程序和倒置代理中进行长寿命的连接.
只返回您需要的字段
fields 控制每个 lead 活动。 选择从 name, (中文(简体) ), website, (中文(简体) ), pageUrl, (中文(简体) ), email, (中文(简体) ), phone, (中文(简体) ), summary, (中文(简体) ), contactSourceUrl, (中文(简体) ), searchQuery, (中文(简体) ), fit, (中文(简体) ), reason,以及 evidence。 。 。 . sourceUrl 总是包括用于核查。 把一块地放进去 requiredFields 以跳过没有该值的匹配;每个所需的字段也必须出现在 fields。 。 。 .
for await (const event of crawtir.searchLeads({
business: 'We provide booking and payment software for event venues',
location: 'Canada',
limit: 10,
fields: ['email'],
requiredFields: ['email'],
contactPageLimit: 2,
provider: {
name: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
model: 'gpt-4.1-mini',
},
})) {
if (event.type === 'lead') {
// Shape: { sourceUrl: string, email: string | null }
console.log(event.lead.email, event.lead.sourceUrl);
}
}
一个 email 是公共页面上观察到的地址。 Crawtir 不验证信箱的发送. requiredFields: ['email'] 不包括没有公共电子邮件的线索;它不运行电子邮件搜索级联。 这个工作流程找到的是企业和公共联系人,而不是一个专门的逐个角色的数据库.
搜索公司索引
searchCompanies() 先前通过线索搜索发现的查询公司记录. 它在共享索引上使用关键字搜索,并且确实 没有 打电话给人工智能供应商。 该指数随着公共商业网站的合格程度而增加;它不是一个完整的网络或个人指数.
const { data, count } = await crawtir.searchCompanies('event venue', 20);
for (const company of data) {
console.log({
name: company.name,
website: company.website,
source: company.sourceUrl,
email: company.email,
emailStatus: company.emailStatus,
firstSeenAt: company.firstSeenAt,
lastSeenAt: company.lastSeenAt,
});
}
console.log('Returned:', count);
查询必须是2 - 200个字符. limit 默认为20,并允许1–50。 一个 IndexedCompany 可包含 id, (中文(简体) ), domain, (中文(简体) ), website, (中文(简体) ), name, (中文(简体) ), summary, (中文(简体) ), email, (中文(简体) ), emailSourceUrl, (中文(简体) ), emailStatus, (中文(简体) ), phone, (中文(简体) ), sourceUrl, (中文(简体) ), sourceTitle, (中文(简体) ), firstSeenAt,以及 lastSeenAt。 。 。 . emailStatus: 'observed' 表示在被爬行的页面上出现电子邮件; 'unavailable' 意味着没有找到公共邮件 . count 是此响应中返回的数字,而不是索引总数.
错误、重复和超时
HTTP 错误和终端流出错误的使用 CrawtirError,与 message数字 status选择 details。网络和中止错误也可能来自运行时间 fetch。 。 。 .
try {
const page = await crawtir.scrape({ url: 'https://example.com' });
console.log(page.title);
} catch (error) {
if (error instanceof CrawtirError) {
console.error('Crawtir request failed:', error.status, error.message);
console.error('Details:', error.details);
} else {
throw error;
}
}
普通类 GET 请求在默认情况下重试瞬态网络故障和HTTP 429、502、503和504,同时进行两次重试并增加延迟。 构造器 retries 改变这个。 写作和流不自动重试,避免重复工作或搜索. 默认构造器 timeout 对于普通请求,是120秒。 流出请求使用至少15分钟的HTTP超时;服务器也执行15分钟的流出最后期限. 对齐您的应用程序和代理超时 .
类型脚本导入
软件包导出 Crawtir, (中文(简体) ), CrawtirError和类型,包括 ScrapeInput, (中文(简体) ), CrawlInput, (中文(简体) ), MapInput, (中文(简体) ), BatchInput, (中文(简体) ), ExtractInput, (中文(简体) ), PageResult, (中文(简体) ), UiCaptureInput, (中文(简体) ), UiCapturePage, (中文(简体) ), UiCaptureEvent, (中文(简体) ), LeadSearchInput, (中文(简体) ), LeadSearchPlan, (中文(简体) ), LeadResult, (中文(简体) ), LeadSearchEvent, (中文(简体) ), LeadField, (中文(简体) ), SelectedLeadResult,以及 IndexedCompany。 。 。 .
import { Crawtir, CrawtirError } from '@crawtir/sdk';
import type { PageResult, LeadSearchEvent, IndexedCompany } from '@crawtir/sdk';
匹配 HTTP 路由、 认证和 OpenAPI 引用, 请访问 /docs 在你的爬行 API部署.