first commit

This commit is contained in:
mstfyldz
2026-05-29 23:23:50 +03:00
commit 0773e7f6f3
9 changed files with 241 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
import { chromium, Browser } from "playwright";
let browser: Browser | null = null;
async function getBrowser(): Promise<Browser> {
if (!browser || !browser.isConnected()) {
browser = await chromium.launch({
headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
}
return browser;
}
// Navbar'da atlanacak anahtar kelimeler
const SKIP_KEYWORDS = [
"kariyer", "/ik", "kvkk", "gizlilik", "cerez",
"blog", "haber", "saglikbulteni", "saglik-rehberi",
"rezervasyon", "randevu", "e-sonuc", "checkup",
"wp-admin", "wp-content", "feed", "sitemap",
];
const SKIP_SCHEMES = ["mailto:", "tel:", "javascript:", "#"];
export interface NavLink {
label: string;
url: string;
}
export async function extractNavLinks(targetUrl: string): Promise<NavLink[]> {
const base = new URL(targetUrl);
const b = await getBrowser();
const page = await b.newPage();
try {
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 30000 });
await page.waitForTimeout(1200); // dropdown'ların render edilmesi için
// Navbar içindeki tüm <a> etiketlerini çek
const rawLinks = await page.evaluate(() => {
const selectors = [
"nav a", "header a",
"[class*='menu'] a", "[class*='navbar'] a",
"[class*='nav-'] a", "[id*='menu'] a", "[id*='nav'] a",
];
const seen = new Set<string>();
const links: { href: string; label: string }[] = [];
for (const sel of selectors) {
document.querySelectorAll<HTMLAnchorElement>(sel).forEach((el) => {
const href = el.href || el.getAttribute("href") || "";
const label = el.textContent?.trim().replace(/\s+/g, " ") || "";
if (href && !seen.has(href)) {
seen.add(href);
links.push({ href, label });
}
});
}
return links;
});
// Filtrele ve temizle
const seen = new Set<string>();
const result: NavLink[] = [];
for (const { href, label } of rawLinks) {
if (!href) continue;
if (SKIP_SCHEMES.some((s) => href.startsWith(s))) continue;
let parsed: URL;
try { parsed = new URL(href, targetUrl); } catch { continue; }
// Sadece aynı domain
if (parsed.hostname !== base.hostname) continue;
const path = parsed.pathname.toLowerCase();
// Atlanacak sayfalar
if (SKIP_KEYWORDS.some((kw) => path.includes(kw))) continue;
// Fragment ve trailing slash temizle
parsed.hash = "";
const normalized = parsed.toString().replace(/\/$/, "");
if (seen.has(normalized)) continue;
seen.add(normalized);
result.push({ label: label || pathToLabel(parsed.pathname), url: normalized });
}
return result;
} finally {
await page.close();
}
}
function pathToLabel(pathname: string): string {
const last = pathname.split("/").filter(Boolean).pop() || "anasayfa";
return last.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}