Парсинг People Also Ask и автодополнения Google для исследования ключевых слов: руководство по Python

Практическое руководство по парсингу People Also Ask и автодополнения Google на Python: готовый код, residential-прокси, кластеризация и экспорт ключевых слов для SEO.

Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)
В этой статье

Парсинг People Also Ask и автодополнения Google — один из самых недооценённых способов собрать реальные поисковые запросы пользователей бесплатно. В отличие от платных инструментов вроде Ahrefs или SEMrush, Google сам предоставляет три источника данных, которые отражают фактический поиск: автодополнение (Autocomplete), блок People Also Ask (PAA) и связанные запросы (Related Searches). В этом руководстве мы разберём, как извлекать эти данные на Python с помощью residential-прокси, чтобы получать чистые локализованные результаты без блокировок.

Парсинг People Also Ask и автодополнения Google: три источника ключевых слов

Google предлагает три публичных источника поисковых подсказок, каждый из которых отражает разный аспект интента пользователя:

ИсточникURL / расположениеТип интентаОбъём данных
Autocomplete (Suggest)suggestqueries.google.com/complete/search?client=chrome&q=…Все типы — навигационный, информационный, транзакционный10 подсказок на запрос
People Also AskSERP, блок div[role='treeitem']Информационный, вопросный4–8 вопросов на SERP, рекурсивно
Related SearchesНиз SERP, блок связанных запросовСмешанный, контекстный8–10 запросов

Автодополнение Google возвращает JSON-ответ с подсказками, основанными на реальном поисковом объёме. Это означает, что каждая подсказка — это запрос, который пользователи реально вводят. Технология автодополнения работает на основе агрегированных данных о поисковых запросах, что делает её надёжным индикатором спроса.

People Also Ask — это блок вопросов, который Google показывает прямо в результатах поиска. Каждый вопрос можно развернуть (кликнуть по аккордеону), и Google подгрузит ответ и новые вложенные вопросы. Это создаёт рекурсивную структуру: из 4 начальных вопросов можно получить десятки вложенных.

Related Searches — самый простой источник: блок внизу страницы результатов с 8–10 связанными запросами. Полезен для быстрого расширения семантического ядра.

Технический контекст: почему Google ограничивает автоматические запросы

Проблема в том, что Google активно защищает свои SERP от автоматизированного скрапинга. Когда вы делаете десятки запросов в секунду с одного IP-адреса, Google срабатывает на несколько уровней защиты:

  • Per-IP rate limits — после ~50–100 запросов с одного IP за короткое время Google начинает возвращать CAPTCHA или HTTP 429.
  • Locale bias — автодополнение и PAA зависят от геолокации IP. Запрос из немецкого IP вернёт немецкие подсказки, даже если вы передаёте gl=us. Это критично для локализованного keyword research.
  • Fingerprinting — Google анализирует заголовки, TLS-отпечаток и поведение, чтобы отличить ботов от реальных браузеров.

Поэтому для парсинга автодополнения и PAA нужны residential-прокси с геотаргетингом. Google документирует FAQ-разметку для валидных PAA-блоков, но не предоставляет публичный API для их извлечения — остаётся только скрапинг.

Настройка ProxyHat: residential-прокси с геотаргетингом

ProxyHat предоставляет residential-прокси с поддержкой country- и city-level геотаргетинга через параметры в username. Это позволяет получать локализованные подсказки из любой страны без VPN.

Базовые параметры подключения:

# HTTP-прокси (порт 8080)
http://user-country-US:pass@gate.proxyhat.com:8080

# HTTP-прокси с городом
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080

# SOCKS5-прокси (порт 1080)
socks5://user-country-US:pass@gate.proxyhat.com:1080

# Sticky-сессия (один IP на все запросы)
http://user-session-abc123-country-US:pass@gate.proxyhat.com:8080

Для keyword research обычно нужен rotating-режим (каждый запрос — новый IP), чтобы распределить нагрузку и избежать блокировок. Sticky-сессии полезны, когда нужно сохранить один IP для серии связанных запросов — например, при навигации по SERP в Playwright.

Практическая реализация: парсинг автодополнения через httpx и ProxyHat

Начнём с самого простого источника — endpoint автодополнения. Этот endpoint возвращает JSON, поэтому не нужен браузер — достаточно HTTP-клиента.

Базовый запрос через curl

curl -x http://user-country-US:pass@gate.proxyhat.com:8080 \
  "https://suggestqueries.google.com/complete/search?client=chrome&q=python"

Ответ — JSON-массив, где второй элемент содержит список подсказок в формате ["подсказка", объём_поиска].

Python: httpx + ProxyHat для автодополнения

import httpx
import json
from typing import Optional

def fetch_autocomplete(
    query: str,
    country: str = "US",
    proxy_user: str = "user",
    proxy_pass: str = "pass"
) -> list[str]:
    """Получить подсказки автодополнения Google через residential-прокси."""
    proxy_url = f"http://{proxy_user}-country-{country}:{proxy_pass}@gate.proxyhat.com:8080"
    url = "https://suggestqueries.google.com/complete/search"
    params = {"client": "chrome", "q": query}
    
    with httpx.Client(proxy=proxy_url, timeout=15) as client:
        resp = client.get(url, params=params)
        resp.raise_for_status()
        data = resp.json()
    
    # data[1] — список подсказок, data[1][i][0] — текст подсказки
    suggestions = [item[0] for item in data[1]] if len(data) > 1 else []
    return suggestions

# Пример
if __name__ == "__main__":
    results = fetch_autocomplete("best python framework", country="US")
    for s in results:
        print(s)

Этот код делает один запрос через residential-прокси с геотаргетингом США. Подсказки будут отражать реальный американский поиск.

Расширение seed-ключевых слов: от одного запроса к сотням long-tail вариантов

Один seed-запрос даёт ~10 подсказок. Чтобы получить сотни, нужно систематически расширять seed с помощью префиксов и суффиксов. Техника проста: добавляйте буквы a-z и модификаторы к seed-запросу.

import itertools
import asyncio
import httpx
from typing import Optional

MODIFIERS = [
    "best", "how to", "what is", "why", "vs", "alternatives",
    "free", "near me", "for beginners", "review", "pricing",
    "tutorial", "examples", "download", "online"
]
ALPHABET = list("abcdefghijklmnopqrstuvwxyz")

def expand_seed(seed: str) -> list[str]:
    """Превратить один seed-запрос в сотни поисковых подсказок."""
    queries = [seed]
    # Префикс с каждой буквой алфавита
    queries += [f"{seed} {ch}" for ch in ALPHABET]
    # Модификатор как префикс
    queries += [f"{mod} {seed}" for mod in MODIFIERS]
    # Модификатор как суффикс
    queries += [f"{seed} {mod}" for mod in MODIFIERS]
    return list(set(queries))

async def fetch_suggestions(
    query: str,
    proxy_url: str,
    client: httpx.AsyncClient
) -> list[str]:
    url = "https://suggestqueries.google.com/complete/search"
    params = {"client": "chrome", "q": query}
    try:
        resp = await client.get(url, params=params)
        resp.raise_for_status()
        data = resp.json()
        return [item[0] for item in data[1]] if len(data) > 1 else []
    except Exception as e:
        print(f"Error for '{query}': {e}")
        return []

async def batch_expand(
    seed: str,
    country: str = "US",
    max_concurrent: int = 10
) -> dict[str, list[str]]:
    """Асинхронно собрать подсказки для всех расширенных запросов."""
    proxy = f"http://user-country-{country}:pass@gate.proxyhat.com:8080"
    expanded = expand_seed(seed)
    sem = asyncio.Semaphore(max_concurrent)
    results = {}
    
    async with httpx.AsyncClient(proxy=proxy, timeout=15) as client:
        async def limited_fetch(q):
            async with sem:
                await asyncio.sleep(1.5)  # вежливая задержка
                return q, await fetch_suggestions(q, proxy, client)
        
        tasks = [limited_fetch(q) for q in expanded]
        done = await asyncio.gather(*tasks)
    
    for q, suggestions in done:
        results[q] = suggestions
    return results

# Запуск
if __name__ == "__main__":
    data = asyncio.run(batch_expand("python framework", country="US"))
    total = sum(len(v) for v in data.values())
    print(f"Собрано {total} подсказок из {len(data)} запросов")

Из одного seed «python framework» этот код сгенерирует ~67 запросов (1 + 26 букв + 15 префиксов + 15 суффиксов), каждый из которых вернёт до 10 подсказок — итого до 670 уникальных long-tail ключевых слов.

Извлечение People Also Ask с помощью Playwright и ProxyHat

People Also Ask требует рендеринга JavaScript и клика по аккордеонам для раскрытия вложенных вопросов. Это означает, что нужен браузер — мы будем использовать Playwright.

from playwright.async_api import async_playwright
import asyncio
import json
from typing import Optional

PROXY_SERVER = "http://gate.proxyhat.com:8080"
PROXY_USER = "user-country-US"
PROXY_PASS = "pass"

async def scrape_paa(
    keyword: str,
    max_depth: int = 4,
    country: str = "US"
) -> list[dict]:
    """
    Извлечь вопросы People Also Ask и источники ответов.
    
    Args:
        keyword: поисковый запрос
        max_depth: сколько раз кликать по аккордеонам
        country: код страны для геотаргетинга прокси
    """
    questions = []
    seen = set()
    
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            proxy={
                "server": PROXY_SERVER,
                "username": f"user-country-{country}",
                "password": PROXY_PASS
            }
        )
        page = await browser.new_page()
        
        # Устанавливаем реалистичный User-Agent
        await page.set_extra_http_headers({
            "Accept-Language": "en-US,en;q=0.9"
        })
        
        await page.goto(
            f"https://www.google.com/search?q={keyword}&gl={country.lower()}",
            wait_until="domcontentloaded"
        )
        await page.wait_for_timeout(2000)
        
        for depth in range(max_depth):
            # Находим все элементы PAA
            paa_items = await page.query_selector_all("div[role='treeitem']")
            
            for item in paa_items:
                try:
                    text = await item.inner_text()
                    lines = text.strip().split("\n")
                    question_text = lines[0].strip()
                    
                    if question_text.endswith("?") and question_text not in seen:
                        seen.add(question_text)
                        
                        # Кликаем для раскрытия ответа и новых вопросов
                        await item.click()
                        await page.wait_for_timeout(1500)
                        
                        # Пытаемся найти источник ответа
                        answer_source = ""
                        try:
                            source_el = await page.query_selector("div[role='treeitem'] a")
                            if source_el:
                                answer_source = await source_el.get_attribute("href") or ""
                        except Exception:
                            pass
                        
                        questions.append({
                            "question": question_text,
                            "source": answer_source,
                            "keyword": keyword,
                            "depth": depth
                        })
                except Exception as e:
                    print(f"Error extracting PAA item: {e}")
                    continue
        
        await browser.close()
    
    return questions

# Запуск
if __name__ == "__main__":
    paa_data = asyncio.run(scrape_paa("what is python", max_depth=4))
    print(f"Извлечено {len(paa_data)} вопросов PAA")
    for q in paa_data[:10]:
        print(f"  [{q['depth']}] {q['question']}")

Каждый клик по аккордеону раскрывает ответ и добавляет 1–2 новых вопроса. При max_depth=4 из 4 начальных вопросов можно получить 20–40 вложенных вопросов. Поле source содержит URL сайта, который Google цитирует как источник ответа — полезно для анализа конкурентов в контент-маркетинге.

Дедупликация, кластеризация и экспорт в CSV

После сбора данных из автодополнения и PAA нужно объединить, дедуплицировать и кластеризовать по интенту для планирования контента.

import csv
import re
from collections import defaultdict
from typing import Optional

def classify_intent(keyword: str) -> str:
    """Классифицировать поисковый интент по паттернам."""
    kw_lower = keyword.lower().strip()
    
    if kw_lower.startswith(("how to", "how do", "how does", "how can")):
        return "how-to"
    if kw_lower.startswith(("what is", "what are", "what does", "who is", "who are")):
        return "informational"
    if kw_lower.startswith(("why", "when", "where")):
        return "informational"
    if kw_lower.startswith(("best", "top", "review", "vs", "vs.", "compare")):
        return "commercial"
    if kw_lower.startswith(("buy", "price", "pricing", "cost", "cheap", "discount")):
        return "transactional"
    if "near me" in kw_lower or kw_lower.startswith(("find", "locate")):
        return "local"
    return "general"

def dedupe_and_export(
    autocomplete_results: dict[str, list[str]],
    paa_results: list[dict],
    output_file: str = "keywords.csv"
) -> dict[str, int]:
    """
    Объединить данные из автодополнения и PAA, 
    дедуплицировать, кластеризовать и экспортировать в CSV.
    """
    all_keywords = set()
    keyword_meta = {}  # keyword -> {source, seed, intent}
    
    # Обработка автодополнения
    for seed, suggestions in autocomplete_results.items():
        for s in suggestions:
            clean = s.strip().lower()
            if clean and clean not in all_keywords:
                all_keywords.add(clean)
                keyword_meta[clean] = {
                    "source": "autocomplete",
                    "seed": seed,
                    "intent": classify_intent(clean)
                }
    
    # Обработка PAA
    for item in paa_results:
        clean = item["question"].strip().lower()
        if clean and clean not in all_keywords:
            all_keywords.add(clean)
            keyword_meta[clean] = {
                "source": "paa",
                "seed": item["keyword"],
                "intent": classify_intent(clean)
            }
    
    # Кластеризация по интенту
    clusters = defaultdict(list)
 for kw in all_keywords:
        clusters[keyword_meta[kw]["intent"]].append(kw)
    
    # Экспорт в CSV
    with open(output_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["keyword", "intent", "source", "seed"])
        for kw in sorted(all_keywords):
            meta = keyword_meta[kw]
            writer.writerow([kw, meta["intent"], meta["source"], meta["seed"]])
    
    # Статистика
    stats = {intent: len(items) for intent, items in clusters.items()}
    print(f"\nЭкспортировано {len(all_keywords)} уникальных ключевых слов в {output_file}")
    print("\nКластеры по интенту:")
    for intent, count in sorted(stats.items(), key=lambda x: -x[1]):
        print(f"  {intent}: {count}")
    
    return stats

# Пример использования
if __name__ == "__main__":
    # Предполагается, что autocomplete_data и paa_data уже собраны
    # stats = dedupe_and_export(autocomplete_data, paa_data, "research_keywords.csv")

На выходе получается CSV-файл с колонками keyword, intent, source и seed. Этот файл可以直接 можно импортировать в Google Sheets, Notion или любой SEO-инструмент для дальнейшего планирования контента.

Распространённые ошибки и граничные случаи

1. Локальный bias автодополнения

Автодополнение Google жёстко привязано к геолокации IP. Если вы парсите из дата-центра в Франкфурте без прокси, вы получите немецкие подсказки даже для английских запросов. Residential-прокси с параметром country-US решают эту проблему — Google видит американский IP и возвращает американские подсказки.

2. Пустые ответы при высоком rate

При превышении ~100 запросов в минуту с одного IP Google начинает возвращать пустые JSON-массивы вместо блокировки. Это легко пропустить: код не падает, но данные пустые. Решение — ограничить concurrency до 10 одновременных запросов и добавить задержку 1–2 секунды между запросами.

3. Изменение структуры SERP

Селекторы PAA (div[role='treeitem']) могут меняться. Google регулярно обновляет DOM-структуру SERP. Рекомендуется периодически проверять селекторы и иметь fallback-логику. Для production-систем лучше использовать несколько альтернативных селекторов.

4. Дубликаты при рекурсивном PAA

При раскрытии аккордеонов Google может показывать одни и те же вопросы на разных уровнях вложенности. Множество seen в коде выше решает эту проблему — дубликаты пропускаются.

Этика: ответственный подход к сбору данных

Автодополнение и PAA — это публичные данные, которые Google показывает каждому пользователю. Однако массовый скрапинг создаёт нагрузку на инфраструктуру Google. Несколько принципов ответственного подхода:

  • Соблюдайте robots.txt — проверьте https://www.google.com/robots.txt перед началом скрапинга.
  • Троттлинг — держите задержку 1–2 секунды между запросами, не превышайте 10 одновременных соединений.
  • Используйте официальные API где возможно — Google Keyword Planner API (через Google Ads) предоставляет данные о поисковом объёме легально и без риска блокировок. Скрапинг оправдан, когда нужен long-tail, который не покрывает Keyword Planner.
  • GDPR и CCPA — поисковые подсказки не содержат персональных данных, но если вы собираете данные о конкретных пользователях, учитывайте требования GDPR и CCPA.

Ознакомьтесь с тарифами ProxyHat для выбора подходящего плана residential-прокси, а также со списком доступных геолокаций для точного таргетинга.

Ключевые выводы

Резюме: Парсинг People Also Ask и автодополнения Google — это бесплатный способ собрать сотни реальных поисковых запросов. Три источника (Autocomplete, PAA, Related Searches) покрывают разные типы интента. Residential-прокси с геотаргетингом необходимы для получения локализованных данных без блокировок. Дедупликация и кластеризация по интенту превращают сырые данные в готовый контент-план.

  • Автодополнение возвращает ~10 подсказок на запрос; расширение через a-z и модификаторы превращает один seed в 500+ ключевых слов.
  • PAA даёт вопросные запросы с источниками ответов — идеально для FAQ-страниц и контент-маркетинга.
  • Residential-прокси с country-level геотаргетингом (user-country-US) решают проблему локального bias и блокировок.
  • Ограничение concurrency до 10 и задержка 1–2 секунды обеспечивают вежливый скрапинг без CAPTCHA.
  • Экспорт в CSV с кластеризацией по интенту создаёт готовый вход для контент-планирования.

Готовы начать? Изучите варианты использования ProxyHat для веб-скрапинга и SERP-трекинга, или посетите документацию ProxyHat для подробной настройки прокси.

Часто задаваемые вопросы

Что такое парсинг People Also Ask и автодополнения Google для исследования ключевых слов?

Это процесс автоматизированного извлечения поисковых подсказок Google (Autocomplete) и вопросов из блока People Also Ask (PAA) на Python для сбора реальных поисковых запросов пользователей. Autocomplete возвращает до 10 подсказок на запрос через JSON-endpoint suggestqueries.google.com, а PAA содержит вопросные запросы, которые можно рекурсивно расширять кликами по аккордеонам. Вместе они образуют бесплатный источник long-tail ключевых слов для SEO-исследований и контент-планирования.

Зачем нужны прокси при парсинге People Also Ask и автодополнения Google?

Google ограничивает количество автоматизированных запросов с одного IP-адреса — после примерно 50–100 запросов за короткое время начинаются CAPTCHA и пустые ответы. Кроме того, автодополнение жёстко привязано к геолокации IP: запрос из немецкого дата-центра вернёт немецкие подсказки даже для английских запросов. Residential-прокси с country-level геотаргетингом (например, user-country-US) решают обе проблемы: распределяют нагрузку по множеству IP и обеспечивают локализованные результаты без VPN.

Какой тип прокси лучше всего подходит для парсинга People Also Ask и автодополнения Google?

Residential-прокси — оптимальный выбор для парсинга Google. В отличие от datacenter-прокси, residential IP-адреса принадлежат реальным интернет-провайдерам и выглядят как обычные пользователи, что снижает риск блокировок. Mobile-прокси также эффективны, но обычно дороже. Для парсинга автодополнения достаточно HTTP-прокси на порту 8080, а для PAA с Playwright нужен прокси с поддержкой браузерного соединения. ProxyHat предоставляет residential-прокси с геотаргетингом по стране и городу через параметры в username.

Как избежать блокировок при парсинге People Also Ask и автодополнения Google?

Используйте несколько стратегий: ограничьте concurrency до 10 одновременных запросов, добавьте задержку 1–2 секунды между запросами, используйте rotating residential-прокси для распределения запросов по разным IP, применяйте реалистичные User-Agent заголовки и Accept-Language, а также отслеживайте пустые ответы — Google иногда возвращает пустой JSON вместо явной блокировки. Для Playwright используйте headless-режим с реалистичными viewport-размерами и задержками между кликами по аккордеонам PAA.

Можно ли использовать официальные API Google вместо скрапинга для исследования ключевых слов?

Google Keyword Planner API (через Google Ads) предоставляет данные о поисковом объёме легально, но требует рекламного аккаунта и не покрывает long-tail запросы с низким объёмом. Google Trends API даёт относительную популярность, но не конкретные подсказки. Скрапинг автодополнения и PAA оправдан, когда нужны именно long-tail варианты, вопросные запросы и локализованные подсказки, которые не доступны через официальные API. При масштабировании рекомендуется комбинировать оба подхода.

Готовы начать?

Резидентные, ISP и мобильные прокси в 148+ странах. Создайте бесплатный аккаунт.

Создать бесплатный аккаунт
← Вернуться в Блог