website-builde / lib /browser-crawler.ts
Daviddolor's picture
Single-process Chromium, fixed visual-polish prompt, Docker config for HF Space
ec675f2
Raw
History Blame Contribute Delete
2.43 kB
import { chromium } from "playwright";
import fs from "fs";
export async function crawlBrowser(url:string){
console.log("AI Browser crawling:",url);
const browserPath =
"/root/.cache/puppeteer/chrome/linux_arm-148.0.7778.97/chrome-linux64/chrome";
const browser =
await chromium.launch({
executablePath: browserPath,
headless:true,
args:[
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage"
]
});
const page = await browser.newPage({
viewport:{
width:1440,
height:900
}
});
await page.goto(url,{
waitUntil:"commit",
timeout:60000
});
const data = await page.evaluate(()=>{
const pick=(arr:string[]) =>
Array.from(new Set(arr.filter(Boolean)));
const elements =
Array.from(document.querySelectorAll("*"));
const styles =
elements.map(e=>getComputedStyle(e));
return {
title:
document.title,
description:
document.querySelector(
'meta[name="description"]'
)?.getAttribute("content") || "",
viewport:
document.querySelector(
'meta[name="viewport"]'
)?.getAttribute("content") || "",
favicon:
(document.querySelector(
'link[rel="icon"]'
) as HTMLLinkElement)?.href || "",
headings:
Array.from(
document.querySelectorAll("h1,h2,h3,h4")
)
.map(x=>x.textContent?.trim())
.filter(Boolean),
images:
Array.from(
document.images
)
.map(x=>({
src:x.src,
alt:x.alt,
width:x.width,
height:x.height
})),
links:
Array.from(
document.querySelectorAll("a")
)
.map(x=>(x as HTMLAnchorElement).href)
.filter(Boolean),
buttons:
Array.from(
document.querySelectorAll(
"button,a"
)
)
.map(x=>x.textContent?.trim())
.filter(Boolean),
css:
Array.from(
document.styleSheets
)
.map((x:any)=>x.href)
.filter(Boolean),
design:{
colors:
pick(
styles.map(
s=>s.color
)
.concat(
styles.map(
s=>s.backgroundColor
)
)
),
fonts:
pick(
styles.map(
s=>s.fontFamily
)
),
fontSizes:
pick(
styles.map(
s=>s.fontSize
)
),
spacing:
pick(
styles.map(
s=>`${s.margin}|${s.padding}`
)
),
borderRadius:
pick(
styles.map(
s=>s.borderRadius
)
),
animations:
pick(
styles.map(
s=>s.animation
)
),
gradients:
pick(
styles.map(
s=>s.backgroundImage
)
.filter(x=>x.includes("gradient"))
)
},
text:
document.body.innerText
.replace(/\s+/g," ")
.slice(0,5000)
};
});
const screenshot =
`/tmp/crawl-${Date.now()}.png`;
await page.screenshot({
path:screenshot,
fullPage:true
});
await browser.close();
return {
url,
screenshot,
...data
};
}