Jawaban singkat
Bagaimana cara crawl situs web ke Markdown dengan WebReaderAPI?
Kirim URL awal ke POST https://webreaderapi.com/api/v1/crawl dengan halaman limit. WebReaderAPI membaca situs di latar belakang, hanya domain yang sama, mengikuti sitemap, robots.txt, dan Crawl-delay-nya, hingga 10.000 halaman per job. Ambil halaman Markdown dari job, satu halaman hasil setiap kali. Setiap halaman yang dibaca berbiaya 1 kredit (2 dengan browser), mulai dari US$0,07/1K halaman per Oktober 2026. Tanpa KYC; bayar dengan kripto.
Job sekilas
| Batch | Hingga 100 URL per batch job: POST https://webreaderapi.com/api/v1/batch |
|---|---|
| Crawl | Crawl satu situs web per job, hingga 10.000 halaman, mengikuti sitemap, robots.txt dan Crawl-delay-nya: POST https://webreaderapi.com/api/v1/crawl |
| Hasil | GET https://webreaderapi.com/api/v1/jobs/{job_id}, lalu ?cursor=… untuk halaman hasil berikutnya |
| Penagihan | Setiap halaman yang dibaca ditagih seperti panggilan /read; halaman yang dilewati oleh robots.txt dan halaman yang gagal tidak berbiaya |
| Cakupan crawl | Satu domain; tautan ke domain lain dicantumkan tetapi tidak dibaca |
| Batalkan job | Tidak tersedia di v1: setel limit ke jumlah halaman maksimum yang siap Anda bayar |
Mulai job batch
POST/api/v1/batch
Membaca hingga 100 URL di latar belakang dengan opsi yang sama. Opsi menggunakan nama dan nilai dari /read. Jawabannya adalah ID job; nilai bersifat ilustratif.
Autentikasi: API key di header Authorization: Bearer API_KEY.
Request body
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
urls | array of strings | Ya | 1 hingga 100 URL http atau https. Duplikat dibaca sekali. |
options | object | Tidak | Parameter /read apa pun kecuali url: format, main_content, render, include_links, include_images, country, max_chars, timeout. |
{
"urls": [
"https://example.com/blog/post-1",
"https://example.com/blog/post-2",
"https://example.org/news/launch"
],
"options": {
"format": "markdown",
"max_chars": 50000
}
}Response 202 Accepted
{
"job_id": "job_5c1e8a90d2"
}Contoh kode
curl -s "https://webreaderapi.com/api/v1/batch" \
-H "Authorization: Bearer $WEBREADER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}}'import os
import requests
resp = requests.post(
"https://webreaderapi.com/api/v1/batch",
headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
json={"urls": ["https://example.com/blog/post-1", "https://example.com/blog/post-2"], "options": {"format": "markdown"}},
timeout=30,
)
print(resp.json()["job_id"])const res = await fetch('https://webreaderapi.com/api/v1/batch', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ urls: ['https://example.com/blog/post-1', 'https://example.com/blog/post-2'], options: { format: 'markdown' } }),
});
console.log((await res.json()).job_id);Mulai job crawl
POST/api/v1/crawl
Membaca satu website dari URL awal, breadth first. Crawler tetap berada di domain URL awal, menggunakan sitemap yang disebut di robots.txt atau yang ditemukan di /sitemap.xml, serta mematuhi robots.txt dan Crawl-delay. Nilai-nilai bersifat ilustratif.
Autentikasi: API key di header Authorization: Bearer API_KEY.
Request body
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
url | string | Ya | Halaman awal, misalnya halaman beranda situs dokumentasi. |
limit | integer | Tidak | Jumlah maksimum halaman yang dibaca, hingga 10.000. Job berhenti saat mencapai jumlah ini. |
max_depth | integer | Tidak | Jumlah maksimum langkah tautan menjauh dari URL awal. |
include_paths | array of strings | Tidak | Pola path sederhana yang dipertahankan, misalnya /docs/*. |
exclude_paths | array of strings | Tidak | Pola path sederhana yang dilewati, misalnya /blog/tag/*. |
options | object | Tidak | Parameter /read apa pun kecuali url, diterapkan ke setiap halaman. |
{
"url": "https://docs.example.com/",
"limit": 500,
"max_depth": 3,
"include_paths": [
"/docs/*"
],
"exclude_paths": [
"/docs/archive/*"
],
"options": {
"format": "markdown"
}
}Response 202 Accepted
{
"job_id": "job_8b27f41c0e"
}Contoh kode
curl -s "https://webreaderapi.com/api/v1/crawl" \
-H "Authorization: Bearer $WEBREADER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]}'import os
import requests
resp = requests.post(
"https://webreaderapi.com/api/v1/crawl",
headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
json={"url": "https://docs.example.com/", "limit": 500, "include_paths": ["/docs/*"]},
timeout=30,
)
print(resp.json()["job_id"])const res = await fetch('https://webreaderapi.com/api/v1/crawl', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://docs.example.com/', limit: 500, include_paths: ['/docs/*'] }),
});
console.log((await res.json()).job_id);Ambil status dan hasil job
GET/api/v1/jobs/{job_id}
Mengembalikan status job dan hasil berikutnya yang sudah siap. Setiap item results berupa respons /read lengkap atau {url, error} untuk halaman yang tidak dapat dibaca. Jika next_cursor ada, panggil lagi dengan cursor diisi nilainya; jika tidak ada, belum ada hasil lain yang siap. Nilai-nilai bersifat ilustratif.
Autentikasi: API key di header Authorization: Bearer API_KEY.
Parameter
| Nama | Di | Tipe | Wajib | Deskripsi |
|---|---|---|---|---|
job_id | path | string | Ya | ID yang dikembalikan oleh /batch atau /crawl. |
cursor | query | string | Tidak | Nilai next_cursor dari panggilan sebelumnya, untuk mendapatkan hasil berikutnya. |
Response 200
{
"job_id": "job_8b27f41c0e",
"status": "running",
"results": [
{
"url": "https://docs.example.com/docs/install",
"final_url": "https://docs.example.com/docs/install",
"status_code": 200,
"rendered": false,
"credits_used": 1,
"title": "Install",
"markdown": "# Install\n\nRun the installer...",
"word_count": 418
},
{
"url": "https://docs.example.com/docs/private",
"error": {
"code": "blocked_by_robots",
"message": "robots.txt disallows this page for WebReaderAPI."
}
}
],
"next_cursor": "c_000002",
"credits_used": 1
}Contoh kode
curl -sG "https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e" \
-H "Authorization: Bearer $WEBREADER_API_KEY" \
-d cursor=c_000002import os
import requests
resp = requests.get(
"https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e",
headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
params={"cursor": "c_000002"},
timeout=30,
)
job = resp.json()
print(job["status"], len(job["results"]), job.get("next_cursor"))const res = await fetch('https://webreaderapi.com/api/v1/jobs/job_8b27f41c0e?cursor=c_000002', {
headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
});
const job = await res.json();
console.log(job.status, job.results.length, job.next_cursor);Bagaimana cara menunggu job selesai?
Poll /jobs/{job_id} dan simpan cursor. Proses hasil yang Anda terima, lalu panggil lagi dengan cursor diisi next_cursor. Jika next_cursor tidak ada dan status adalah done, Anda sudah mendapatkan semuanya; jika tidak ada dan job masih running, tunggu lalu tanyakan lagi dengan cursor yang sama.
Mulai polling setiap 2 detik dan gandakan jeda hingga 30 detik selama tidak ada hasil baru yang masuk. Crawl yang mematuhi Crawl-delay sebuah situs bisa memakan waktu, jadi menunggu lama itu normal dan tidak memakan biaya.
import os
import pathlib
import re
import time
import requests
JOBS = "https://webreaderapi.com/api/v1/jobs"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}
def save_job(job_id, folder="pages"):
out = pathlib.Path(folder)
out.mkdir(exist_ok=True)
cursor, wait, saved = None, 2, 0
while True:
params = {"cursor": cursor} if cursor else {}
job = requests.get(f"{JOBS}/{job_id}", headers=HEADERS, params=params, timeout=30).json()
for item in job["results"]:
if "error" in item:
print("skipped", item["url"], item["error"]["code"])
continue
name = re.sub(r"[^a-z0-9]+", "-", item["final_url"].lower()).strip("-")[:120]
(out / f"{name}.md").write_text(item["markdown"], encoding="utf-8")
saved += 1
if job.get("next_cursor"):
cursor, wait = job["next_cursor"], 2
continue
if job["status"] == "done":
return saved
time.sleep(wait)
wait = min(wait * 2, 30)
if __name__ == "__main__":
print(save_job("job_8b27f41c0e"), "pages saved")
Halaman mana yang dibaca oleh crawl?
Crawl dimulai dari URL Anda dan bergerak keluar satu langkah tautan setiap kali, breadth first, hingga max_depth. Crawl juga membaca sitemap situs, dari alamat yang diberikan di robots.txt atau dari /sitemap.xml, untuk menemukan halaman yang hanya ditunjuk sedikit tautan.
- Hanya domain yang sama. Tautan ke domain lain dicantumkan di hasil saat Anda meminta
include_links, tetapi tidak dibaca. - Filter path.
include_pathsdanexclude_pathsmenerima pola sederhana seperti/blog/*. - Satu salinan per halaman. Jika situs mendeklarasikan canonical URL, halaman yang dicapai melalui beberapa alamat hanya dibaca sekali.
- Batas keras. Job berakhir saat telah membaca
limithalaman.
Bagaimana crawl menghormati situs?
Setiap request membawa User-Agent WebReaderAPI/1.0 (+https://webreaderapi.com/bot/), dan crawler mengikuti aturan robots.txt untuk WebReaderAPI, atau untuk semua robot bila tidak ada yang menyebutkannya. Halaman yang tidak diizinkan dilewati dan muncul di results dengan error blocked_by_robots; halaman tersebut tidak memakan biaya.
Jika robots.txt menetapkan Crawl-delay, crawler menunggu selama itu di antara dua request ke situs. Jika suatu situs mendeklarasikan Content-Signal: ai-input=no di robots.txt-nya, kami tidak membaca halaman tersebut untuk Anda. Jika suatu situs menolak permintaan kami, kami mengembalikan jawabannya: kami tidak pernah menyelesaikan CAPTCHA, masuk ke akun, atau mencoba mengatasi blokir atau paywall.
Berapa biaya sebuah crawl?
Setiap halaman yang dibaca memakan biaya seperti panggilan /read: 1 kredit, 2 jika halaman membutuhkan browser, ditambah 10 dengan country. Halaman yang dilewati dan gagal gratis. credits_used pada job menjumlahkan apa yang telah ditagih sejauh ini.
Situs dokumentasi 500 halaman yang dibaca tanpa browser menggunakan sekitar 500 kredit, yang ditanggung berkali-kali lipat oleh paket 10.000 halaman (US$3,75). Karena job tidak dapat dibatalkan di v1, limit adalah batas pengeluaran Anda: atur ke jumlah halaman maksimum yang siap Anda bayar.
Batch dan crawl: pertanyaan umum
Haruskah saya memakai /batch atau banyak panggilan /read?
Gunakan /batch bila Anda sudah memiliki URL-nya dan tidak perlu setiap jawaban sekaligus. Ini menghindarkan Anda dari mengelola concurrency dan retry. Gunakan /read bila agent membutuhkan satu halaman sekarang.
Berapa lama hasil job disimpan?
Ambil segera setelah siap. Hasil menunggu sampai Anda mengambilnya; setelah terkirim, tidak ada salinan konten halaman yang disimpan, jadi simpan sendiri apa yang Anda butuhkan.
Bisakah crawl mengikuti tautan ke website lain?
Tidak. Crawl membaca satu domain. Domain lain muncul sebagai tautan saat Anda memintanya, dan Anda dapat mengirim URL tersebut ke /batch jika ingin dibaca.
Bisakah saya menghentikan crawl yang sudah berjalan?
Tidak di v1. Job berhenti pada limit halaman, jadi pilih batas yang sesuai anggaran Anda. Halaman yang sudah dibaca tetap ditagih; halaman yang tidak pernah dibaca tidak memakan biaya.