-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhn-top.ts
More file actions
37 lines (33 loc) · 1.3 KB
/
hn-top.ts
File metadata and controls
37 lines (33 loc) · 1.3 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
import { z } from 'zod'
import type { Browser } from '@browserclijs/browser-cli'
/**
* Fetch top N stories from the Hacker News front page.
*
* Layer 3 (DOM) example — Hacker News has no public JSON endpoint for
* its ranked front page, so the resilient path is `page.extract` with
* a Zod schema. Stagehand caches the resolved selectors per (URL,
* instruction) pair and self-heals if HN tweaks `tr.athing` or `.score`
* tomorrow. Hand-rolled `document.querySelectorAll` would just break.
*/
export const schema = z.object({
limit: z.number().int().positive().max(30).default(5),
})
export async function run(browser: Browser, args: z.infer<typeof schema>) {
const page = await browser.newPage()
await page.goto('https://news.ycombinator.com/', { waitUntil: 'domcontentloaded' })
const result = await page.extract(
`extract the top ${args.limit} stories from the Hacker News front page in the order they appear; for each story return rank, title, url, score, and user`,
z.object({
stories: z.array(
z.object({
rank: z.string().nullable(),
title: z.string().nullable(),
url: z.string().nullable(),
score: z.string().nullable(),
user: z.string().nullable(),
}),
),
}),
)
return result.stories.slice(0, args.limit)
}