← back to Govarbitrage

scripts/probe-govdeals.ts

62 lines

// One-off: discover live GovDeals item URLs by rendering the Angular SPA and
// harvesting item-detail links. Prints candidates so we can point scrapeUrl at
// a real, currently-open listing.
import { chromium } from "playwright";

const ENTRY = process.argv[2] || "https://www.govdeals.com/";
const HEADED = process.env.HEADED === "1";

async function main() {
  const browser = await chromium.launch({
    headless: !HEADED,
    args: ["--disable-blink-features=AutomationControlled"],
  });
  const context = await browser.newContext({
    userAgent:
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    viewport: { width: 1400, height: 900 },
    locale: "en-US",
    timezoneId: "America/Los_Angeles",
  });
  // Mask the headless/automation tells before any page script runs.
  await context.addInitScript(() => {
    Object.defineProperty(navigator, "webdriver", { get: () => undefined });
    // @ts-expect-error test fingerprint props
    window.chrome = { runtime: {} };
    Object.defineProperty(navigator, "plugins", { get: () => [1, 2, 3] });
    Object.defineProperty(navigator, "languages", { get: () => ["en-US", "en"] });
  });
  const page = await context.newPage();
  try {
    console.log("goto", ENTRY);
    await page.goto(ENTRY, { waitUntil: "networkidle", timeout: 45_000 }).catch((e) => console.log("nav warn:", e.message));
    await page.waitForTimeout(4000);
    console.log("title:", await page.title());
    console.log("url:", page.url());

    const links = await page.evaluate(() => {
      const hrefs = Array.from(document.querySelectorAll("a"))
        .map((a) => (a as HTMLAnchorElement).href)
        .filter((h) => /asset|\/item|itemid|\/listing/i.test(h));
      return Array.from(new Set(hrefs)).slice(0, 15);
    });
    console.log(`\nfound ${links.length} item-like links:`);
    links.forEach((l) => console.log("  ", l));

    // Fallback: sample any anchor hrefs so we can see the URL shape.
    if (links.length === 0) {
      const sample = await page.evaluate(() =>
        Array.from(new Set(Array.from(document.querySelectorAll("a")).map((a) => (a as HTMLAnchorElement).href)))
          .filter((h) => h.includes("govdeals.com"))
          .slice(0, 20),
      );
      console.log("\nno item links; sample of on-site anchors:");
      sample.forEach((s) => console.log("  ", s));
    }
  } finally {
    await browser.close();
  }
}

main();