Files
AI/참고/firecrawl-main/apps/python-sdk/firecrawl/v2/methods/aio/browser.py
2026-05-12 19:40:31 +09:00

180 lines
5.8 KiB
Python

"""
Async browser session methods for Firecrawl v2 API.
Provides async create, execute, delete, and list operations for browser sessions.
"""
from typing import Any, Dict, Literal, Optional
from ...types import (
BrowserCreateResponse,
BrowserExecuteResponse,
BrowserDeleteResponse,
BrowserListResponse,
)
from ...utils.http_client_async import AsyncHttpClient
def _normalize_browser_create_response(payload: Dict[str, Any]) -> Dict[str, Any]:
out = dict(payload)
if "cdpUrl" in out and "cdp_url" not in out:
out["cdp_url"] = out["cdpUrl"]
if "liveViewUrl" in out and "live_view_url" not in out:
out["live_view_url"] = out["liveViewUrl"]
if "interactiveLiveViewUrl" in out and "interactive_live_view_url" not in out:
out["interactive_live_view_url"] = out["interactiveLiveViewUrl"]
if "expiresAt" in out and "expires_at" not in out:
out["expires_at"] = out["expiresAt"]
return out
def _normalize_browser_list_response(payload: Dict[str, Any]) -> Dict[str, Any]:
out = dict(payload)
if "sessions" in out and isinstance(out["sessions"], list):
normalized_sessions = []
for s in out["sessions"]:
ns = dict(s)
if "cdpUrl" in ns and "cdp_url" not in ns:
ns["cdp_url"] = ns["cdpUrl"]
if "liveViewUrl" in ns and "live_view_url" not in ns:
ns["live_view_url"] = ns["liveViewUrl"]
if "interactiveLiveViewUrl" in ns and "interactive_live_view_url" not in ns:
ns["interactive_live_view_url"] = ns["interactiveLiveViewUrl"]
if "streamWebView" in ns and "stream_web_view" not in ns:
ns["stream_web_view"] = ns["streamWebView"]
if "createdAt" in ns and "created_at" not in ns:
ns["created_at"] = ns["createdAt"]
if "lastActivity" in ns and "last_activity" not in ns:
ns["last_activity"] = ns["lastActivity"]
normalized_sessions.append(ns)
out["sessions"] = normalized_sessions
return out
async def browser(
client: AsyncHttpClient,
*,
ttl: Optional[int] = None,
activity_ttl: Optional[int] = None,
stream_web_view: Optional[bool] = None,
profile: Optional[Dict[str, Any]] = None,
) -> BrowserCreateResponse:
"""Create a new browser session.
Args:
client: Async HTTP client instance
ttl: Total time-to-live in seconds (30-3600, default 300)
activity_ttl: Inactivity TTL in seconds (10-3600)
stream_web_view: Whether to enable webview streaming
profile: Profile config with ``name`` (str) and
optional ``save_changes`` (bool, default ``True``)
Returns:
BrowserCreateResponse with session id and CDP URL
"""
body: Dict[str, Any] = {}
if ttl is not None:
body["ttl"] = ttl
if activity_ttl is not None:
body["activityTtl"] = activity_ttl
if stream_web_view is not None:
body["streamWebView"] = stream_web_view
if profile is not None:
body["profile"] = {
"name": profile["name"],
"saveChanges": profile.get("save_changes", True),
}
resp = await client.post("/v2/browser", body)
payload = _normalize_browser_create_response(resp.json())
return BrowserCreateResponse(**payload)
def _normalize_browser_execute_response(payload: Dict[str, Any]) -> Dict[str, Any]:
out = dict(payload)
if "exitCode" in out and "exit_code" not in out:
out["exit_code"] = out["exitCode"]
return out
def _normalize_browser_delete_response(payload: Dict[str, Any]) -> Dict[str, Any]:
out = dict(payload)
if "sessionDurationMs" in out and "session_duration_ms" not in out:
out["session_duration_ms"] = out["sessionDurationMs"]
if "creditsBilled" in out and "credits_billed" not in out:
out["credits_billed"] = out["creditsBilled"]
return out
async def browser_execute(
client: AsyncHttpClient,
session_id: str,
code: str,
*,
language: Literal["python", "node", "bash"] = "bash",
timeout: Optional[int] = None,
) -> BrowserExecuteResponse:
"""Execute code in a browser session.
Args:
client: Async HTTP client instance
session_id: Browser session ID
code: Code to execute
language: Programming language ("python", "node", or "bash")
timeout: Execution timeout in seconds (1-300, default 30)
Returns:
BrowserExecuteResponse with execution result
"""
body: Dict[str, Any] = {
"code": code,
"language": language,
}
if timeout is not None:
body["timeout"] = timeout
resp = await client.post(f"/v2/browser/{session_id}/execute", body)
payload = _normalize_browser_execute_response(resp.json())
return BrowserExecuteResponse(**payload)
async def delete_browser(
client: AsyncHttpClient,
session_id: str,
) -> BrowserDeleteResponse:
"""Delete a browser session.
Args:
client: Async HTTP client instance
session_id: Browser session ID
Returns:
BrowserDeleteResponse
"""
resp = await client.delete(f"/v2/browser/{session_id}")
payload = _normalize_browser_delete_response(resp.json())
return BrowserDeleteResponse(**payload)
async def list_browsers(
client: AsyncHttpClient,
*,
status: Optional[Literal["active", "destroyed"]] = None,
) -> BrowserListResponse:
"""List browser sessions.
Args:
client: Async HTTP client instance
status: Filter by session status ("active" or "destroyed")
Returns:
BrowserListResponse with list of sessions
"""
endpoint = "/v2/browser"
if status is not None:
endpoint = f"{endpoint}?status={status}"
resp = await client.get(endpoint)
payload = _normalize_browser_list_response(resp.json())
return BrowserListResponse(**payload)