Skip to content

Commit 85639ef

Browse files
committed
Merge branch 'main' into DX-2751
2 parents 683db49 + 17adf0a commit 85639ef

36 files changed

Lines changed: 5675 additions & 5827 deletions
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
title: "Scrape Dynamic Websites with Playwright"
3+
---
4+
5+
In this guide, we use Upstash Box to run [Playwright](https://playwright.dev) against a JavaScript-heavy site, scrape structured data from it, and pull the results back to our own server. Because a Box is a real Linux container rather than a restricted serverless runtime, Chromium and its system dependencies install and run exactly like they would on your laptop.
6+
7+
---
8+
9+
## 1. Installation
10+
11+
```bash
12+
npm install @upstash/box
13+
```
14+
15+
Set your environment variables:
16+
17+
```bash title=".env"
18+
UPSTASH_BOX_API_KEY=box_xxxxxxxxxxxxxxxxxxxxxxxx
19+
```
20+
21+
---
22+
23+
## 2. Provision a box and install Playwright
24+
25+
Create a box with outbound network access (the default) so it can reach the target site and download the browser binaries, then install Playwright and Chromium with its system dependencies.
26+
27+
```typescript title="scripts/scrape.ts"
28+
import "dotenv/config"
29+
import { Agent, Box } from "@upstash/box"
30+
31+
const box = await Box.create({
32+
runtime: "node",
33+
agent: {
34+
harness: Agent.ClaudeCode,
35+
model: "anthropic/claude-sonnet-4-6",
36+
},
37+
})
38+
39+
console.log(`Box ready: ${box.id}`)
40+
41+
await box.exec.command("npm init -y && npm install playwright")
42+
43+
// `--with-deps` pulls in the Linux system libraries Chromium needs via apt-get
44+
const setup = await box.exec.command("npx playwright install chromium --with-deps")
45+
46+
if (setup.status !== "completed") {
47+
throw new Error(`Chromium setup failed: ${setup.result}`)
48+
}
49+
50+
console.log("Chromium and its system dependencies are ready.")
51+
```
52+
53+
---
54+
55+
## 3. Let the agent write and run the scraper
56+
57+
Hand the scraping task to the box's built-in agent. It writes the Playwright script, runs it, fixes any issues it hits along the way, and saves the output to a file in the workspace.
58+
59+
```typescript title="scripts/scrape.ts" {1}
60+
const run = await box.agent.run({
61+
prompt: `
62+
Write a Node.js script that uses Playwright to:
63+
1. Launch headless Chromium and navigate to https://news.ycombinator.com/show
64+
2. Wait for the page to finish loading
65+
3. Extract the title, URL, and point count for the top 10 posts
66+
4. Save the result as a JSON array to /workspace/home/scraped_data.json
67+
68+
Then run the script and confirm the file was written successfully.
69+
`.trim(),
70+
})
71+
72+
console.log(run.result)
73+
```
74+
75+
The agent has shell, filesystem, and the installed Playwright package available, so it can iterate — adjusting selectors, adding waits for dynamic content, retrying on failure — until the scrape actually produces data.
76+
77+
---
78+
79+
## 4. Pull the results back
80+
81+
Read the file the agent wrote and bring it back into your own process.
82+
83+
```typescript title="scripts/scrape.ts"
84+
const raw = await box.files.read("/workspace/home/scraped_data.json")
85+
const dataset = JSON.parse(raw)
86+
87+
console.table(dataset.slice(0, 3))
88+
89+
await box.delete()
90+
```
91+
92+
You now have structured data extracted from a dynamic, JavaScript-rendered page — without managing a single Chromium binary yourself.
93+
94+
---
95+
96+
## 5. Skip the setup on every run with snapshots
97+
98+
`npx playwright install chromium --with-deps` takes real time to stream and unpack OS-level packages. Paying that cost on every scrape request would be painful in production.
99+
100+
[Snapshot](/box/overall/snapshots) the box once Chromium and its dependencies are installed, and restore from that snapshot whenever you need a ready-to-go scraping environment:
101+
102+
```typescript title="scripts/prepare-snapshot.ts"
103+
const snapshot = await box.snapshot({ name: "playwright-ready" })
104+
console.log(`Snapshot ready: ${snapshot.id}`)
105+
```
106+
107+
Store `snapshot.id` somewhere your application can reach (an env var, a database row, etc.), then spin up pre-warmed boxes from it on demand:
108+
109+
```typescript title="scripts/run-scrape-job.ts"
110+
import { Box } from "@upstash/box"
111+
112+
const box = await Box.fromSnapshot(process.env.PLAYWRIGHT_SNAPSHOT_ID!)
113+
114+
const run = await box.agent.run({
115+
prompt: "Navigate to <url> and extract <data>...",
116+
})
117+
118+
await box.delete()
119+
```
120+
121+
Restoring from a snapshot starts the box with Chromium and its system libraries already in place, so the agent can start scraping immediately instead of waiting on `apt-get` and binary downloads.

0 commit comments

Comments
 (0)