抓取Google People Also Ask和Autocomplete用于关键词研究:Python完整指南

本文以代码优先的方式讲解如何用Python抓取Google Autocomplete建议、People Also Ask问题和Related Searches,配合住宅代理实现本地化关键词扩展,涵盖httpx、Playwright实战示例与去重导出方案。

Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)
本文目录

关键词研究的第一步往往不是买昂贵工具,而是直接从Google自身的建议系统中提取数据。本文将系统讲解如何抓取Google People Also Ask和Autocomplete用于关键词研究——这是SEO开发者和数据工程师构建关键词工具时最实用的技术路径之一。我们会覆盖三个免费数据源、种子词扩展策略、代理防封方案,以及完整的Python实现代码。

三大免费关键词数据源及其搜索意图映射

Google在搜索过程中会生成三种结构化建议数据,每种对应不同的搜索意图阶段:

1. Autocomplete建议(suggestqueries.google.com)

Autocomplete是用户在搜索框输入时实时弹出的建议词。它的端点格式为:

https://suggestqueries.google.com/complete/search?client=chrome&q=你的关键词

返回JSON数组,第二个元素是建议词列表。Autocomplete词反映早期探索意图——用户还在搜索框打字阶段,意图尚未完全明确。例如输入"running shoes",建议词可能包含"running shoes for flat feet"、"running shoes on sale",分别对应信息型和交易型意图。

2. People Also Ask(PAA)问题

PAA是搜索结果页面中以手风琴式折叠展示的问答模块。每个PAA问题对应信息型意图,非常适合FAQ页面和内容选题。PAA的独特之处在于它是递归的——点击展开一个问题后,会动态加载新的相关问题,形成无限扩展链。

页面底部的相关搜索词反映搜索细化意图——用户已完成一次搜索但未完全满足,准备调整查询方向。这些词适合作为内容集群的主题锚点。

数据源意图类型数据结构获取难度
Autocomplete探索/交易JSON数组低(HTTP请求)
People Also Ask信息型嵌套DOM中(需渲染)
Related Searches细化/导航DOM列表低(HTTP+解析)

种子词到长尾词的扩展策略

单个种子词通过Autocomplete只能获得约10个建议。要生成数百个长尾词,需要组合两种策略:

a-z字母前缀扩展

对种子词逐一添加a到z的前缀,每次请求Autocomplete端点。例如"running shoes a"、"running shoes b"……理论上一个种子词可产生约260个候选词(26个字母 × 约10个建议词/次)。

修饰词前缀扩展

除了字母,还可以添加常见修饰词前缀:

  • how — how to, how do, how much
  • what — what is, what are, what causes
  • best — best running shoes, best cheap running shoes
  • vs — nike vs adidas running shoes
  • near me — running shoes near me

将字母扩展与修饰词扩展结合,一个种子词可扩展出300-500个候选长尾词。

递归PAA扩展

PAA模块默认展示3-4个问题。点击展开一个问题后,Google会动态注入新的相关问题。通过递归展开,可以从单个种子词的PAA模块中提取20-50个嵌套问题。每个问题本身又可以作为新的种子词再次查询Autocomplete和PAA,形成指数级扩展。

为什么Autocomplete和PAA抓取需要住宅代理

直接用数据中心IP批量请求Autocomplete端点或PAA页面,会遇到两个核心问题:

1. 每IP速率限制

Google对suggestqueries.google.com端点施加了每IP速率限制。经验表明,单IP在短时间内发送超过约100-200次请求就可能触发临时封锁(HTTP 429或空响应)。对于需要a-z × 多种子词 × 多地区的扩展任务,单IP远远不够。

2. 地区偏见与本地化

Autocomplete建议和PAA问题具有强烈的地区依赖性。同一关键词"best running shoes"在美国、德国、日本的建议词完全不同。如果用美国数据中心IP查询德国用户的建议词,结果会被严重偏移。根据Google官方文档,搜索结果和建议受用户位置、语言和搜索历史影响(参见 Google搜索API文档)。

住宅代理通过提供真实ISP分配的IP地址,使请求看起来来自真实用户。配合国家/城市级地理定位,可以获取准确的本地化建议数据。

ProxyHat代理配置详解

ProxyHat住宅代理网关地址为 gate.proxyhat.com,HTTP端口 8080,SOCKS5端口 1080。地理定位参数通过用户名传递:

# 德国柏林住宅代理
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080

# 美国纽约住宅代理
http://user-country-US-city-newyork:pass@gate.proxyhat.com:8080

# 日本东京住宅代理(SOCKS5)
socks5://user-country-JP-city-tokyo:pass@gate.proxyhat.com:1080

使用-session-xxx参数可保持会话粘性,确保同一IP用于同一搜索会话:

http://user-country-DE-city-berlin-session-key1:pass@gate.proxyhat.com:8080

更多配置细节可参考 ProxyHat官方文档。定价信息见 ProxyHat定价页

实战代码:用httpx抓取Autocomplete JSON

以下示例使用httpx通过ProxyHat住宅代理抓取Autocomplete建议词,包含错误处理和重试逻辑:

import httpx
import time
import logging
import json
from typing import Optional

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# ProxyHat 住宅代理配置
PROXY_URL = "http://user-country-DE-city-berlin:YOUR_PASSWORD@gate.proxyhat.com:8080"
AUTOCOMPLETE_URL = "https://suggestqueries.google.com/complete/search"

# Chrome client 参数返回 JSON 而非 XML
DEFAULT_PARAMS = {"client": "chrome", "hl": "de", "gl": "de"}

MAX_RETRIES = 3
RETRY_DELAY = 2.0  # 秒

def fetch_autocomplete(
    keyword: str,
    client: httpx.Client,
    retries: int = MAX_RETRIES
) -> Optional[list[str]]:
    """抓取单个关键词的Autocomplete建议词列表"""
    params = {**DEFAULT_PARAMS, "q": keyword}

    for attempt in range(1, retries + 1):
        try:
            resp = client.get(
                AUTOCOMPLETE_URL,
                params=params,
                timeout=10.0,
                headers={
                    "User-Agent": (
                        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                        "AppleWebKit/537.36 (KHTML, like Gecko) "
                        "Chrome/120.0.0.0 Safari/537.36"
                    ),
                    "Accept-Language": "de-DE,de;q=0.9,en;q=0.8",
                },
            )
            resp.raise_for_status()

            data = resp.json()
            # Google返回格式: [原始查询, [建议词列表], ...]
            suggestions = data[1] if len(data) > 1 else []
            logger.info(f"'{keyword}' -> {len(suggestions)} suggestions")
            return suggestions

        except httpx.HTTPStatusError as e:
            if e.response.status_code == 429:
                logger.warning(f"Rate limited on '{keyword}', attempt {attempt}/{retries}")
                time.sleep(RETRY_DELAY * attempt)
            else:
                logger.error(f"HTTP {e.response.status_code} for '{keyword}'")
                return None
        except (httpx.RequestError, json.JSONDecodeError) as e:
            logger.error(f"Request failed for '{keyword}': {e}")
            time.sleep(RETRY_DELAY)

    return None


def expand_with_alpha(seed: str, client: httpx.Client) -> list[str]:
    """a-z字母前缀扩展"""
    all_suggestions = []
    for ch in "abcdefghijklmnopqrstuvwxyz":
        query = f"{seed} {ch}"
        suggestions = fetch_autocomplete(query, client)
        if suggestions:
            all_suggestions.extend(suggestions)
        time.sleep(0.5)  # 礼貌延迟
    return all_suggestions


# 使用示例
with httpx.Client(proxy=PROXY_URL) as client:
    seed = "running shoes"
    results = expand_with_alpha(seed, client)
    print(f"总共获取 {len(results)} 个建议词")
    print(results[:10])

上述代码通过德国柏林的住宅代理发出请求,hl=degl=de参数确保返回德语建议词。每个字母查询之间有0.5秒延迟,避免触发速率限制。

用修饰词前缀进一步扩展

import httpx
import time
import logging
from itertools import chain

logger = logging.getLogger(__name__)

MODIFIER_PREFIXES = [
    "how", "what", "why", "when", "where", "which",
    "best", "top", "cheap", "buy", "review",
    "vs", "alternative", "near me", "for",
]

SECOND_MODIFIERS = ["to", "is", "are", "does", "much", "many", "long"]

def expand_with_modifiers(
    seed: str,
    client: httpx.Client,
    fetch_fn
) -> list[str]:
    """使用修饰词前缀扩展种子词"""
    all_suggestions = []

    # 单修饰词: "best running shoes"
    for mod in MODIFIER_PREFIXES:
        query = f"{mod} {seed}"
        suggestions = fetch_fn(query, client)
        if suggestions:
            all_suggestions.extend(suggestions)
        time.sleep(0.4)

    # 双修饰词: "how to running shoes", "what is running shoes"
    for mod1 in ["how", "what", "why", "when"]:
        for mod2 in SECOND_MODIFIERS:
            query = f"{mod1} {mod2} {seed}"
            suggestions = fetch_fn(query, client)
            if suggestions:
                all_suggestions.extend(suggestions)
            time.sleep(0.4)

    return all_suggestions

# 组合字母扩展和修饰词扩展
# total = expand_with_alpha(seed, client) + expand_with_modifiers(seed, client, fetch_autocomplete)

用Playwright递归展开PAA问题

PAA问题嵌在动态DOM中,需要浏览器渲染才能提取。以下代码使用Playwright通过ProxyHat代理加载Google搜索页,递归点击PAA手风琴并提取问题及引用来源:

import asyncio
import logging
from playwright.async_api import async_playwright
from dataclasses import dataclass, field

logger = logging.getLogger(__name__)

@dataclass
class PAAQuestion:
    question: str
    answer_snippet: str = ""
    source_url: str = ""
    source_name: str = ""

PROXY_SERVER = "http://gate.proxyhat.com:8080"
PROXY_USER = "user-country-DE-city-berlin"
PROXY_PASS = "YOUR_PASSWORD"

MAX_PAA_DEPTH = 8  # 递归展开层数
SCROLL_WAIT = 2.0  # 秒

def build_paa_url(keyword: str, gl: str = "de", hl: str = "de") -> str:
    return f"https://www.google.com/search?q={keyword}&gl={gl}&hl={hl}"

async def scrape_paa(keyword: str, max_depth: int = MAX_PAA_DEPTH) -> list[PAAQuestion]:
    """递归抓取PAA问题及其引用来源"""
    results: list[PAAQuestion] = []
    seen_questions: set[str] = set()

    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            proxy={
                "server": PROXY_SERVER,
                "username": PROXY_USER,
                "password": PROXY_PASS,
            },
        )
        context = await browser.new_context(
            locale="de-DE",
            user_agent=(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
        )
        page = await context.new_page()

        try:
            url = build_paa_url(keyword)
            await page.goto(url, wait_until="domcontentloaded", timeout=30000)
            await page.wait_for_timeout(SCROLL_WAIT * 1000)

            for depth in range(max_depth):
                # 查找所有PAA问题元素
                paa_elements = page.locator(
                    "div[jsname='Cpkphb'] >> div[class*='BA0z6e']"
                )
                count = await paa_elements.count()

                if count == 0:
                    logger.info(f"Depth {depth}: No PAA elements found")
                    break

                # 点击最后一个未展开的问题以触发新问题加载
                for i in range(count):
                    try:
                        el = paa_elements.nth(i)
                        text = await el.inner_text()
                        question_text = text.strip().split("\n")[0]

                        if question_text and question_text not in seen_questions:
                            seen_questions.add(question_text)

                            # 点击展开获取答案
                            await el.click()
                            await page.wait_for_timeout(1500)

                            # 提取答案摘要和引用来源
                            answer_el = page.locator(
                                "div[data-attrid='wa:/description']"
                            ).first
                            if await answer_el.count() > 0:
                                answer_text = await answer_el.inner_text()
                            else:
                                answer_text = ""

                            # 提取引用来源链接
                            source_link = page.locator(
                                "a[data-ved] >> span"
                            ).first
                            source_url = ""
                            source_name = ""
                            if await source_link.count() > 0:
                                source_name = await source_link.inner_text()
                                href = await page.locator(
                                    "a[data-ved]"
                                ).first.get_attribute("href")
                                source_url = href or ""

                            results.append(PAAQuestion(
                                question=question_text,
                                answer_snippet=answer_text[:500],
                                source_url=source_url,
                                source_name=source_name,
                            ))
                            logger.info(f"Depth {depth}: {question_text[:60]}")

                    except Exception as e:
                        logger.debug(f"Error at depth {depth}, item {i}: {e}")
                        continue

                # 滚动到底部加载更多
                await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
                await page.wait_for_timeout(2000)

        except Exception as e:
            logger.error(f"PAA scraping failed: {e}")
        finally:
            await browser.close()

    return results

# 运行
# results = asyncio.run(scrape_paa("running shoes"))
# for r in results[:5]:
#     print(f"Q: {r.question}")
#     print(f"A: {r.answer_snippet[:100]}")
#     print(f"Source: {r.source_name} - {r.source_url}")
#     print()

该脚本通过ProxyHat德国柏林住宅代理加载Google搜索页,递归展开PAA手风琴,提取每个问题的文本、答案摘要和引用来源URL。设置最大深度为8层,避免无限递归。

异步并发抓取多种子词

当需要处理多个种子词时,使用asyncio并发可以大幅提升效率。以下示例展示如何用httpx AsyncClient配合ProxyHat会话粘性代理实现并发抓取:

import asyncio
import httpx
import logging
from typing import Optional

logger = logging.getLogger(__name__)

AUTOCOMPLETE_URL = "https://suggestqueries.google.com/complete/search"

def build_proxy_url(country: str, city: str, session_id: str) -> str:
    """构建ProxyHat会话粘性代理URL"""
    return (
        f"http://user-country-{country}-city-{city}-session-{session_id}"
        f":YOUR_PASSWORD@gate.proxyhat.com:8080"
    )

async def fetch_autocomplete_async(
    keyword: str,
    country: str = "DE",
    city: str = "berlin",
    hl: str = "de",
    gl: str = "de",
) -> Optional[list[str]]:
    """异步抓取Autocomplete,每个关键词使用独立会话IP"""
    session_id = f"kw{abs(hash(keyword)) % 100000}"
    proxy_url = build_proxy_url(country, city, session_id)

    params = {"client": "chrome", "hl": hl, "gl": gl, "q": keyword}

    async with httpx.AsyncClient(
        proxy=proxy_url,
        timeout=httpx.Timeout(15.0, connect=10.0),
        limits=httpx.Limits(max_connections=5, max_keepalive_connections=2),
        headers={
            "User-Agent": (
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
            "Accept-Language": f"{hl}-{country.upper()},{hl};q=0.9",
        },
    ) as client:
        try:
            resp = await client.get(AUTOCOMPLETE_URL, params=params)
            resp.raise_for_status()
            data = resp.json()
            suggestions = data[1] if len(data) > 1 else []
            logger.info(f"[{country}/{city}] '{keyword}' -> {len(suggestions)} suggestions")
            return suggestions
        except Exception as e:
            logger.error(f"Failed for '{keyword}': {e}")
            return None


async def batch_expand(
    seeds: list[str],
    country: str = "DE",
    city: str = "berlin",
    max_concurrent: int = 5,
) -> dict[str, list[str]]:
    """批量并发扩展多种子词"""
    semaphore = asyncio.Semaphore(max_concurrent)

    async def bounded_fetch(seed: str) -> tuple[str, list[str]]:
        async with semaphore:
            # 字母扩展
            all_suggestions = []
            for ch in "abcdefghijklmnopqrstuvwxyz":
                query = f"{seed} {ch}"
                suggestions = await fetch_autocomplete_async(
                    query, country, city
                )
                if suggestions:
                    all_suggestions.extend(suggestions)
                await asyncio.sleep(0.3)  # 礼貌延迟
            return seed, list(set(all_suggestions))

    tasks = [bounded_fetch(seed) for seed in seeds]
    results = await asyncio.gather(*tasks, return_exceptions=True)

    output = {}
    for result in results:
        if isinstance(result, tuple):
            output[result[0]] = result[1]
        else:
            logger.error(f"Task failed: {result}")

    return output


# 运行示例
# seeds = ["running shoes", "trail running", "marathon training"]
# results = asyncio.run(batch_expand(seeds, country="DE", city="berlin"))
# for seed, suggestions in results.items():
#     print(f"{seed}: {len(suggestions)} suggestions")

使用信号量控制并发数为5,每个关键词分配独立的会话ID以获得不同IP。更多关于Web抓取最佳实践,可参考 ProxyHat Web抓取用例

去重、意图聚类与CSV导出

抓取完成后,需要对结果去重、按意图聚类并导出为可用的CSV格式:

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

@dataclass
class KeywordEntry:
    keyword: str
    source: str  # "autocomplete" | "paa" | "related"
    country: str
    intent: str = ""
    parent_seed: str = ""
    paa_source_url: str = ""

# 意图分类规则
INTENT_PATTERNS = {
    "informational": [
        r"^how\b", r"^what\b", r"^why\b", r"^when\b",
        r"^where\b", r"^which\b", r"\bguide\b", r"\btutorial\b",
    ],
    "transactional": [
        r"\bbuy\b", r"\bprice\b", r"\bsale\b", r"\bcheap\b",
        r"\bdeal\b", r"\bcoupon\b", r"\bdiscount\b",
    ],
    "navigational": [
        r"\blogin\b", r"\bsign\s*up\b", r"\bofficial\b",
        r"\bnear\s*me\b",
    ],
    "comparison": [
        r"\bvs\b", r"\balternative\b", r"\bcompare\b",
        r"\bor\b",
    ],
}

def classify_intent(keyword: str) -> str:
    """基于关键词模式分类搜索意图"""
    kw_lower = keyword.lower()
    for intent, patterns in INTENT_PATTERNS.items():
        for pattern in patterns:
            if re.search(pattern, kw_lower):
                return intent
    return "commercial"  # 默认归为商业型

def dedup_and_cluster(
    entries: list[KeywordEntry],
) -> dict[str, list[KeywordEntry]]:
    """去重并按意图聚类"""
    seen = set()
    clustered: dict[str, list[KeywordEntry]] = defaultdict(list)

    for entry in entries:
        normalized = entry.keyword.lower().strip()
        if normalized in seen:
            continue
        seen.add(normalized)

        entry.intent = classify_intent(entry.keyword)
        clustered[entry.intent].append(entry)

    return clustered

def export_to_csv(
    clustered: dict[str, list[KeywordEntry]],
    filepath: str = "keyword_research.csv",
) -> None:
    """导出为CSV,按意图分组"""
    with open(filepath, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([
            "keyword", "intent", "source", "country",
            "parent_seed", "paa_source_url",
        ])

        for intent, entries in sorted(clustered.items()):
            for entry in entries:
                writer.writerow([
                    entry.keyword,
                    entry.intent,
                    entry.source,
                    entry.country,
                    entry.parent_seed,
                    entry.paa_source_url,
                ])

    total = sum(len(v) for v in clustered.values())
    print(f"导出完成: {total} 个关键词 -> {filepath}")
    for intent, entries in clustered.items():
        print(f"  {intent}: {len(entries)} 个")


# 使用示例
# entries = [
#     KeywordEntry("how to choose running shoes", "autocomplete", "DE", parent_seed="running shoes"),
#     KeywordEntry("best running shoes 2024", "autocomplete", "DE", parent_seed="running shoes"),
#     KeywordEntry("running shoes vs walking shoes", "paa", "DE", parent_seed="running shoes"),
#     KeywordEntry("buy nike running shoes", "autocomplete", "DE", parent_seed="running shoes"),
# ]
# clustered = dedup_and_cluster(entries)
# export_to_csv(clustered, "running_shoes_keywords_de.csv")

导出的CSV可直接导入内容管理工具或用于FAQ页面规划。PAA来源URL字段可帮助内容团队直接引用权威来源。

使用curl快速验证Autocomplete

在编写完整脚本前,可以用curl快速验证代理和端点是否正常工作:

# 通过ProxyHat德国代理抓取Autocomplete建议
curl -x "http://user-country-DE-city-berlin:YOUR_PASSWORD@gate.proxyhat.com:8080" \
  "https://suggestqueries.google.com/complete/search?client=chrome&hl=de&gl=de&q=running+shoes" \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0" \
  -H "Accept-Language: de-DE,de;q=0.9" \
  --connect-timeout 10 \
  --max-time 15

# 使用SOCKS5代理(端口1080)
curl -x "socks5://user-country-US-city-newyork:YOUR_PASSWORD@gate.proxyhat.com:1080" \
  "https://suggestqueries.google.com/complete/search?client=chrome&hl=en&gl=us&q=best+running+shoes" \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0" \
  --connect-timeout 10

伦理与合规考量

Autocomplete建议和PAA问题是公开可见的搜索建议数据,但大规模自动化抓取仍需注意以下原则:

  • 控制请求频率:每个IP保持每秒不超过1-2次请求,避免对Google服务造成压力。
  • 优先使用官方API:如果项目规模较大(每日超过10,000次请求),应考虑使用 Google Custom Search APISerpAPI 等官方/第三方API服务。
  • 遵守robots.txt:检查 suggestqueries.google.com/robots.txt 的规则,虽然Autocomplete端点通常未被禁止,但仍应遵守。
  • GDPR合规:如果处理涉及欧盟用户的数据,确保不收集个人可识别信息。PAA问题本身是聚合搜索行为数据,不涉及个人隐私。
  • 合理使用:抓取的数据应用于关键词研究和内容规划,而非重新发布为搜索服务。

关于SERP追踪的更多技术细节,可参考 ProxyHat SERP追踪用例

关键要点总结

三大数据源各有侧重:Autocomplete适合探索型长尾词发现,PAA适合信息型FAQ内容选题,Related Searches适合内容集群规划。三者结合可覆盖完整搜索意图漏斗。

住宅代理是规模化前提:单IP在约100-200次请求后可能触发限制。使用ProxyHat住宅代理配合国家/城市地理定位,可获取准确的本地化建议数据,同时分散请求避免封锁。

a-z + 修饰词扩展是核心策略:一个种子词通过字母前缀和修饰词前缀可扩展出300-500个候选词。递归PAA展开可额外获得20-50个嵌套问题。

去重和意图聚类是关键后处理步骤:基于正则模式的意图分类可将关键词分为informational/transactional/navigational/comparison四类,直接指导内容策略。

礼貌抓取是可持续之道:控制并发、添加延迟、遵守robots.txt,在规模较大时迁移到官方API。

准备好开始构建你的关键词研究工具了吗?查看 ProxyHat支持的全球代理位置,选择你需要的国家和地区开始本地化关键词扩展。

常见问题

什么是抓取Google People Also Ask和Autocomplete用于关键词研究?

这是指通过程序化方式从Google的Autocomplete建议端点(suggestqueries.google.com)和搜索结果页的People Also Ask模块中提取关键词建议和问题数据,用于SEO关键词研究。Autocomplete返回JSON格式的建议词列表,PAA模块包含递归展开的问答对,两者结合可覆盖从探索型到信息型的完整搜索意图。配合a-z字母前缀和修饰词扩展策略,一个种子词可扩展出300-500个长尾候选词。

为什么抓取Google PAA和Autocomplete需要代理?

Google对suggestqueries.google.com端点施加了每IP速率限制,单IP在短时间内发送超过约100-200次请求就可能触发HTTP 429封锁或空响应。此外,Autocomplete建议和PAA问题具有强烈地区依赖性,同一关键词在不同国家返回的建议词完全不同。住宅代理提供真实ISP的IP地址,配合国家/城市地理定位参数,可获取准确的本地化建议数据并分散请求避免封锁。

哪种代理类型最适合抓取Google PAA和Autocomplete?

住宅代理是最佳选择,因为它们使用真实ISP分配的IP地址,被Google识别为普通用户而非数据中心爬虫。住宅代理支持国家/城市级地理定位(如country-DE-city-berlin),可获取准确的本地化建议。数据中心代理虽然速度更快、成本更低,但容易被Google识别并封锁。移动代理也可用,但成本更高,适合需要模拟移动端搜索结果的场景。ProxyHat住宅代理通过gate.proxyhat.com:8080网关提供服务,支持会话粘性和地理定位。

如何避免抓取Google Autocomplete和PAA时被封锁?

避免封锁的关键策略包括:使用住宅代理分散请求到不同IP,每个关键词使用独立会话ID获得不同IP;控制请求频率,每个IP每秒不超过1-2次请求,字母扩展之间添加0.3-0.5秒延迟;设置合理的重试机制,遇到429状态码时指数退避;使用真实的User-Agent和Accept-Language头匹配目标地区;限制并发连接数为5-10个;在规模较大时(每日超过10,000次请求)考虑迁移到Google Custom Search API等官方服务。

PAA递归展开是什么意思,如何实现?

PAA(People Also Ask)模块具有递归特性:点击展开一个问题后,Google会动态注入新的相关问题到列表底部。递归展开是指通过程序化方式不断点击新出现的问题,提取嵌套的问题文本和答案引用来源。实现上需要使用Playwright等浏览器自动化工具渲染页面并模拟点击,设置最大递归深度(通常8层)避免无限循环。每个PAA问题包含问题文本、答案摘要和引用来源URL,适合直接用于FAQ页面内容规划。

准备好开始了吗?

覆盖 148+ 国家的住宅、ISP 和移动代理。创建免费账户。

创建免费账户
← 返回博客