-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathmain.py
More file actions
204 lines (167 loc) · 7.24 KB
/
main.py
File metadata and controls
204 lines (167 loc) · 7.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# Stagehand + Browserbase: Context Authentication Example - See README.md for full documentation
import os
import requests
from browserbase import Browserbase
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright
from pydantic import BaseModel, Field
from stagehand import Stagehand
# Load environment variables
load_dotenv()
def create_session_context_id():
print("Creating new Browserbase context...")
# First create a context using Browserbase SDK to get a context ID.
bb = Browserbase(api_key=os.environ.get("BROWSERBASE_API_KEY"))
context = bb.contexts.create()
print(f"Created context ID: {context.id}")
# Create a single session using the context ID to perform initial login.
print("Creating session for initial login...")
session = bb.sessions.create(
browser_settings={
"context": {
"id": context.id,
"persist": True, # Save authentication state to context
}
},
)
session_id = session.id
print(f"Live view: https://browserbase.com/sessions/{session_id}")
# Initialize Stagehand with Browserbase for cloud-based browser automation
client = Stagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
)
# Connect Stagehand to the existing session (no new session created).
print("Connecting Stagehand to session...")
# Connect to the browser via CDP
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(
f"wss://connect.browserbase.com?apiKey={os.environ['BROWSERBASE_API_KEY']}&sessionId={session_id}"
)
ctx = browser.contexts[0]
page = ctx.pages[0] if ctx.pages else ctx.new_page()
email = os.environ.get("SF_REC_PARK_EMAIL")
password = os.environ.get("SF_REC_PARK_PASSWORD")
# Navigate to login page with extended timeout for slow-loading sites.
print("Navigating to SF Rec & Park login page...")
page.goto(
"https://www.rec.us/organizations/san-francisco-rec-park",
wait_until="domcontentloaded",
timeout=60000,
)
# Perform login sequence: each step is atomic to handle dynamic page changes.
print("Starting login sequence...")
client.sessions.act(
id=session_id,
input="Click the Login button",
)
client.sessions.act(
id=session_id,
input=f'Fill in the email or username field with "{email}"',
)
client.sessions.act(
id=session_id,
input="Click the next, continue, or submit button to proceed",
)
client.sessions.act(
id=session_id,
input=f'Fill in the password field with "{password}"',
)
client.sessions.act(
id=session_id,
input="Click the login, sign in, or submit button",
)
print("Login sequence completed!")
browser.close()
client.sessions.end(id=session_id)
print("Authentication state saved to context")
# Return the context ID for reuse in future sessions.
return {"id": context.id}
def delete_context(context_id: str):
"""Delete context via Browserbase API to clean up stored authentication data.
This prevents accumulation of unused contexts and ensures security cleanup."""
try:
print(f"Cleaning up context: {context_id}")
response = requests.delete(
f"https://api.browserbase.com/v1/contexts/{context_id}",
headers={
"X-BB-API-Key": os.environ.get("BROWSERBASE_API_KEY"),
},
)
print(f"Context deleted successfully (status: {response.status_code})")
except Exception as error:
error_msg = getattr(error, "response", {}).get("data") or str(error)
print(f"Error deleting context: {error_msg}")
def main():
print("Starting Context Authentication Example...")
# Create context with login state for reuse in authenticated sessions.
context_id = create_session_context_id()
# Initialize new session using existing context to inherit authentication state.
# persist: true ensures any new changes (cookies, cache) are saved back to context.
bb = Browserbase(api_key=os.environ.get("BROWSERBASE_API_KEY"))
session = bb.sessions.create(
browser_settings={
"context": {
"id": context_id["id"],
"persist": True,
}
},
)
session_id = session.id
# Initialize Stagehand with Browserbase for cloud-based browser automation
client = Stagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
)
try:
print("Authenticated session ready!")
print(f"Live view: https://browserbase.com/sessions/{session_id}")
# Connect to the browser via CDP
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(
f"wss://connect.browserbase.com?apiKey={os.environ['BROWSERBASE_API_KEY']}&sessionId={session_id}"
)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
# Navigate to authenticated area - should skip login due to persisted cookies.
print("Navigating to authenticated area (should skip login)...")
page.goto(
"https://www.rec.us/organizations/san-francisco-rec-park",
wait_until="domcontentloaded",
timeout=60000,
)
# Navigate to user-specific area to access personal data.
client.sessions.act(
id=session_id,
input="Click on the reservations button",
)
# Extract structured user data using Pydantic schema for type safety.
# Schema ensures consistent data format and validates extracted content.
print("Extracting user profile data...")
class UserData(BaseModel):
full_name: str = Field(..., description="the user's full name")
address: str = Field(..., description="the user's address")
extract_response = client.sessions.extract(
id=session_id,
instruction="Extract the user's full name and address",
schema=UserData.model_json_schema(),
)
print(f"Extracted user data: {extract_response.data.result}")
browser.close()
client.sessions.end(id=session_id)
print("Session closed successfully")
except Exception as error:
print(f"Error: {error}")
client.sessions.end(id=session_id)
raise
# Clean up context to prevent accumulation and ensure security.
delete_context(context_id["id"])
if __name__ == "__main__":
try:
main()
except Exception as err:
print(f"Error in context authentication example: {err}")
print("Common issues:")
print(" - Check .env file has SF_REC_PARK_EMAIL and SF_REC_PARK_PASSWORD")
print(" - Verify BROWSERBASE_API_KEY is set")
print(" - Ensure credentials are valid for SF Rec & Park")
print("Docs: https://docs.stagehand.dev/v3/first-steps/introduction")
exit(1)