Diese Woche am beliebtesten

Vertiefendes Material

Seo Dashboard

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:

  1. Keyword-Position: Ermittelt die aktuelle Platzierung deiner Domain für beliebige Keywords in Google.
  2. Konkurrenzanalyse: Zeigt die Top-Konkurrenten für jedes Keyword in den Suchergebnissen an.
  3. Sichtbarkeit: Übersicht über Top-10 und Top-100 Rankings, inkl. Historie.
  4. Meta-Daten Check: Prüft Title, Description und H1 deiner Domain.
  5. Page Speed: Misst die Ladezeit der Domain als einfacher Performance-Indikator.
  6. Trend-Charts: Visualisierung der Ranking-Entwicklung über die Zeit.
  7. Info-Boxen: Alle Ergebnisse werden übersichtlich in Infoboxen angezeigt, auflockerbar durch AJAX.
  8. 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>
Dreamcodes Redaktion
Dreamcodes Redaktion
Jeder Inhalt auf Dreamcodes entsteht mit einem klaren Anspruch: geprüfte Praxis statt schneller Theorie. Was hier veröffentlicht wird, basiert auf Best Practices, echten Projekterfahrungen und technischem Verständnis, das über das Offensichtliche hinausgeht. Unser Ziel ist ein Fundament, auf dem du aufbauen kannst, nicht eines, das beim ersten produktiven Einsatz bricht. Wie du die Inhalte integrierst, absicherst und in deinen Kontext überträgst, liegt bei dir. Die fachliche Grundlage liefern wir, die Verantwortung für den Einsatz bleibt deine.
Vorheriges Tutorial
Nächstes Tutorial

Vielleicht einen Blick WERT?