const http = require('http');
async function auditPage(url, pageName) {
try {
const res = await fetch(url);
if (!res.ok) {
console.log(`[${pageName}] HTTP Status: ${res.status}`);
return;
}
const html = await res.text();
console.log(`\n==============================================`);
console.log(`π [μ λ° SEO κ°μ¬ λ³΄κ³ μ] ${pageName}`);
console.log(`π λμ URL: ${url}`);
console.log(`==============================================`);
// 1. Title
const titleMatch = html.match(/
([^<]+)<\/title>/i);
const title = titleMatch ? titleMatch[1].trim() : 'β μμ';
console.log(`1. `);
console.log(` - ν
μ€νΈ: "${title}"`);
console.log(` - κΈμμ: ${title.length}μ (λ€μ΄λ²/κ΅¬κΈ κ²μ μ΅μ κΆμ₯ 30~35μ λ΄μΈ)`);
console.log(` - κ²μκ²°κ³Ό λ§μ€μ(β¦) λ°©μ§ νκ°: ${title.length >= 25 && title.length <= 40 ? 'β
μ΅μ (λ§μ€μ μμ)' : 'β οΈ μ κ² κΆμ₯'}`);
// 2. H1 νκ·Έ
const h1Matches = [...html.matchAll(/]*>([\s\S]*?)<\/h1>/gi)];
console.log(`\n2. νκ·Έ`);
console.log(` - λ°κ²¬λ H1 κ°μ: ${h1Matches.length}κ° (κ²μμμ§ κΆμ₯ λ¨λ
1κ° μμΉ)`);
h1Matches.forEach((m, i) => {
const cleanH1 = m[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
console.log(` - H1 #${i + 1}: "${cleanH1}"`);
});
console.log(` - νκ°: ${h1Matches.length === 1 ? 'β
λ¨λ
H1 κ·κ²© μ€μ (κ²μ κ°μ€μΉ μ§μ€)' : 'β οΈ H1 μ€λ³΅ λλ λλ½'}`);
// 3. Meta Description
const descMatch = html.match(/]*name=["']description["'][^>]*content=["']([^"']+)["']/i)
|| html.match(/]*content=["']([^"']+)["'][^>]*name=["']description["']/i);
const desc = descMatch ? descMatch[1].trim() : 'β μμ';
console.log(`\n3. Meta Description`);
console.log(` - λ΄μ©: "${desc}"`);
console.log(` - κΈμμ: ${desc.length}μ (κΆμ₯ 80~140μ)`);
console.log(` - κ²μ μ€λν« CTR νκ°: ${desc.length >= 50 && desc.length <= 160 ? 'β
μ΅μ ' : 'β οΈ μ κ² κΆμ₯'}`);
// 4. Canonical URL
const canonMatch = html.match(/]*rel=["']canonical["'][^>]*href=["']([^"']+)["']/i);
const canonical = canonMatch ? canonMatch[1] : 'β μμ';
console.log(`\n4. Canonical URL (νμ€ URL)`);
console.log(` - λμ URL: ${canonical}`);
console.log(` - νκ°: ${canonical.startsWith('http') ? 'β
μ λκ²½λ‘ νμ€ μ€μ (μ€λ³΅ λ¬Έμ νλν° λ°©μ§)' : 'β μλκ²½λ‘ λλ λλ½'}`);
// 5. Naver Site Verification
const naverMatch = html.match(/]*name=["']naver-site-verification["'][^>]*content=["']([^"']+)["']/i);
console.log(`\n5. λ€μ΄λ² μμΉμ΄λλ°μ΄μ μμ νμΈ νκ·Έ`);
console.log(` - ν€ κ°: ${naverMatch ? naverMatch[1] : 'β μμ'}`);
// 6. Open Graph & Twitter Cards
const ogTitle = (html.match(/]*property=["']og:title["'][^>]*content=["']([^"']+)["']/i) || [])[1];
const ogImage = (html.match(/]*property=["']og:image["'][^>]*content=["']([^"']+)["']/i) || [])[1];
const twitterCard = (html.match(/]*name=["']twitter:card["'][^>]*content=["']([^"']+)["']/i) || [])[1];
console.log(`\n6. μμ
λ―Έλμ΄ λ©νλ°μ΄ν° (OG & Twitter)`);
console.log(` - og:title: ${ogTitle || 'β'}`);
console.log(` - og:image: ${ogImage || 'β'}`);
console.log(` - twitter:card: ${twitterCard || 'β'}`);
// 7. JSON-LD ꡬ쑰ν λ°μ΄ν°
const ldJsonMatches = [...html.matchAll(/