import { randomUUID } from "node:crypto"; import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { chromium } from "playwright"; const ENTRY = "https://www.priority1.com/instant-freight-quotes/#New%20Step%201"; const CLICK = { noWaitAfter: true as const }; async function typeField( page: import("playwright").Page, sel: string, value: string, ) { const loc = page.locator(`#container-mh ${sel}`).first(); await loc.click(CLICK); await loc.fill(""); await loc.pressSequentially(value, { delay: 20 }); } async function main() { const out = join(process.cwd(), ".rpa", "priority1-probe-quotes"); mkdirSync(out, { recursive: true }); const network: Array<{ url: string; status: number; body: string }> = []; const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); page.on("response", async (res) => { const url = res.url(); if (!/quote|rate|pricing|ltl|feathery|priority/i.test(url)) return; if (!res.headers()["content-type"]?.includes("json")) return; try { const body = await res.text(); if (body.length > 50) { network.push({ url, status: res.status(), body: body.slice(0, 8000) }); } } catch { /* ignore */ } }); await page.goto(ENTRY, { waitUntil: "domcontentloaded" }); await page.locator("#container-mh").waitFor(); await page.waitForTimeout(1500); await page.locator("#cb_st_ltl").click({ force: true, ...CLICK }); await page .locator("#container-mh") .getByText(/^Less Than Truckload/i) .first() .click(CLICK) .catch(() => undefined); await page.waitForTimeout(600); await typeField(page, "#origin-zip", "10118"); await typeField(page, "#destination-zip", "90017"); await page.locator("#container-mh #freight-shipment").selectOption("One Time Shipment"); await typeField(page, "#pickup-date", "07/01/2026"); await typeField(page, "#business-email", "niqijiti542@gmail.com"); await typeField(page, "#client-phone", "2125550198"); const btn1 = page .locator("#container-mh") .getByRole("button", { name: /GET INSTANT QUOTES/i }) .first(); await btn1.click(CLICK); await page.locator("#container-mh #length").waitFor({ state: "visible", timeout: 60_000 }); await typeField(page, "#length", "48"); await typeField(page, "#width", "40"); await typeField(page, "#height", "48"); await typeField(page, "#weight", "30"); await typeField(page, "#number-of-pallets", "2"); const pkg = page .locator("#container-mh select") .filter({ has: page.locator('option:has-text("Pallet")') }); if ((await pkg.count()) > 0) await pkg.first().selectOption("Pallet"); await page.locator("#container-mh #PickupLocation").selectOption("Residence / Home Business"); await page.locator("#container-mh #DropoffLocation").selectOption("Residence / Home Business"); const btn2 = page .locator("#container-mh") .getByRole("button", { name: /GET INSTANT QUOTES/i }) .first(); await btn2.click(CLICK); const started = Date.now(); while (Date.now() - started < 90_000) { const has = await page.evaluate(() => /\$[\d,]+\.\d{2}/.test(document.body.innerText)); if (has) break; await page.waitForTimeout(2000); } const dom = await page.evaluate(() => { const cards = [...document.querySelectorAll("#container-mh *")].filter((el) => { const t = el.textContent || ""; return /\$[\d,]+\.\d{2}/.test(t) && t.length < 500; }); return cards.slice(0, 15).map((el) => ({ tag: el.tagName, class: (el as HTMLElement).className?.slice?.(0, 80), text: el.textContent?.replace(/\s+/g, " ").trim().slice(0, 200), })); }); writeFileSync(join(out, "network.json"), JSON.stringify(network, null, 2)); writeFileSync(join(out, "dom.json"), JSON.stringify(dom, null, 2)); await page.screenshot({ path: join(out, "quote.png"), fullPage: true }); console.log("network:", network.length, "dom cards:", dom.length); console.log("out:", out); for (const n of network.slice(0, 5)) { console.log("---", n.url, n.status); console.log(n.body.slice(0, 500)); } console.log("dom sample:", JSON.stringify(dom.slice(0, 5), null, 2)); await browser.close(); } main().catch(console.error);