read_result
Baca semula hasil yang terlalu besar untuk dikembalikan sebaris. Apabila JSON sesuatu alat melebihi max_inline_chars, responsnya membawa preview, result_handle dan truncated: true; hantar handle itu ke sini untuk menghiris teks, mencarinya, menelusurinya mengikut baris atau membaca satu laluan JSON — tanpa mengambil semula halaman atau membayar harga alat itu buat kali kedua.
Kes Penggunaan
Cari Bahagian yang Anda Perlukan
Jalankan search untuk tajuk atau frasa, kemudian slice dari offset padanan — dua panggilan yang membaca satu bahagian halaman panjang dan bukannya keseluruhan hasil.
Telusuri Teks Panjang
lines mengembalikan tetingkap baris dengan has_more, jadi dokumen markdown yang besar dibaca dalam tetingkap yang muat dalam konteks anda.
Tarik Satu Medan daripada JSON Besar
json_path membaca satu laluan daripada hasil crawl_deep, batch_scrape atau deep_research yang tersimpan, atau daripada badan terhurai sesuatu fetch_url JSON.
Jangan Sesekali Ambil Semula
Hasil tersimpan ialah hasil yang sudah anda bayar. Membacanya berkos 1 credit setiap panggilan; menjalankan semula alat itu berkos harga penuhnya dan mengunjungi tapak sekali lagi.
Endpoint
/api/v1/tools/read_resultParameters
handle datang daripada respons dengan truncated: true — alat ini tidak pernah mengambil halaman, ia hanya membaca hasil yang sudah anda miliki. Handle luput 1 jam selepas hasil disimpan.| Name | Type | Required | Default | Description |
|---|---|---|---|---|
handle | string | Required | - | `result_handle` daripada respons yang terpotong (`res_` diikuti UUID). Hanya boleh dibaca oleh akaun yang menciptanya, selama 1 jam. Example: res_9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c |
operation | string | Required | - | `slice` mengembalikan julat aksara paparan teks; `search` mencari subrentetan literal tanpa mengira huruf besar kecil (bukan regex) dan mengembalikan setiap padanan dengan konteks; `lines` mengembalikan tetingkap baris; `json_path` membaca satu laluan daripada JSON tersimpan. Example: search |
offset | number | Optional | 0 | `slice`: aksara pertama yang dikembalikan. `lines`: indeks baris pertama yang dikembalikan. Example: 18240 |
length | number | Optional | 10000 | `slice`: bilangan aksara yang dikembalikan (lalai 10,000). `lines`: bilangan baris yang dikembalikan (lalai 200, paling banyak 5,000). Example: 4000 |
query | string | Optional | - | Untuk `search` sahaja, dan wajib di situ: teks literal yang dicari, dipadankan tanpa mengira huruf besar kecil. Example: rate limits |
max_matches | number | Optional | 20 | `search`: bilangan maksimum padanan yang dikembalikan, 1-100. `truncated: true` dalam respons bermakna lebih banyak yang sepadan daripada yang dikembalikan. Example: 5 |
path | string | Optional | - | Untuk `json_path` sahaja, dan wajib di situ: kunci bertitik dan indeks tatasusunan, dalam bentuk titik atau kurungan (`pages.0.url` atau `pages[0].url`); tiada kad bebas, penapis atau hirisan. Dibaca daripada objek hasil tersimpan — atau daripada badan terhurai apabila teks tersimpan ialah JSON, seperti badan `fetch_url`. Example: pages.0.url |
max_inline_chars | number | Optional | 40000 | Jumlah teks terbesar yang dikembalikan sebaris, 1,000-10,000,000 aksara; setiap operasi mengehadkan teks yang dikembalikannya di sini. Bagi `json_path`, `value` yang lebih besar kembali sebagai `value: null` dengan `preview`, `truncated: true` dan amaran untuk menyempitkan laluan. Example: 40000 |
Operasi
Setiap respons membawa handle, tool, operation, view, view_path, total_chars dan expires_at, kemudian medan bagi operasi yang anda minta.
offset, length, text dan has_more. Lalai kepada 10,000 aksara pertama.query, matches (setiap satu dengan offset, length, context_offset dan context — 200 aksara di kedua-dua belah), total_matches dan truncated.first_line, line_count, total_lines, char_offset, lines dan has_more. offset ialah indeks baris pertama, length ialah bilangan baris (lalai 200, paling banyak 5,000).path, value dan value_chars. Melebihi max_inline_chars, nilai digantikan dengan value: null, preview dan truncated: true, dengan amaran untuk menyempitkan laluan.Di mana hasil tersimpan berada
~/.crawlforge/results/ (TTL 1 jam, LRU 200 MB) dan tiada apa-apa dimuat naik. Respons ralat tidak pernah disimpan, dan kerja batch_scrape berkongsi storan yang sama.Contoh Permintaan
cURL
# 1. A scrape whose JSON exceeded max_inline_chars (default 40,000) came back
# with a preview instead of the markdown:
# "truncated": true,
# "result_handle": "res_9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
# "total_chars": 182406
# 2. Search the stored result for the section you need (1 credit)
curl -X POST https://crawlforge.dev/api/v1/tools/read_result \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"handle": "res_9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
"operation": "search",
"query": "rate limits",
"max_matches": 5
}'
# 3. Read the section at the first match offset (1 credit) — no second fetch
curl -X POST https://crawlforge.dev/api/v1/tools/read_result \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"handle": "res_9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
"operation": "slice",
"offset": 18240,
"length": 4000
}'TypeScript
// npm install crawlforge-sdk
import { CrawlForge } from 'crawlforge-sdk';
const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });
// 1. Scrape a long page. Over max_inline_chars (default 40,000 characters of
// JSON) the markdown is replaced by a preview and a result_handle.
const page = await client.scrape({
url: 'https://example.com/docs/api',
formats: ['markdown'],
});
// page.data is untyped in crawlforge-sdk 0.1 — a truncated result carries the
// handle fields shown in the cURL tab instead of the markdown.
const scraped = page.data as
| { truncated: true; result_handle: string; total_chars: number }
| { truncated?: false; formats: { markdown: string } };
if (scraped.truncated) {
const { result_handle, total_chars } = scraped;
console.log('Stored ' + total_chars + ' characters as ' + result_handle);
// 2. Search the stored markdown for the section you need (1 credit).
const found = await client.readResult({
handle: result_handle,
operation: 'search',
query: 'rate limits',
max_matches: 5,
});
// result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
const { matches } = found.data as { matches: { offset: number }[] };
// 3. Slice from the first match offset (1 credit) — no second fetch.
const [first] = matches;
if (first) {
const section = await client.readResult({
handle: result_handle,
operation: 'slice',
offset: first.offset,
length: 4000,
});
const { text, has_more } = section.data as { text: string; has_more: boolean };
console.log(text);
console.log('More after this slice:', has_more);
}
} else {
console.log(scraped.formats.markdown); // small enough to arrive inline
}Python
# pip install crawlforge
from crawlforge import CrawlForge
client = CrawlForge() # reads CRAWLFORGE_API_KEY
# 1. Scrape a long page. Over max_inline_chars (default 40,000 characters of
# JSON) the markdown is replaced by a preview and a result_handle.
page = client.scrape(url='https://example.com/docs/api', formats=['markdown'])
# result.data is a plain dict — its shape is the Response Example below.
if page.data.get('truncated'):
handle = page.data['result_handle']
print(f"Stored {page.data['total_chars']} characters as {handle}")
# 2. Search the stored markdown for the section you need (1 credit).
found = client.read_result(
handle=handle,
operation='search',
query='rate limits',
max_matches=5,
)
# 3. Slice from the first match offset (1 credit) - no second fetch.
if found.data['matches']:
first = found.data['matches'][0]
section = client.read_result(
handle=handle,
operation='slice',
offset=first['offset'],
length=4000,
)
print(section.data['text'])
print('More after this slice:', section.data['has_more'])
else:
print(page.data['formats']['markdown']) # small enough to arrive inlineContoh Respons
{ "success": true, "data": { "handle": "res_9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c", "tool": "scrape", "operation": "search", "view": "text", "view_path": "markdown", "total_chars": 182406, "expires_at": "2026-09-05T15:42:10.000Z", "query": "rate limits", "matches": [ { "offset": 18240, "length": 11, "context_offset": 18040, "context": "…request. Every plan is metered per API key.\n\n## Rate limits\n\nEach key may make one request per second on the Free plan…" }, { "offset": 61377, "length": 11, "context_offset": 61177, "context": "…returns 429 with a Retry-After header; see the rate limits table above for the per-plan ceilings…" } ], "total_matches": 2, "truncated": false }, "credits_used": 1, "credits_remaining": 998, "processing_time": 42}data.handleHandle yang anda hantar, dikembalikan semuladata.toolAlat yang menghasilkan hasil tersimpan itudata.view`text` apabila operasi membaca paparan teks (markdown bagi scrape, badan bagi fetch_url); `json` bagi `json_path`data.view_pathMedan hasil asal yang menjadi paparan teksdata.total_charsSaiz paparan teks tersimpan, dalam aksaradata.expires_atBila hasil tersimpan dipadamkan — 1 jam selepas ia disimpandata.matchesSatu entri bagi setiap padanan: `offset` dan `length` merujuk paparan teks; `context` membawa sehingga 200 aksara di kedua-dua belah, bermula pada `context_offset`data.total_matchesBerapa banyak padanan wujud kesemuanya; `truncated` bernilai true apabila lebih banyak yang sepadan daripada yang dibenarkan `max_matches`credits_usedCredits yang ditolak bagi permintaan ini (1 setiap bacaan)credits_remainingBaki credits andaPengendalian Ralat
Input Tidak Sah (400 Bad Request)
handle tiada, operation bukan salah satu daripada slice, search, lines atau json_path, search dihantar tanpa query, json_path tanpa path, atau max_matches berada di luar julat 1-100 (VALIDATION_ERROR).
Laluan Tidak Ditemui (400 Bad Request)
json_path tidak dapat menyelesaikan path (PATH_NOT_FOUND); ralat itu menamakan kunci yang tersedia di tempat ia berhenti. Credits tidak ditolak.
Hasil Tidak Ditemui (404 Not Found)
Handle hasil tidak dikenali atau telah luput (RESULT_NOT_FOUND) — hasil disimpan selama 1 jam dan hanya boleh dibaca oleh akaun yang menciptanya. Credits tidak ditolak.
Storan Tidak Tersedia (503 Service Unavailable)
Storan hasil tidak dapat dicapai (STORAGE_UNAVAILABLE). Cuba semula sebentar lagi; tiada caj bagi bacaan yang tidak selesai.
Credits Tidak Mencukupi (402 Payment Required)
Akaun anda tidak mempunyai credits yang mencukupi. Beli lebih banyak credits atau naik taraf pelan anda.
Had Kadar Dilampaui (429 Too Many Requests)
Anda telah melampaui had kadar pelan anda. Tunggu sebentar atau naik taraf pelan anda untuk had yang lebih tinggi.
search, kemudian slice pada offset padanan, membaca satu bahagian dengan 2 credits. Menelusuri keseluruhan hasil dalam hirisan 10,000 aksara berkos 1 credit setiap hirisan, dan menjalankan semula alat itu berkos harga penuhnya ditambah satu lagi ambilan tapak.Kos Credits
Pelan Free: 1,000 credits sekali sahaja = 1,000 permintaan
Pelan Hobby: 5,000 credits/bulan = 5,000 permintaan (USD 19/bulan)
Pelan Professional: 50,000 credits/bulan = 50,000 permintaan (USD 99/bulan)
Pelan Business: 250,000 credits/bulan = 250,000 permintaan (USD 399/bulan)
Alat Berkaitan
result_handle — max_inline_chars menetapkan berapa banyak yang tiba sebaris (2 credits)json_path membaca satu halaman daripada perayapan tersimpan (4 credits)json_path membaca badan terhurainya (1 credit)batch_scrape; hasil tersimpan kelompok itu berkongsi storan 1 jam yang sama (1 credit)