API リファレンス
paprika_client の全公開関数。
Session は Page を継承するので page.* はセッションでもそのまま使えます。
接続
async_paprika.connect(base_url=None, *, token=None, timeout=180.0) → PaprikaClient
ハブへの接続。接続先は 引数 → PAPRIKA_HUB → http://localhost:8000。
async with async_paprika.connect() as cli:
...with sync_paprika.connect() as cli:
...use Paprika\Client\Paprika;
$cli = Paprika::connect(); // PAPRIKA_HUB or http://localhost:8000
// ...同期版(sync_paprika)
async/await を使えない・使いたくない場面(簡単なスクリプト、ノートブック、既存の同期コード)向けに、
非同期 API を 1:1 でブロッキングに写した同期ファサードがあります。裏でバックグラウンドの
asyncio ループに橋渡しするだけなので、メソッド名・引数・戻り値は async 版と同一(await を外すだけ)。
例1: セッションを動かす
Hacker News のトップ記事をクリックして、辿り着いた先の URL とタイトルを表示します。
from paprika_client import sync_paprika
with sync_paprika.connect() as cli: # await 不要
with cli.session("https://news.ycombinator.com") as page:
page.locator(".athing .titleline > a").first.click()
st = page.state()
print("url: ", st["url"])
print("title:", st["title"])
実行結果(例):
url: https://www.anthropic.com/research/glasswing-initial-update
title: Project Glasswing: An initial update \ Anthropic
例2: fetch で画像を一括取得
Wikipedia の記事を fetch ジョブで丸ごと取得し、保存された画像の URL を表示します。
from paprika_client import sync_paprika
with sync_paprika.connect() as cli:
job = cli.fetch("https://en.wikipedia.org/wiki/Cat", scroll=True)
imgs = cli.job_images(job["job_id"])
print("status:", job["status"])
print("images:", len(imgs))
print("first 3:")
for u in imgs[:3]:
print(" ", u)
実行結果(例):
status: completed
images: 49
first 3:
http://paprika.lan:8000/jobs/08dbe3379087/assets/120px-Felis_chaus_-_…jpg
http://paprika.lan:8000/jobs/08dbe3379087/assets/120px-Gustav_chocolate.jpg
http://paprika.lan:8000/jobs/08dbe3379087/assets/120px-Orange_tabby_cat_…jpg
本リファレンスの cli.* / page.* / loc.* がそのまま(同期で)使えます。
connect(base_url=None, *, token=None, timeout=180.0, auto_start=True) が既定でループを起動します。
既定では各アクションが [paprika] page.X(...) 形式でログに流れます(無効化は PAPRIKA_CLIENT_ACTION_LOG=0)。
PHP SDK (Phase 1)
PHP からも同じハブを叩けます。同期・外部依存なし (ext-curl のみ)・PHP 8.1+。
Composer パッケージ paprika/client。命名は Python 版を snake_case → camelCase
に直したもの (例: job_images → jobImages)。
現在の Phase 1 は Job API + Session ライフサイクル。 Page/Locator/walk は Phase 2 で対応予定です。
インストール
composer require paprika/client
例: fetch ジョブを投げて画像を集める
<?php
require 'vendor/autoload.php';
use Paprika\Client\Paprika;
$cli = Paprika::connect(); // PAPRIKA_HUB or http://localhost:8000
$job = $cli->fetch('https://en.wikipedia.org/wiki/Cat', scroll: true);
echo "status: {$job['status']}\n";
foreach ($cli->jobImages($job['job_id']) as $u) {
echo $u, "\n";
}
例: ライブセッションを開く
use Paprika\Client\Paprika;
use Paprika\Client\Session;
$cli = Paprika::connect();
$cli->session('https://example.com', function (Session $sess) use ($cli) {
echo "noVNC: ", $cli->baseUrl() . $sess->novncUrl, "\n";
// Phase 2: $sess->goto(...), $sess->locator(...) ...
});
Phase 1 で使える $cli->* メソッド (Python 版と1:1)
| PHP メソッド | 説明 / Python 版 |
|---|---|
$cli->health() | 疎通確認 / cli.health() |
$cli->listWorkers() / listSessions() | 一覧 / list_workers / list_sessions |
$cli->createJob($url, $opts) | POST /jobs / create_job |
$cli->fetch($url, $opts = [], wait: true, ...) | fetch 投入+完了待ち / fetch |
$cli->getJob($id) / listJobs() / jobResult($id) | 状態 / get_job / list_jobs / job_result |
$cli->waitJob($id, pollInterval: 2.0, timeout: 600.0) | 終端まで待機 / wait_job |
$cli->cancelJob($id) / deleteJob($id) | 中止 / 削除 |
$cli->jobAssets($id, kind: null, absolute: true, details: false) | asset 一覧 / job_assets |
$cli->jobImages($id) | 画像ショートカット / job_images |
$cli->downloadJobAssets($id, $destDir, kind: 'image') | ローカル保存 / download_job_assets |
$cli->openSession(initialUrl: null, ...) → Session | セッション確保 / open_session |
$cli->session($url, $closure, $kwargs = []) | クロージャ自動 close 形 / Python の async with cli.session(...) |
Session の Phase 1 サーフェス
- プロパティ (readonly):
$sess->sessionId/workerId/laneIdx/novncUrl $sess->close()—DELETE /sessions/{id}(idempotent / 安全)$sess->detach()—POST /sessions/{id}/detach。クロージャ form の自動 close をスキップ- (Phase 2)
goto / click / fill / locator / screenshot / state / outline / ...
例外
| クラス | 用途 |
|---|---|
Paprika\Client\PaprikaError | HTTP/トランスポート系エラー。$e->statusCode で HTTP コード取得 (transport なら null) |
Paprika\Client\PaprikaActionError | Page/Locator 系の失敗 (Phase 2 で本格使用) |
PaprikaClient (cli.*)
| メソッド | 説明 |
|---|---|
cli.health() → dict | 疎通確認 |
cli.list_workers() → list | 接続中ワーカー一覧 |
cli.list_sessions() → list | セッション一覧 |
cli.session(url=None, **kw) | セッションを開く(async with / await)。kw: parent_job_id / worker_id / lane_hint / idle_ttl_s / absolute_ttl_s / use_profile |
cli.open_session(...) → Session | 手動でセッション確保(await page.close() で解放) |
Job ライフサイクル
| メソッド | 説明 |
|---|---|
cli.create_job(url, **opts) → dict | POST /jobs。投入のみ。opts は JobOptions(mode / scroll / goal / use_profile / cookies_from …) |
cli.fetch(url, *, wait=True, poll_interval=2.0, timeout=600.0, scroll=True, **opts) → dict | fetch 投入 + 完了待ち。wait=False で投げっぱなし |
cli.get_job(id) → dict | 現在の状態(status / progress …) |
cli.list_jobs() → list | 全ジョブ(新しい順) |
cli.wait_job(id, *, poll_interval=2.0, timeout=600.0) → dict | 終了状態まで待つ |
cli.job_result(id) → dict | 最終結果(assets / links / 最終URL) |
cli.cancel_job(id) / delete_job(id) → dict | 中止 / 削除 |
asset(画像・動画)取得
| メソッド | 説明 |
|---|---|
cli.job_assets(id, *, kind=None, absolute=True, details=False) → list | キャプチャ済み asset 一覧。kind=image/video/audio/other/None、details=メタ付き dict |
cli.job_images(id, **kw) → list | job_assets(kind="image") のショートカット |
cli.download_job_assets(id, dest_dir, *, kind="image") → list[str] | ディスクに保存。保存パス一覧を返す |
Page — ナビゲーション・操作
プロパティ(I/O なし): page.url / session_id / worker_id / lane_idx / novnc_url / page_id。
| メソッド | 説明 |
|---|---|
page.goto(url) → dict | ページ遷移 |
page.back() / forward() / history_first() / reload() | 履歴移動・再読み込み(境界で安全) |
page.click(selector) → dict | クリック。[@N] は [data-paprika-id="N"] に展開 |
page.fill(selector, value) → dict | input/textarea に値セット(input/change 発火) |
page.press(key, *, count=1, modifiers=None) → dict | キー押下("Enter" / modifiers=["Ctrl"]) |
page.type(text) → dict | フォーカス要素に文字挿入 |
page.scroll(direction="down", pixels=800) → dict | スクロール |
page.hover / dblclick / focus / scroll_into_view_if_needed (selector, *, index=0) → bool | 入力デバイス(合成イベント) |
page.select_option(selector, value, *, index=0) → bool | <select> を選択 |
page.check / uncheck (selector, *, index=0) → bool | チェック ON/OFF |
page.set_input_files(selector, files) → dict | ファイルアップロード(CDP)。files はパス or リスト |
await page.goto("https://example.com")
await page.fill("#email", "user@example.com")
await page.press("Enter")
await page.set_input_files("input[type=file]", ["a.jpg", "b.jpg"])page.goto("https://example.com")
page.fill("#email", "user@example.com")
page.press("Enter")
page.set_input_files("input[type=file]", ["a.jpg", "b.jpg"])Page — 取得・待機・状態
| メソッド | 説明 |
|---|---|
page.text_content / inner_text / inner_html / input_value (selector, *, index=0) | テキスト・HTML・値 |
page.get_attribute(selector, name, *, index=0) | 属性値 |
page.count(selector) → int | 一致要素数 |
page.is_visible / is_checked / is_enabled / is_disabled / is_editable (selector, *, index=0) → bool | 状態判定 |
page.exists(selector) → bool | 存在チェック(確定的・LLM不要) |
page.wait_for_selector(selector, *, state="visible", timeout=30.0) → bool | 出現/消失待ち。state=attached/detached/visible/hidden |
page.wait_for(*, seconds=None, ms=None) → None | 単純待機 |
page.state() → dict | {url, title, lane_idx, visited_count} |
page.title() → str / page.outline() → str | タイトル / 要素一覧([@N] 付き) |
page.links(*, urls_only=False) → list | 全 <a href> 絶対URL |
page.visited_urls() → list[str] | 踏んだURL |
page.screenshot(*, path=None) → bytes | ビューポート PNG |
Page — JS 実行・ロケータ生成
page.evaluate(expression, *, await_promise=False) → 値
任意 JS を実行し評価値を返す(JSON 化可能な値のみ)。取得・待機・入力系はこれが土台。
title = await page.evaluate("document.title")
data = await page.evaluate("fetch('/api').then(r=>r.json())", await_promise=True)title = page.evaluate("document.title")
data = page.evaluate("fetch('/api').then(r=>r.json())", await_promise=True)evaluate は Page サーフェスの一部として Phase 2 に含まれます)。| ロケータ生成 | 意味 |
|---|---|
page.locator(selector) → Locator | CSS セレクタ |
page.get_by_text(text) → Locator | 可視テキスト一致 |
page.get_by_role(role, *, name=None) → Locator | [role=] |
page.get_by_test_id / get_by_placeholder / get_by_title / get_by_alt_text (text) → Locator | 属性セレクタ |
Page — 収集・Cookie・LLM・永続状態
| メソッド | 説明 |
|---|---|
page.capture(label="capture") → dict | HTML + スクショ + outline を保存 |
page.assets(*, kind="image", absolute=True, refresh=True, details=False) → list | このセッションでキャプチャ済みの asset(要 parent_job_id) |
page.save_assets(dest_dir, *, kind="image", refresh=True) → list[str] | ↑をディスク保存 |
page.download_video(url=None, *, referer=None, timeout_s=1800) → dict | yt-dlp で動画取得 |
page.cookies(*, host=None, all_cookies=False) → dict | 現在の Cookie |
page.save_cookies_to_host(*, host=None, notes=None, all_cookies=False) → dict | Cookie を Host レジストリへ保存 |
page.network(*, since=0.0) → dict | メディアのネットワークログ |
page.ask(question, *, engine="auto") → bool | LLM に yes/no 質問 |
page.agent(goal, *, max_steps=5, engine="auto") → dict | vision/LLM エージェントに委譲 |
page.get_state(key) / set_state(key, value) | 親 job に紐づく永続データ(要 parent_job_id) |
page.solve_cloudflare(*, timeout_s=25.0) → dict | Cloudflare チャレンジを待つ/通す |
page.resize_window(width, height) → dict | ウィンドウサイズ変更 |
Page — タブ・ライフサイクル
| メソッド | 説明 |
|---|---|
page.new_page(url) / open(url) → Page | 新規タブ(switch=True で既定に) |
page.pages() → list[Page] | 全タブ |
page.switch() → dict | このタブを前面に |
page.close() → None | タブを閉じる(最後の1枚ならセッション終了) |
page.keepalive(*, idle_ttl_s=120, absolute_ttl_s=86400) → HandoffInfo | スクリプト終了後も残し noVNC で人手に引き継ぐ(別名 detach) |
Session 固有
Session は Page + 複数タブ操作の拡張:
- シーケンス操作:
len(sess)/sess[i]/for t in sess sess.front/front_index/current(プロパティ)— 前面タブsess.refresh()→ list[Page] — タブ一覧を再取得するsess.switch(idx=None)→ dict —idxのタブを前面にsess.close_popups()→ int — 既定タブ以外(popup)を全部閉じる
await sess[-1].close() は使わないこと(セッション全体を殺すことがある)。sess.close_popups() を使う。Locator
page.locator(sel) / get_by_*() が返す。解決はアクション時。
| メソッド | 説明 |
|---|---|
loc.click() / fill(v) / press(k) / type(t) | 操作 |
loc.hover() / dblclick() / focus() / check() / uncheck() / select_option(v) / set_input_files(f) / scroll_into_view_if_needed() | 入力デバイス |
loc.text_content() / inner_text() / inner_html() / input_value() / get_attribute(name) | 取得 |
loc.is_visible() / is_checked() / is_enabled() / is_disabled() / is_editable() → bool | 状態 |
loc.nth(i) / first / last / count() / all() | チェーン |
loc.wait_for(*, state="visible", timeout=30.0) → bool | この要素が state になるまで待つ |
rows = page.locator(".item")
for r in await rows.all():
print(await r.get_attribute("data-id"))
await rows.first.click()rows = page.locator(".item")
for r in rows.all():
print(r.get_attribute("data-id"))
rows.first.click()$page->locator(...)->first()->click() を実装予定)。サイト巡回(walk / Walker)
「サイト X のページを N 件巡回」のようなクロールを、キュー・重複除去・ドメイン/パスのフィルタ・
オフスコープ redirect 対応まで込みで回す高レベルヘルパー。手書きのループより堅牢です。
walk(page, **opts) は Visit を yield する非同期イテレータ(クラス版は Walker)。
from paprika_client import async_paprika, walk
async with async_paprika.connect() as cli:
async with cli.session("https://example.com", parent_job_id="crawl") as page:
async for visit in walk(page, target_pages=50, same_domain=True):
print(visit.n, visit.depth, visit.url)
await page.save_assets("out/images") # 各ページで画像保存などasyncio.run() で
上の async 例をラップしてください(または walk 部分だけ async で書き、結果を集めてから同期処理に戻す)。Visit は n / url / requested_url / depth /
outline / page を持ちます(page はそのページに居る Page)。
| 主なオプション | 既定 | 説明 |
|---|---|---|
start_url | 現在地 | 巡回の起点 |
target_pages | 100 | 訪問ページ数の上限 |
same_domain / allowed_domains | True / — | ドメイン制限 |
allow_paths / deny_paths / deny_defaults | — / — / True | パスの許可・除外(既定の除外パターンあり) |
order | "bfs" | 探索順(bfs / dfs) |
max_depth | — | リンク深さの上限 |
per_page_timeout_s | 30.0 | 1 ページあたりの上限秒 |
persist_state | True | 進捗を parent job に永続化(attempt 跨ぎ再開) |
host_dedup | False | ホスト横断の既訪 URL 重複除去 |
ワンショットヘルパー
1 動作だけしてセッションを閉じる糖衣です。インポートは from paprika_client import snapshot, outline, state, run です。
| 関数 | 説明 |
|---|---|
await snapshot(url, *, wait=2.0, full_page=False, path=None) → bytes | 開いて PNG |
await outline(url, *, wait=2.0) → str | outline 文字列 |
await state(url, *, wait=2.0) → dict | url/title… |
await run(actions, *, initial_url=None) → dict | act.* のアクション列を実行 |
例外
| 例外 | 発生条件 |
|---|---|
PaprikaError | HTTP レベルのエラー(404 / 5xx / ネットワーク) |
PaprikaActionError | 200 だが action が NO_MATCH / ERR: を返した(.status に生文字列) |