Skip to content

Commit bfcb873

Browse files
committed
Playwright captcha and contexts
1 parent 3f523dc commit bfcb873

File tree

4 files changed

+225
-21
lines changed

4 files changed

+225
-21
lines changed

examples/e2e/test_playwright.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pytest
2+
from playwright.sync_api import Playwright, sync_playwright
3+
from dotenv import load_dotenv
4+
import os
5+
from browserbase import Browserbase
6+
7+
from .. import (
8+
BROWSERBASE_API_KEY,
9+
playwright_basic,
10+
playwright_captcha,
11+
playwright_contexts,
12+
)
13+
14+
bb = Browserbase(api_key=BROWSERBASE_API_KEY)
15+
load_dotenv()
16+
17+
SKIP_CAPTCHA_SOLVING = os.getenv("SKIP_CAPTCHA_SOLVING", "false").lower() == "true"
18+
19+
20+
@pytest.fixture(scope="session")
21+
def playwright():
22+
with sync_playwright() as p:
23+
yield p
24+
25+
26+
def test_playwright_basic(playwright: Playwright):
27+
playwright_basic.run(playwright)
28+
29+
30+
def test_playwright_captcha(playwright: Playwright):
31+
if SKIP_CAPTCHA_SOLVING:
32+
pytest.skip("Skipping captcha solving")
33+
playwright_captcha.run(playwright)
34+
35+
36+
def test_playwright_contexts(playwright: Playwright):
37+
playwright_contexts.run(playwright)

examples/e2e/test_playwright_basic.py

Lines changed: 0 additions & 21 deletions
This file was deleted.

examples/playwright_captcha.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from playwright.sync_api import Playwright, sync_playwright, ConsoleMessage
2+
3+
4+
from examples import (
5+
BROWSERBASE_API_KEY,
6+
BROWSERBASE_PROJECT_ID,
7+
BROWSERBASE_CONNECT_URL,
8+
bb,
9+
)
10+
11+
DEFAULT_CAPTCHA_URL = "https://www.google.com/recaptcha/api2/demo"
12+
OVERRIDE_TIMEOUT = 60000 # 60 seconds, adjust as needed
13+
14+
15+
def run(playwright: Playwright):
16+
# Create a session on Browserbase
17+
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
18+
assert session.id is not None
19+
assert session.status == "RUNNING", f"Session status is {session.status}"
20+
21+
# Connect to the remote session
22+
connect_url = (
23+
f"{BROWSERBASE_CONNECT_URL}?sessionId={session.id}&apiKey={BROWSERBASE_API_KEY}"
24+
)
25+
chromium = playwright.chromium
26+
browser = chromium.connect_over_cdp(connect_url)
27+
context = browser.contexts[0]
28+
page = context.pages[0]
29+
30+
captcha_solving_started = False
31+
captcha_solving_finished = False
32+
33+
# Browserbase logs messages to the console to indicate when captcha solving has started and finished
34+
# We can track these messages to know when the captcha solving has started and finished
35+
def handle_console(msg: ConsoleMessage):
36+
nonlocal captcha_solving_started, captcha_solving_finished
37+
if msg.text == "browserbase-solving-started":
38+
captcha_solving_started = True
39+
page.evaluate("window.captchaSolvingFinished = false;")
40+
elif msg.text == "browserbase-solving-finished":
41+
captcha_solving_finished = True
42+
page.evaluate("window.captchaSolvingFinished = true;")
43+
44+
page.on("console", handle_console)
45+
46+
page.goto(DEFAULT_CAPTCHA_URL, wait_until="networkidle")
47+
page.wait_for_function(
48+
"() => window.captchaSolvingFinished === true", timeout=OVERRIDE_TIMEOUT
49+
)
50+
51+
assert captcha_solving_started, "Captcha solving did not start"
52+
assert captcha_solving_finished, "Captcha solving did not finish"
53+
54+
page.close()
55+
browser.close()
56+
print("Done!")
57+
58+
59+
if __name__ == "__main__":
60+
with sync_playwright() as playwright:
61+
run(playwright)

examples/playwright_contexts.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
from playwright.sync_api import Playwright, sync_playwright, Browser, Cookie
2+
from browserbase.types.session_create_params import (
3+
BrowserSettings,
4+
BrowserSettingsContext,
5+
)
6+
import time
7+
from typing import Optional
8+
9+
from examples import (
10+
BROWSERBASE_API_KEY,
11+
BROWSERBASE_PROJECT_ID,
12+
BROWSERBASE_CONNECT_URL,
13+
bb,
14+
)
15+
16+
CONTEXT_TEST_URL = "https://www.browserbase.com"
17+
SECOND = 1000
18+
19+
20+
def add_hour(date: float) -> int:
21+
return int((date + 3600) * 1000) // SECOND
22+
23+
24+
def find_cookie(browser: Browser, name: str) -> Optional[Cookie]:
25+
default_context = browser.contexts[0]
26+
cookies = default_context.cookies()
27+
return next((cookie for cookie in cookies if cookie.get("name") == name), None)
28+
29+
30+
def run(playwright: Playwright):
31+
context_id = None
32+
session_id = None
33+
test_cookie_name = None
34+
test_cookie_value = None
35+
36+
# Step 1: Creates a context
37+
context = bb.contexts.create(project_id=BROWSERBASE_PROJECT_ID)
38+
assert context.id is not None
39+
context_id = context.id
40+
41+
uploaded_context = bb.contexts.retrieve(id=context_id)
42+
assert uploaded_context.id == context_id
43+
44+
# Step 2: Creates a session with the context
45+
session = bb.sessions.create(
46+
project_id=BROWSERBASE_PROJECT_ID,
47+
browser_settings=BrowserSettings(
48+
context=BrowserSettingsContext(id=context_id, persist=True),
49+
),
50+
)
51+
52+
assert (
53+
session.context_id == context_id
54+
), f"Session context_id is {session.context_id}, expected {context_id}"
55+
session_id = session.id
56+
57+
# Step 3: Populates and persists the context
58+
print(f"Populating context {context_id} during session {session_id}")
59+
connect_url = (
60+
f"{BROWSERBASE_CONNECT_URL}?sessionId={session_id}&apiKey={BROWSERBASE_API_KEY}"
61+
)
62+
browser = playwright.chromium.connect_over_cdp(connect_url)
63+
page = browser.contexts[0].pages[0]
64+
65+
page.goto(CONTEXT_TEST_URL, wait_until="domcontentloaded")
66+
67+
now = time.time()
68+
test_cookie_name = f"bb_{int(now * 1000)}"
69+
test_cookie_value = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime(now))
70+
browser.contexts[0].add_cookies(
71+
[
72+
{
73+
"domain": ".browserbase.com",
74+
"expires": add_hour(now),
75+
"name": test_cookie_name,
76+
"path": "/",
77+
"value": test_cookie_value,
78+
}
79+
]
80+
)
81+
82+
assert find_cookie(browser, test_cookie_name) is not None
83+
84+
page.goto("https://www.google.com", wait_until="domcontentloaded")
85+
page.go_back()
86+
87+
assert find_cookie(browser, test_cookie_name) is not None
88+
89+
page.close()
90+
browser.close()
91+
92+
time.sleep(5)
93+
94+
# Step 4: Creates another session with the same context
95+
session = bb.sessions.create(
96+
project_id=BROWSERBASE_PROJECT_ID,
97+
browser_settings=BrowserSettings(
98+
context=BrowserSettingsContext(id=context_id, persist=True)
99+
),
100+
)
101+
assert (
102+
session.context_id == context_id
103+
), f"Session context_id is {session.context_id}, expected {context_id}"
104+
session_id = session.id
105+
106+
# Step 5: Uses context to find previous state
107+
print(f"Reusing context {context_id} during session {session_id}")
108+
connect_url = (
109+
f"{BROWSERBASE_CONNECT_URL}?sessionId={session_id}&apiKey={BROWSERBASE_API_KEY}"
110+
)
111+
browser = playwright.chromium.connect_over_cdp(connect_url)
112+
page = browser.contexts[0].pages[0]
113+
114+
page.goto(CONTEXT_TEST_URL, wait_until="domcontentloaded")
115+
116+
found_cookie = find_cookie(browser, test_cookie_name)
117+
print(found_cookie)
118+
assert found_cookie is not None
119+
assert found_cookie.get("value") == test_cookie_value
120+
121+
page.close()
122+
browser.close()
123+
124+
125+
if __name__ == "__main__":
126+
with sync_playwright() as playwright:
127+
run(playwright)

0 commit comments

Comments
 (0)