# PythonでWebページをMarkdownに変換

> PythonでWebページをMarkdownに変換:requests、同時実行数上限付きの非同期httpx、バッチジョブ、見出し単位のRAGチャンキング。$0.07/1Kページから、KYC不要。

- URL: https://webreaderapi.com/ja/docs/python/
- 最終更新: 2026-10-22
- 発行者: WebReaderAPI (https://webreaderapi.com)

ほとんどのPythonプロジェクトをカバーする4つのレシピ:requestsで1ページを読み取る、httpxで複数ページを並行して読み取る、リストをバッチジョブに渡す、Markdownをベクトルストア用にチャンク分割する。

**概要 — PythonでWebページをMarkdownに変換するにはどうすればよいですか？**

**WebReaderAPI**を`requests.get("https://webreaderapi.com/api/v1/read", params={"url": ...})`と`Authorization`ヘッダーのキーとともに呼び出します。JSONの応答にはページの本文が`markdown`で入っています。複数ページには、セマフォ付きの`httpx.AsyncClient`またはバッチジョブを使います。1ページ1クレジットで、2026年10月時点で$0.07/1Kページから利用できます。KYC不要、暗号資産で支払い。

## 何をインストールする必要がありますか？

Python 3.9以降とHTTPクライアントが1つ必要です。1ページずつ読み取るスクリプトには`requests`で十分です。`httpx`は多数のページを並行処理する非同期サポートを追加します。当社のパッケージは不要です:APIはプレーンなHTTPSとJSONです。

キーはコードに含めないでください。以下のすべての例と同様に、`WEBREADER_API_KEY`環境変数から読み取り、プロジェクトごとに専用のキーを発行すれば、他のキーに触れずに1つだけを失効できます。

*インストール*

```bash
pip install requests httpx
export WEBREADER_API_KEY="your-key"
```

## requestsで1ページを読み取るにはどうすればよいですか？

`url`と任意のオプションをクエリパラメータとして送信し、HTTPエラーで例外を発生させ、必要なフィールドを読み取ります。この例では本文を保持し、モデル用に20,000文字で上限を設定し、呼び出しにかかったコストを出力します。

*requests:1ページ*

```python
import os

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


def read(url, **options):
    resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
    if resp.status_code != 200:
        error = resp.json()["error"]
        raise RuntimeError(error["code"] + ": " + error["message"])
    return resp.json()


page = read("https://example.com/docs/getting-started", max_chars=20000)
print(page["title"], page["word_count"], "words", page["credits_used"], "credit(s)")
print(page["markdown"][:500])

```

## httpxで複数ページを一度に読み取るにはどうすればよいですか？

`httpx.AsyncClient`を1つと、同時実行数の上限以下に設定した`asyncio.Semaphore`を使います。すべてのアカウントには同時に読み取れるページ数の上限があります。上限はダッシュボードに表示され、サポートで引き上げられます。1ページのエラーで他のページが止まるべきではないため、この例では例外を発生させる代わりに結果と並べてエラーを収集します。

上限を超えると、APIは`429 concurrency_limit`を返します。課金はされませんが、ページは読み取られません。セマフォを上限以下に保つほうが、リトライするより簡単です。

*httpx:最大10ページを同時実行*

```python
import asyncio
import os

import httpx

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


async def read_one(client, sem, url):
    async with sem:
        resp = await client.get(API, params={"url": url, "max_chars": 50000})
    body = resp.json()
    if resp.status_code == 200:
        return url, body, None
    return url, None, body["error"]["code"]


async def read_many(urls, limit=10):
    sem = asyncio.Semaphore(limit)
    async with httpx.AsyncClient(headers=HEADERS, timeout=75) as client:
        return await asyncio.gather(*(read_one(client, sem, u) for u in urls))


if __name__ == "__main__":
    urls = [f"https://example.com/blog/post-{n}" for n in range(1, 21)]
    for url, page, error in asyncio.run(read_many(urls)):
        print(url, "->", error or page["title"])

```

## 代わりにバッチジョブはいつ使うべきですか？

最大100件のURLリストがあり、各ページを準備ができた瞬間に取得する必要がない場合です。バッチジョブは当社側で実行されるため、あなたのスクリプトは接続を開いたままにせず、リトライ処理も行いません。`POST https://webreaderapi.com/api/v1/batch`で開始し、[バッチとクロールのページ](https://webreaderapi.com/ja/docs/crawl/)に示すカーソルループでジョブから結果を収集します。

サイト全体の場合は、代わりにクロールを開始し、sitemapとリンクをたどらせます。同じページに、ページごとに1つの`.md`ファイルを書き出す完全なループがあります。

*バッチジョブの開始*

```python
import os

import requests

urls = [f"https://example.com/changelog/{year}" for year in range(2020, 2027)]
resp = requests.post(
    "https://webreaderapi.com/api/v1/batch",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"urls": urls, "options": {"format": "markdown", "main_content": True}},
    timeout=30,
)
resp.raise_for_status()
print("job:", resp.json()["job_id"])

```

## RAG用にMarkdownをチャンクに分割するにはどうすればよいですか？

まず見出しで分割し、次にサイズで分割します。見出しはトピックが変わる位置を示すため、見出しから始まるチャンクはレトリーバーがマッチしやすくなります。各チャンクのメタデータにページタイトルと見出しパスを保持してください。モデルが正しいセクションを引用するのに役立ちます。

以下の関数は追加のライブラリを必要としません。`#`から`###`の見出しで分割し、その後、長いセクションを空行で分割して文字数予算内に収めます。各チャンクとともに`final_url`を保存し、同じページに至る2つのアドレスが重複を作らないようにします。

*見出しでMarkdownをチャンク化する*

```python
import re


def chunk_markdown(page, max_chars=2000):
    """Split a /read response into chunks with a heading path and the source URL."""
    chunks, path, buf = [], [], []

    def flush():
        text = "\n".join(buf).strip()
        while text:
            part = text[:max_chars]
            cut = part.rfind("\n\n")
            if len(text) > max_chars and cut > max_chars // 2:
                part = part[:cut]
            chunks.append({"text": part.strip(), "section": " > ".join(path), "title": page.get("title"), "source": page["final_url"]})
            text = text[len(part):].strip()
        buf.clear()

    for line in page["markdown"].splitlines():
        m = re.match(r"^(#{1,3}) (.+)", line)
        if m:
            flush()
            level = len(m.group(1))
            path[:] = path[: level - 1] + [m.group(2).strip()]
        buf.append(line)
    flush()
    return chunks

```

## Pythonジョブのコストはいくらですか？

リクエストではなくページを数えます。1クレジット = ブラウザなしでページを1回読み取り。ページのJavaScriptレンダリングにブラウザが必要な場合は2クレジット。失敗したリクエスト、またはサイトのrobots.txtが拒否したリクエストは課金されません。ブラウザを使わずに2,000件のドキュメントページを読むと約2,000クレジットを使用し、これは10,000ページ（$3.75）で5回分以上をカバーします。プリペイドクレジットに有効期限はありません。未使用のページは使うまでアカウントに残りますため、月に1回実行するパイプラインは読んだ分だけを使用します。

## Python：よくある質問

### 公式のPythonパッケージはありますか？

いいえ。このページのコードだけで十分です。WebReaderAPIはプレーンなHTTPS APIであり、`requests`や`httpx`はそれを直接扱えます。

### robots.txtが拒否するページはどう処理すればよいですか？

エラーコードを確認してください。`blocked_by_robots`と`target_refused`は最終的で無料です。記録して続行してください。[エラーページ](https://webreaderapi.com/ja/docs/errors/)には、変化しうるコードのみをリトライするリトライヘルパーがあります。

### JupyterノートブックからAPIを使えますか？

はい。`requests`のレシピはそのまま動作します。ノートブックでは、イベントループがすでに実行されているため、`await read_many(urls)`が`asyncio.run`の代わりになります。

### クライアントのタイムアウトはどれを使うべきですか？

API自体より少し長めにしてください。デフォルトは30秒、最大は60秒なので、クライアント側で75秒にすると遅いサイトとレスポンスのための余裕ができます。

---

WebReaderAPI: WebReaderAPIはAIエージェント向けのWebリーダーAPIで、あらゆる公開WebページをクリーンなMarkdownに変換します。暗号資産で支払い、本人確認書類のアップロードは不要です。$0.07/1Kページから購入できるプリペイドクレジットに有効期限はなく、robots.txtを尊重します。KYC不要 — 身分証もセルフィーも書類も不要。暗号資産で支払い。
