Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ dist
codegen.log
Brewfile.lock.json
screenshot.png
openapi.v1.yaml
**/.DS_Store
71 changes: 33 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,45 @@ The full API of this library can be found in [api.md](api.md).

```python
import os
from playwright.sync_api import Playwright, sync_playwright
from browserbase import Browserbase

client = Browserbase(
BROWSERBASE_API_KEY = os.environ.get("BROWSERBASE_API_KEY")
BROWSERBASE_PROJECT_ID = os.environ.get("BROWSERBASE_PROJECT_ID")

bb = Browserbase(
# This is the default and can be omitted
api_key=os.environ.get("BROWSERBASE_API_KEY"),
api_key=BROWSERBASE_API_KEY,
)

context = client.contexts.create(
project_id="projectId",
)
print(context.id)
```
def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)

# Connect to the remote session
chromium = playwright.chromium
browser = chromium.connect_over_cdp(session.connect_url)
context = browser.contexts[0]
page = context.pages[0]

While you can provide an `api_key` keyword argument,
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
to add `BROWSERBASE_API_KEY="My API Key"` to your `.env` file
so that your API Key is not stored in source control.
# Execute Playwright actions on the remote browser tab
page.goto("https://news.ycombinator.com/")
page_title = page.title()
assert (
page_title == "Hacker News"
), f"Page title is not 'Hacker News', it is '{page_title}'"
page.screenshot(path="screenshot.png")

page.close()
browser.close()
print("Done!")


if __name__ == "__main__":
with sync_playwright() as playwright:
run(playwright)

```

## Examples

Expand All @@ -63,33 +85,6 @@ rye run example playwright_basic # replace with the example you want to run
> [!NOTE]
> Make sure you have a `.env` file that matches the [.env.example](.env.example) file in the root of this repository.

## Async usage

Simply import `AsyncBrowserbase` instead of `Browserbase` and use `await` with each API call:

```python
import os
import asyncio
from browserbase import AsyncBrowserbase

client = AsyncBrowserbase(
# This is the default and can be omitted
api_key=os.environ.get("BROWSERBASE_API_KEY"),
)


async def main() -> None:
context = await client.contexts.create(
project_id="projectId",
)
print(context.id)


asyncio.run(main())
```

Functionality between the synchronous and asynchronous clients is otherwise identical.

## Using types

Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
Expand Down
56 changes: 45 additions & 11 deletions examples/e2e/test_playwright.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import os
from typing import Generator

import pytest
from playwright.sync_api import Playwright, sync_playwright
from dotenv import load_dotenv
import os
from playwright.sync_api import Playwright, sync_playwright
from browserbase import Browserbase

from .. import (
BROWSERBASE_API_KEY,
playwright_basic,
playwright_proxy,
playwright_upload,
playwright_captcha,
playwright_contexts,
playwright_downloads,
Expand All @@ -15,28 +19,58 @@
bb = Browserbase(api_key=BROWSERBASE_API_KEY)
load_dotenv()

SKIP_CAPTCHA_SOLVING = os.getenv("SKIP_CAPTCHA_SOLVING", "true").lower() == "true"
CI = os.getenv("CI", "false").lower() == "true"


@pytest.fixture(scope="session")
def playwright():
def playwright() -> Generator[Playwright, None, None]:
with sync_playwright() as p:
yield p


def test_playwright_basic(playwright: Playwright):
def test_playwright_basic(playwright: Playwright) -> None:
playwright_basic.run(playwright)


def test_playwright_captcha(playwright: Playwright):
if SKIP_CAPTCHA_SOLVING:
pytest.skip("Skipping captcha solving")
@pytest.mark.skipif(True, reason="Flaky and fails often")
def test_playwright_captcha(playwright: Playwright) -> None:
playwright_captcha.run(playwright)


def test_playwright_contexts(playwright: Playwright):
def test_playwright_contexts(playwright: Playwright) -> None:
playwright_contexts.run(playwright)


def test_playwright_downloads(playwright: Playwright):
def test_playwright_downloads(playwright: Playwright) -> None:
playwright_downloads.run(playwright)


def test_playwright_proxy_enable_via_create_session(playwright: Playwright) -> None:
playwright_proxy.run_enable_via_create_session(playwright)


def test_playwright_proxy_enable_via_querystring(playwright: Playwright) -> None:
playwright_proxy.run_enable_via_querystring_with_created_session(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_country(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_country(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_state(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_state(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_american_city(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_american_city(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_non_american_city(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_non_american_city(playwright)


def test_playwright_upload(playwright: Playwright) -> None:
playwright_upload.run(playwright)
Binary file added examples/packages/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 16 additions & 12 deletions examples/playwright_basic.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import os

from playwright.sync_api import Playwright, sync_playwright

from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
BROWSERBASE_CONNECT_URL,
bb,
from browserbase import Browserbase

BROWSERBASE_API_KEY = os.environ.get("BROWSERBASE_API_KEY", "")
if not BROWSERBASE_API_KEY:
raise ValueError("BROWSERBASE_API_KEY is not set")
BROWSERBASE_PROJECT_ID = os.environ.get("BROWSERBASE_PROJECT_ID", "")
if not BROWSERBASE_PROJECT_ID:
raise ValueError("BROWSERBASE_PROJECT_ID is not set")

bb = Browserbase(
# This is the default and can be omitted
api_key=BROWSERBASE_API_KEY,
)


def run(playwright: Playwright):
def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
assert session.id is not None
assert session.status == "RUNNING", f"Session status is {session.status}"

# Connect to the remote session
connect_url = (
f"{BROWSERBASE_CONNECT_URL}?sessionId={session.id}&apiKey={BROWSERBASE_API_KEY}"
)
chromium = playwright.chromium
browser = chromium.connect_over_cdp(connect_url)
browser = chromium.connect_over_cdp(session.connect_url)
context = browser.contexts[0]
page = context.pages[0]

Expand Down
6 changes: 3 additions & 3 deletions examples/playwright_captcha.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from playwright.sync_api import Playwright, sync_playwright, ConsoleMessage
from playwright.sync_api import Playwright, ConsoleMessage, sync_playwright


from examples import (
Expand All @@ -12,7 +12,7 @@
OVERRIDE_TIMEOUT = 60000 # 60 seconds, adjust as needed


def run(playwright: Playwright):
def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
assert session.id is not None
Expand All @@ -32,7 +32,7 @@ def run(playwright: Playwright):

# Browserbase logs messages to the console to indicate when captcha solving has started and finished
# We can track these messages to know when the captcha solving has started and finished
def handle_console(msg: ConsoleMessage):
def handle_console(msg: ConsoleMessage) -> None:
nonlocal captcha_solving_started, captcha_solving_finished
if msg.text == "browserbase-solving-started":
captcha_solving_started = True
Expand Down
15 changes: 9 additions & 6 deletions examples/playwright_contexts.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
from playwright.sync_api import Playwright, sync_playwright, Browser, Cookie
from browserbase.types.session_create_params import (
BrowserSettings,
BrowserSettingsContext,
)
import time
from typing import Optional

from playwright.sync_api import Cookie, Browser, Playwright, sync_playwright


from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
BROWSERBASE_CONNECT_URL,
bb,
)
from browserbase.types.session_create_params import (
BrowserSettings,
BrowserSettingsContext,
)


CONTEXT_TEST_URL = "https://www.browserbase.com"
SECOND = 1000
Expand All @@ -27,7 +30,7 @@ def find_cookie(browser: Browser, name: str) -> Optional[Cookie]:
return next((cookie for cookie in cookies if cookie.get("name") == name), None)


def run(playwright: Playwright):
def run(playwright: Playwright) -> None:
context_id = None
session_id = None
test_cookie_name = None
Expand Down
7 changes: 5 additions & 2 deletions examples/playwright_downloads.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import io
import re
import zipfile
import io

from playwright.sync_api import Playwright, sync_playwright


from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
Expand All @@ -17,7 +20,7 @@ def get_download(session_id: str) -> bytes:
return response.read()


def run(playwright: Playwright):
def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
assert session.id is not None
Expand Down
Loading
Loading