More info
  • Home
  • >
  • Blog
  • >
  • Automation
  • >
  • Günstigere Alternative zum Keyword Planner: 130k Keywords mit Python abrufen

  Minuten Lesedauer verbleibend

März 23, 2025

SEO, Tutorial
Google Keyword Planner Alternative

5
(1)

Der Google Keyword Planner ist praktisch – aber bei großen Keyword-Listen, Automatisierung oder API-Nutzung stößt du schnell an Grenzen.
Wenn du 10.000 oder sogar 130.000 Keywords analysieren willst, brauchst du eine skalierbare, bezahlbare und flexible Lösung.

Genau hier kommt DataForSEO ins Spiel – in Kombination mit Python kannst du dir dein eigenes Keyword-Tool bauen. Schau dir hier das Video dazu an:

Sie sehen gerade einen Platzhalterinhalt von Youtube. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.

Mehr Informationen

In diesem Tutorial zeige ich dir Schritt für Schritt, wie du das machst – inklusive Batching, Kostenkontrolle und Excel-Export.

Warum eine Alternative zum Keyword Planner?

Der Google Keyword Planner ist zwar solide, aber:

  • stark limitiert bei Keyword-Mengen
  • wenig flexibel für automatisierte Workflows
  • API-Zugang nur mit aktivem Google Ads Account

Wenn du also große Keyword-Listen verarbeiten willst (z. B. aus BigQuery, SEO-Tools oder eigenen Datenquellen), brauchst du eine skalierbare Lösung – wie DataForSEO + Python.

Voraussetzungen

Python-Pakete installieren

pip install pandas requests openpyxl

DataForSEO-Zugang

Registriere dich auf DataForSEO und hole dir deine Zugangsdaten (Login & Passwort).
Damit kannst du ihre leistungsfähige API nutzen, die speziell für große Abfragen gedacht ist – die perfekte Keyword Planner Alternative für Entwickler:innen und SEOs.

API-Zugang

Registriere dich unter DataForSEO und hol dir:

  • Login
  • Passwort

Diese brauchst du zur Authentifizierung via Basic Auth.

Logik des Setups

  • Keywords aus Excel-Datei laden
  • In Batches à 1.000 an die API senden
  • Ergebnisse inkl. CPC, Suchvolumen und monatlicher Entwicklung abrufen
  • Fortschritt, API-Kosten und Ergebnisse sichern (Pickle + Excel-Export)
  • Nach Abbruch nahtlos wieder starten

Wichtige Features im Code

Batching:

Keywords werden in Gruppen à 1000 an die API geschickt, um Limits einzuhalten.

Pickle & Fortschritts-Tracking:

Falls das Skript abstürzt, kannst du nahtlos weitermachen – inklusive der Kosten, Fortschritte und Ergebnisse.

API-Kostenübersicht:

Nach jedem Batch werden die Kosten protokolliert – und am Ende als Tabelle in eine Excel-Datei exportiert.

Keyword-Filterung:

  • Max. 80 Zeichen
  • Max. 10 Wörter
  • Bereinigung von Zeichen wie , ©, ® etc.

Ordnerstruktur (empfohlen)

projekt/
│
├── keywords.xlsx                ← Deine Keyword-Liste
├── get_sv_data4seo.py          ← Hauptskript
├── backup_results.pkl          ← automatische Zwischenspeicherung
├── final_results.xlsx          ← Exportiertes Ergebnis (3 Sheets)
├── invalid_keywords.txt        ← gefilterte / unbrauchbare Keywords
└── progress.txt (optional)     ← optionales Fortschrittstracking

Vorteile gegenüber dem Keyword Planner

Google Keyword PlannerDataForSEO + Python (dieses Tutorial)
Limit bei MassenabfragenBeliebig viele Batches möglich
Unflexibel, WeboberflächeVoll automatisiert via Code
Kaum Clustering oder ExportEigene Analysen & Filter möglich
API nur mit Google AdsAPI direkt & transparent nutzbar

👉 Du bekommst also eine echte Alternative zum Keyword Planner, wenn du tiefere, schnellere oder umfangreichere Keyword-Daten brauchst.

Skript:

Es sind Funktionen im Skript (wie die advanced cleaning Methode der Keywords) enthalten, die ich nicht veröffentlichen kann, sofern wenn du Zugang möchtest bzw. Hilfe brauchst bei der Einrichtung dann buche dir hier einen Support Termin.

import os
import time
import json
import base64
import pandas as pd
import requests
import numpy as np
from dotenv import load_dotenv
load_dotenv()
## import word_frequency as wf advanced cleaning
import re
import unicodedata

# --- Konfiguration ---
PICKLE_BACKUP = "backup_results.pkl"
PROGRESS_FILE = "progress.txt"
BATCH_SIZE = 1000
LOCATION_CODE = 2276
LANGUAGE_CODE = "de"
MAX_RETRIES = 3
RETRY_DELAY = 3  # Sekunden

USERNAME = "login"
PASSWORD = "password"
AUTH_HEADER = os.getenv("d4seo") #base64.b64encode(f"{USERNAME}:{PASSWORD}".encode()).decode()

API_URL = "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live"

def return_path():
    EXCEL_FILE = "keywords.xslx"  # muss eine Spalte "keyword" enthalten
    return EXCEL_FILE

def clean_keywords(keywords):
    cleaned = keywords ## wf.basic_cleaning(keywords)

    return cleaned

FORBIDDEN_CHARS = set("™©®✓•→←≠∞¿¡§¶…")

def is_valid_keyword(kw: str) -> bool:
    try:
        kw = kw.strip()
        if not kw:
            return False

        # Entferne verbotene Zeichen
        for char in FORBIDDEN_CHARS:
            kw = kw.replace(char, "")

        kw_norm = unicodedata.normalize("NFKC", kw)

        # Entferne Steuerzeichen
        kw_cleaned = ''.join(c for c in kw_norm if unicodedata.category(c)[0] != 'C')

        # Prüfe verdächtige Zeichen mit Unicode-Name
        for char in kw_cleaned:
            try:
                name = unicodedata.name(char)
                if not any(part in name for part in ["LATIN", "DIGIT", "SPACE", "DASH", "HYPHEN"]):
                    return False
            except ValueError:
                return False

        # Filter kaputter Kodierungen
        if re.search(r"[ãåÓ€]", kw_cleaned):
            return False

        # Zeichenverhältnis
        valid_chars = re.findall(r"[a-zA-Z0-9äöüßéèêáàâíìîóòôúùûčšžăîâăëç\- ]", kw_cleaned.lower())
        ratio = len(valid_chars) / max(len(kw_cleaned), 1)
        if ratio < 0.7:
            return False

        # Mindestens 3 Buchstaben
        if len(re.findall(r"[a-zA-Z]", kw_cleaned)) < 3:
            return False

        return True

    except Exception:
        return False

# ----------------- Hilfsfunktionen -----------------
def load_keywords_from_excel(filepath: str) -> list:
    df = pd.read_excel(filepath)
    return df["keyword"].dropna().astype(str).tolist()

def batch_keywords(keywords: list, size: int) -> list:
    return [keywords[i:i + size] for i in range(0, len(keywords), size)]

def send_batch_request(keywords_batch: list) -> dict:
    payload = [{
        "keywords": keywords_batch,
        "location_code": LOCATION_CODE,
        "language_code": LANGUAGE_CODE,
        "sort_by": "relevance"
    }]
    headers = {
        'Authorization': f'Basic {AUTH_HEADER}',
        'Content-Type': 'application/json'
    }
    response = requests.post(API_URL, headers=headers, data=json.dumps(payload))
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"HTTP {response.status_code}: {response.text}")

def parse_response(response_json: dict) -> tuple[pd.DataFrame, pd.DataFrame]:
    results = []
    monthly_results = []
    error_keywords = []

    tasks = response_json.get("tasks", [])
    for task in tasks:
        items = task.get("result", [])
        for item in items:
            try:
                keyword = item.get("keyword")
                results.append({
                    "keyword": keyword,
                    "search_volume": item.get("search_volume"),
                    "competition": item.get("competition"),
                    "cpc": item.get("cpc"),
                    "currency": item.get("currency")
                })

                monthly_searches = item.get("monthly_searches")
                if isinstance(monthly_searches, list):
                    for ms in monthly_searches:
                        monthly_results.append({
                            "keyword": keyword,
                            "year": ms.get("year"),
                            "month": ms.get("month"),
                            "search_volume": ms.get("search_volume")
                        })

            except Exception as e:
                error_keywords.append((item.get("keyword"), str(e)))
                print(f"Fehler beim Verarbeiten von Keyword '{item.get('keyword')}': {e}")

    return pd.DataFrame(results), pd.DataFrame(monthly_results)


def save_progress(index: int):
    with open(PROGRESS_FILE, "w") as f:
        f.write(str(index))

def load_progress() -> int:
    if os.path.exists(PROGRESS_FILE):
        with open(PROGRESS_FILE, "r") as f:
            return int(f.read())
    return 0

def load_existing_results() -> tuple[pd.DataFrame, pd.DataFrame]:
    if os.path.exists(PICKLE_BACKUP):
        data = pd.read_pickle(PICKLE_BACKUP)
        return (
            data.get("results", pd.DataFrame()),
            data.get("monthly", pd.DataFrame()),
            data.get("api_costs", pd.DataFrame()),
            data.get("status", {}).get("progress_index", 0),
            data.get("status", {}).get("total_cost", 0.0)
        )
    else:
        return pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), 0, 0.0

def save_all_to_pickle(results_df, monthly_df, api_costs_df, progress_index, total_api_cost):
    data = {
        "results": results_df,
        "monthly": monthly_df,
        "api_costs": api_costs_df,
        "status": {
            "progress_index": progress_index,
            "total_cost": total_api_cost
        }
    }
    pd.to_pickle(data, PICKLE_BACKUP)

# ----------------- Filter Keywords -----------------'''
#     dataforseo: max. 80 Zeichen
#     max. 10 Wörter
#     Umwandlung in Kleinbuchstaben
#     :param keywords:
#     :param log_file:
#     :return:
#     '''
def filter_keywords(keywords: list[str], log_file: str = "invalid_keywords.txt") -> list[str]:
    filtered = []
    invalid = []

    for kw in keywords:
        kw_clean = kw.strip().lower()
        if (
            len(kw_clean) <= 80
            and len(kw_clean.split()) <= 10
            and is_valid_keyword(kw_clean)
        ):
            filtered.append(kw_clean)
        else:
            invalid.append(kw.strip())

    if invalid:
        with open(log_file, "w", encoding="utf-8") as f:
            f.write("Ungültige Keywords (zu lang, zu viele Wörter oder ungültige Zeichen):\n\n")
            for kw in invalid:
                f.write(f"{kw}\n")
        print(f"{len(invalid)} ungültige Keywords wurden ignoriert und in '{log_file}' gespeichert.")

    return filtered

def clean_keyword_simple(kw: str) -> str:
    """
    Entfernt gezielt geschützte Zeichen wie ™, ©, ® etc. aus dem Keyword.
    Gibt das bereinigte Keyword zurück.
    """
    FORBIDDEN_CHARS = set("™©®✓•→←≠∞¿¡§¶…")

    kw_cleaned = kw.strip()
    for char in FORBIDDEN_CHARS:
        kw_cleaned = kw_cleaned.replace(char, "")

    return kw_cleaned

def main():
    print("Lade Keywords aus Excel-Datei...")
    excel_file = return_path()
    all_keywords = load_keywords_from_excel(excel_file)
    all_keywords = [clean_keyword_simple(kw) for kw in all_keywords] ## clean keywords from trademark and copyright
    all_keywords = filter_keywords(all_keywords) ## filter too long keywords
    keyword_batches = batch_keywords(all_keywords, BATCH_SIZE)
    start_index = load_progress()

    results_df, monthly_df, api_costs_df, start_index, total_api_cost = load_existing_results()
    #monthly_df = pd.DataFrame()
    total_api_cost = 0.0
    api_costs_list = []

    print(f"{len(all_keywords)} Keywords geladen. Starte ab Batch {start_index + 1} von {len(keyword_batches)}.")

    for idx in range(start_index, len(keyword_batches)):
        batch = keyword_batches[idx]
        print(f"\nVerarbeite Batch {idx + 1}/{len(keyword_batches)} ({len(batch)} Keywords)...")

        success = False
        for attempt in range(1, MAX_RETRIES + 1):
            try:
                ## Clean keywords from apostrophe
                cleaned_batch = clean_keywords(batch)

                response_json = send_batch_request(cleaned_batch)
                time.sleep(1)

                # API-Kosten extrahieren
                batch_cost = response_json.get("cost", 0.0)
                total_api_cost += batch_cost
                api_costs_list.append({
                    "batch_index": idx + 1,
                    "keyword_count": len(batch),
                    "cost_usd": batch_cost
                })
                print(f"API-Kosten für diesen Batch: {batch_cost:.3f} USD")

                df_keywords, df_monthly = parse_response(response_json)
                results_df = pd.concat([results_df, df_keywords], ignore_index=True)
                monthly_df = pd.concat([monthly_df, df_monthly], ignore_index=True)

                save_all_to_pickle(results_df, monthly_df, api_costs_df, idx + 1, total_api_cost)

                print(f"Fortschritt gespeichert – Batch {idx + 1}, Gesamtkosten: {total_api_cost:.3f} USD")

                save_progress(idx + 1)
                success = True
                break
            except Exception as e:
                print(f"Fehler bei Batch {idx + 1} (Versuch {attempt}): {e}")
                if attempt < MAX_RETRIES:
                    print(f"Warte {RETRY_DELAY} Sekunden vor erneutem Versuch...")
                    time.sleep(RETRY_DELAY)
                else:
                    print("Maximale Anzahl an Versuchen erreicht. Skript wird abgebrochen.")
                    return

        if success:
            time.sleep(1.5)  # API-Rate-Limiting

    print(f"\nGesamte API-Kosten: {total_api_cost:.3f} USD")

    # API-Kosten-Tabelle
    api_costs_df = pd.DataFrame(api_costs_list)
    api_costs_df.loc[len(api_costs_df.index)] = {
        "batch_index": "Gesamt",
        "keyword_count": api_costs_df["keyword_count"].sum(),
        "cost_usd": total_api_cost
    }

    # Export in Excel
    with pd.ExcelWriter("final_results.xlsx") as writer:
        results_df.to_excel(writer, sheet_name="Keyword-Daten", index=False)
        monthly_df.to_excel(writer, sheet_name="Monatliche Suche", index=False)
        api_costs_df.to_excel(writer, sheet_name="API-Kosten", index=False)

    print("\nExport abgeschlossen: final_results.xlsx")

if __name__ == "__main__":
    main()

Exportiertes Ergebnis

Am Ende dieses Tutorials hast du eine Excel-Datei mit:

  • Keyword-Übersicht: Suchvolumen, Wettbewerb, CPC
  • Zeitreihe: monatliche Volumenentwicklung
  • API-Kostenübersicht je Batch

Du kannst daraus z. B. Cluster bilden, saisonale Trends analysieren oder dein eigenes Keyword-Tool bauen.


Fazit

Dieses Setup ist ideal für:

  • datengetriebene SEO-Analysen
  • Performance-Marketing mit großen Keyword-Mengen
  • Reporting, Forecasting & Clustering

Wenn du nach einer Alternative zum Keyword Planner suchst, die du vollständig steuern und skalieren kannst – dann ist Python + DataForSEO genau das Richtige.

Weitere passende Artikel:

Wie hilfreich war dieser Beitrag?

Klicke auf die Sterne um zu bewerten!

Durchschnittliche Bewertung 5 / 5. Anzahl Bewertungen: 1

Bisher keine Bewertungen! Sei der Erste, der diesen Beitrag bewertet.

Profile Picture Antonio Blago
Antonio Blago

📈🧠 Hi, ich bin Antonio. Als ehemaliger Datenanalyst und Webentwickler optimiere ich #SEO datengetrieben. Mit Verkaufspsychologie und dem fundierten Neuro-SEO System® verstehe ich Nutzerverhalten und entwickle zielgerichtete Maßnahmen für deine Marketing Strategie. Folge mir gerne auf Instagram oder LinkedIn für tiefgehendes Know-how, smarte Tools und praxisnahe Tipps, die deine Online-Präsenz aufs nächste Level heben!

Über den Autor

📈🧠 Hi, ich bin Antonio. Als ehemaliger Datenanalyst und Webentwickler optimiere ich #SEO datengetrieben.
Mit Verkaufspsychologie und dem fundierten Neuro-SEO System® verstehe ich Nutzerverhalten und entwickle zielgerichtete Maßnahmen für deine Marketing Strategie. Folge mir gerne auf Instagram oder LinkedIn für tiefgehendes Know-how, smarte Tools und praxisnahe Tipps, die deine Online-Präsenz aufs nächste Level heben!

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Nutze meinen SEO Fahrplan, wie du bei Google auf Seite 1 kommst!

Trage dich dafür in meinem Newsletter ein und erhalte Zugriff für kostenlose Anleitungen, Checklisten und Tools.

>