-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserpAnalyzer.js
More file actions
170 lines (142 loc) · 6.06 KB
/
serpAnalyzer.js
File metadata and controls
170 lines (142 loc) · 6.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// serpAnalyzer.js
(function () {
function sendLog(message, level = "info") {
if (typeof chrome !== "undefined" && chrome.runtime && chrome.runtime.sendMessage) {
chrome.runtime.sendMessage({
type: "SEO_LOG",
payload: {
source: "serp",
level,
message
}
});
}
}
console.log("🔎 Google SERP analizi bekleniyor...");
sendLog("Google arama sonuç sayfası açıldı, yerel SEO verisi bekleniyor.");
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "SEO_LOCAL_STATS") {
const local = message.payload;
runSerpAnalysis(local);
}
});
function runSerpAnalysis(local) {
if (!local || !local.keyword) {
console.log("Yerel anahtar kelime bilgisi alınamadı, SERP analizi atlandı.");
sendLog("Yerel anahtar kelime bilgisi gelmedi, SERP analizi atlandı.", "warn");
return;
}
const keyword = local.keyword.toLowerCase();
sendLog(`SERP analizi başlatıldı. Anahtar kelime: "${keyword}"`);
// 1) SERP kartlarını topla
sendLog("Google sonuç sayfasındaki ilk sayfa sonuçları okunuyor...");
const resultNodes = Array.from(document.querySelectorAll("#search .g"));
const competitors = resultNodes.slice(0, 10).map(node => {
const titleEl = node.querySelector("h3");
const linkEl = node.querySelector("a");
const snippetEl =
node.querySelector(".VwiC3b") || node.querySelector(".IsZvec") || node.querySelector("span");
const title = titleEl ? titleEl.innerText.trim() : "";
const url = linkEl ? linkEl.href : "";
const snippet = snippetEl ? snippetEl.innerText.trim() : "";
return { title, url, snippet };
}).filter(c => c.title && c.url);
sendLog(`Toplam ${competitors.length} rakip sonucu bulundu.`);
const stopwords = new Set([
"ve","veya","ile","bir","bu","şu","o","için","gibi","daha",
"çok","az","en","mi","mu","mü","de","da","the","and","for",
"with","you","your","a","an","to","of","in","on","at","from"
]);
function tokenize(text) {
return text
.toLowerCase()
.replace(/[^\p{L}\p{N}\s]/gu, " ")
.split(/\s+/)
.map(t => t.trim())
.filter(t => t.length > 2 && !stopwords.has(t));
}
function wordFreqFromText(text) {
const freq = {};
tokenize(text).forEach(w => {
freq[w] = (freq[w] || 0) + 1;
});
return freq;
}
// 2) SERP kelime frekansları
sendLog("Rakiplerin title + açıklamalarından kelime frekansları hesaplanıyor...");
const allSerpText = competitors
.map(c => c.title + " " + c.snippet)
.join(" ");
const serpFreq = wordFreqFromText(allSerpText);
// 3) Senin title + description frekansı
sendLog("Senin title + description içindeki kelimelerle karşılaştırılıyor...");
const localFreq = wordFreqFromText(
(local.title || "") + " " + (local.description || "")
);
// 4) Eksik terimleri çıkar
sendLog("Rakiplerin sık kullandığı ama sende eksik olan terimler hesaplanıyor...");
const missingTerms = Object.entries(serpFreq)
.filter(([word, count]) => word !== keyword && !localFreq[word])
.sort((a, b) => b[1] - a[1])
.slice(0, 15)
.map(([word, count]) => ({ word, count }));
// 5) Title uzunluk analizi
const serpTitleLengths = competitors.map(c => c.title.length);
const serpAvgTitleLength =
serpTitleLengths.reduce((a, b) => a + b, 0) / (serpTitleLengths.length || 1);
// 6) Pattern analizleri
sendLog("SERP üzerinde pattern analizleri yapılıyor (2025, fiyat, rehber vb.)...");
const patternHints = [];
const serpAllLower = allSerpText.toLowerCase();
const patternWords = ["2025", "fiyat", "rehber", "kılavuz", "nedir", "en iyi", "güncel"];
patternWords.forEach(p => {
const inSerp = serpAllLower.includes(p);
const inLocal = ((local.title || "") + " " + (local.description || "")).toLowerCase().includes(p);
if (inSerp && !inLocal) {
patternHints.push(p);
}
});
const comparison = {
keyword,
localDensity: local.density,
serpCompetitorsCount: competitors.length,
serpAvgTitleLength,
missingTerms,
patternHints,
competitors
};
console.clear();
console.log("📊 SERP KARŞILAŞTIRMA (Anahtar kelime: \"" + keyword + "\")");
console.log(comparison);
console.log(
`📌 Senin yoğunluğun: ${local.density.toFixed(2)}% (kelime: ${local.count} / ${local.wordCount})`
);
console.log("🏆 İlk sayfadaki rakipler (anahtar kelime kullanım sayısı title+snippet):");
competitors.forEach((c, index) => {
const text = (c.title + " " + c.snippet).toLowerCase();
const re = new RegExp("\\b" + escapeRegExp(keyword) + "\\b", "g");
const matches = text.match(re);
const count = matches ? matches.length : 0;
console.log(
`${index + 1}. [${count} kez] ${c.title} → ${c.url}`
);
});
console.log("🧩 Senin title uzunluğu:", (local.title || "").length, "karakter");
console.log("📏 Rakiplerin ortalama title uzunluğu:", serpAvgTitleLength.toFixed(1), "karakter");
if (missingTerms.length) {
console.log("🧠 Rakiplerin sık kullandığı fakat senin title/description'da geçmeyen terimler:");
missingTerms.forEach(t => {
console.log(`• ${t.word} (SERP frekansı: ${t.count})`);
});
}
if (patternHints.length) {
console.log("💡 SERP'te sık görünen bazı pattern'ler, sende yok. Düşünebilirsin:");
patternHints.forEach(p => console.log("• " + p));
}
console.log("✅ SERP analizi tamamlandı.");
sendLog(`SERP analizi tamamlandı. ${competitors.length} rakip incelendi, ${missingTerms.length} eksik terim bulundu.`);
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
})();