Dieses Skript ist eine eigenständige Webanwendung, die eine umfassende Analyse von Keywords und Domains direkt im Browser ermöglicht. Es kombiniert PHP für die Weboberfläche mit einem Headless Browser (Puppeteer/Node.js) zur Datenerhebung, um präzisere Ergebnisse als einfache Curl-Abfragen zu liefern.
Funktionen:
- Keyword-Position: Ermittelt die aktuelle Platzierung deiner Domain für beliebige Keywords in Google.
- Konkurrenzanalyse: Zeigt die Top-Konkurrenten für jedes Keyword in den Suchergebnissen an.
- Sichtbarkeit: Übersicht über Top-10 und Top-100 Rankings, inkl. Historie.
- Meta-Daten Check: Prüft Title, Description und H1 deiner Domain.
- Page Speed: Misst die Ladezeit der Domain als einfacher Performance-Indikator.
- Trend-Charts: Visualisierung der Ranking-Entwicklung über die Zeit.
- Info-Boxen: Alle Ergebnisse werden übersichtlich in Infoboxen angezeigt, auflockerbar durch AJAX.
- Ein Dateiformat: PHP, HTML, CSS und JS sind in einer Datei integriert, einfach zu deployen.
Design:
Das Dashboard präsentiert Ergebnisse in klar strukturierten Boxen mit responsive Charts. Es ist schlicht, modern und eignet sich sowohl für einzelne Analysen als auch für laufende SEO-Monitorings.
<?php
// WARNUNG: Häufiges Scraping kann Google blockieren. Nutzung erfolgt auf eigene Verantwortung.
$dataFile = 'seo_full_history.json';
if(!file_exists($dataFile)) file_put_contents($dataFile,json_encode([]));
if(isset($_POST['action']) && $_POST['action']==='check') {
$keywords = array_map('trim', explode(',', $_POST['keywords']));
$domain = escapeshellarg($_POST['domain']);
$resultsAll = [];
foreach($keywords as $keywordRaw){
$keyword = escapeshellarg($keywordRaw);
$script = <<<JS
const puppeteer = require('puppeteer');
(async () => {
const keyword = process.argv[2];
const domain = process.argv[3];
const browser = await puppeteer.launch({headless:true});
const page = await browser.newPage();
await page.goto('https://www.google.com/search?q=' + encodeURIComponent(keyword));
const results = await page.evaluate(() => {
let data = [];
document.querySelectorAll('div.g').forEach(el => {
const a = el.querySelector('a');
const title = el.querySelector('h3') ? el.querySelector('h3').innerText : '';
const url = a ? a.href : '';
const desc = el.querySelector('.IsZvec') ? el.querySelector('.IsZvec').innerText : '';
if(url) data.push({title,url,desc});
});
return data;
});
let position = null;
let competitors = [];
results.forEach((r,i)=>{
if(r.url.includes(domain)) position = i+1;
else competitors.push(r.url);
});
// Einfacher Meta-Check auf erster Treffer der Domain
let meta = {};
try{
await page.goto('https://'+domain.replace(/https?:\/\//,''));
meta.title = await page.title();
meta.description = await page.$eval('meta[name="description"]',el=>el.content).catch(()=>'');
meta.h1 = await page.$eval('h1',el=>el.innerText).catch(()=>'');
const performanceTiming = JSON.parse(await page.evaluate(()=>JSON.stringify(window.performance.timing)));
meta.loadTime = performanceTiming.loadEventEnd - performanceTiming.navigationStart;
} catch(e){}
await browser.close();
console.log(JSON.stringify({keyword,position,competitors,meta}));
})();
JS;
$tmpFile = tempnam(sys_get_temp_dir(),'seo').'.js';
file_put_contents($tmpFile,$script);
$output = shell_exec("node ".escapeshellarg($tmpFile)." $keyword $domain");
unlink($tmpFile);
$res = json_decode($output,true);
$res['timestamp'] = date('Y-m-d H:i:s');
$resultsAll[] = $res;
$history = json_decode(file_get_contents($dataFile),true);
$history[] = $res;
file_put_contents($dataFile,json_encode($history));
}
header('Content-Type: application/json');
echo json_encode($resultsAll);
exit;
}
if(isset($_POST['action']) && $_POST['action']==='history'){
echo file_get_contents($dataFile);
exit;
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Dreamcodes SEO Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body{font-family:Arial,sans-serif;background:#f4f4f4;padding:20px;}
h1{text-align:center;}
.form-box{background:#fff;padding:20px;border-radius:8px;max-width:700px;margin:20px auto;}
.input-field{width:100%;padding:10px;margin:10px 0;border-radius:5px;border:1px solid #ccc;}
.button{padding:10px 20px;border:none;background:#007bff;color:#fff;border-radius:5px;cursor:pointer;}
.button:hover{background:#0056b3;}
.result-box{background:#fff;padding:20px;border-radius:8px;margin-top:20px;}
.info-box{background:#e9f7ef;border-left:5px solid #28a745;padding:10px;margin:10px 0;}
.chart-container{width:100%;max-width:900px;margin:20px auto;}
</style>
</head>
<body>
<h1>SEO Dashboard</h1>
<div class="form-box">
<input type="text" id="keywords" class="input-field" placeholder="Keywords eingeben, getrennt durch Kommas">
<input type="text" id="domain" class="input-field" placeholder="Domain eingeben">
<button class="button" onclick="checkSEO()">Analyse starten</button>
</div>
<div id="results" class="result-box" style="display:none;"></div>
<div class="chart-container">
<canvas id="trendChart"></canvas>
</div>
<script>
function checkSEO(){
const keywords=document.getElementById('keywords').value;
const domain=document.getElementById('domain').value;
if(!keywords||!domain) return alert('Bitte Keywords und Domain eingeben.');
const resultsDiv=document.getElementById('results');
resultsDiv.style.display='block';
resultsDiv.innerHTML='Bitte warten...';
fetch('',{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:'action=check&keywords='+encodeURIComponent(keywords)+'&domain='+encodeURIComponent(domain)
}).then(r=>r.json()).then(data=>{
let html='<h2>Ergebnisse</h2>';
data.forEach(d=>{
html+=`<div class="info-box">
<h3>${d.keyword}</h3>
<p>Position: ${d.position?d.position:'nicht gelistet'}</p>
<p>Konkurrenzdomains: ${d.competitors.slice(0,5).join(', ')}</p>
<p>Meta Title: ${d.meta.title}</p>
<p>Meta Description: ${d.meta.description}</p>
<p>H1: ${d.meta.h1}</p>
<p>Ladezeit: ${d.meta.loadTime?d.meta.loadTime+'ms':'n/a'}</p>
</div>`;
});
resultsDiv.innerHTML=html;
loadTrendChart();
});
}
function loadTrendChart(){
fetch('',{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:'action=history'
}).then(r=>r.json()).then(history=>{
const labels=[...new Set(history.map(h=>h.timestamp))];
const keywords=[...new Set(history.map(h=>h.keyword))];
const datasets=keywords.map(k=>{
return {
label:k,
data: labels.map(l=>{
const entry=history.find(h=>h.keyword===k && h.timestamp===l);
return entry&&entry.position?entry.position:null;
}),
fill:false,
borderColor:'#'+Math.floor(Math.random()*16777215).toString(16),
tension:0.2
};
});
const ctx=document.getElementById('trendChart').getContext('2d');
new Chart(ctx,{
type:'line',
data:{labels,datasets},
options:{responsive:true,plugins:{legend:{position:'bottom'}},scales:{y:{reverse:true,beginAtZero:false}}}
});
});
}
</script>
<div class="footer-box" style="text-align:center;margin-top:40px;padding:10px;background:#fff;border-radius:8px;">
<p>© <?php echo date("Y"); ?> Dreamcodes.net – Alle Rechte vorbehalten</p>
</div>
</body>
</html>