[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-es-scraping-serp-geo-segmentado-mejores-practicas":3},{"success":4,"payload":5,"related":59,"errors":126},true,{"id":6,"slug":7,"title":8,"excerpt":9,"body_html":10,"meta_title":11,"meta_description":12,"canonical_url":13,"canonical_override":14,"og_title":11,"og_description":12,"og_image_url":15,"faq_json":16,"key_takeaways":14,"allow_index":26,"noindex_google_only":26,"allow_follow":4,"published_at":27,"updated_at":27,"content_updated_at":28,"featured_image_url":29,"featured_image_alt":30,"card_image_url":31,"reading_time_minutes":32,"author":33,"categories":37,"tags":44,"alternates":45,"locale_paths":47,"views":58},198,"scraping-serp-geo-segmentado-mejores-practicas","Mejores prácticas para scraping SERP geo-segmentado: guía developer-first","Guía developer-first sobre scraping SERP geo-segmentado: construcción del parámetro uule, gl\u002Fhl\u002Fgoogle_domain, proxies residenciales por ciudad y código Python listo para producción.","\u003Cp>Los ingenieros SEO saben que \"pizza near me\" devuelve resultados distintos en Manhattan que en Brooklyn. Sin embargo, muchos pipelines de rank tracking siguen scrapeando desde una única ubicación IP y asumen que el targeting a nivel de país es suficiente. No lo es. Para construir datasets SERP localizados precisos necesitas aplicar mejores prácticas para scraping SERP geo-segmentado: combinar parámetros URL precisos (uule, gl, hl) con proxies residenciales que coincidan con la geografía objetivo a nivel de ciudad. Esta guía recorre el stack completo, desde la construcción del parámetro uule hasta la rotación de IPs residenciales por locale, con ejemplos ejecutables en Python y curl.\u003C\u002Fp>\n\n\u003Ch2>Mejores prácticas para scraping SERP geo-segmentado: por qué la ubicación importa\u003C\u002Fh2>\n\u003Cp>Google personaliza los resultados de búsqueda según múltiples señales: la ubicación física del usuario (derivada de su IP), la configuración de búsqueda (gl, hl, google_domain), el historial de búsquedas y el tipo de dispositivo. Para SEO local, el targeting a nivel de país es insuficiente porque el \u003Cem>local pack\u003C\u002Fem> (el bloque de Google Maps con 3 negocios) se basa en un radio de aproximadamente \u003Cstrong>20 km\u003C\u002Fstrong> alrededor del buscador. \"Plumber\" en Miami y \"plumber\" en Seattle devuelven conjuntos de resultados completamente distintos.\u003C\u002Fp>\n\u003Cp>Además, Google verifica la coherencia entre la geografía de la IP y los parámetros de localización. Si envías \u003Ccode>gl=us\u003C\u002Fcode> con una IP alemana, Google puede degradar los resultados o mostrar un CAPTCHA. Por eso, el scraping SERP geo-segmentado requiere que cada parámetro de URL coincida con la geografía del proxy. Consulta nuestra guía de \u003Ca href=\"\u002Fes\u002Fuse-cases\u002Fserp-tracking\">SERP tracking\u003C\u002Fa> para más contexto sobre rank tracking localizado.\u003C\u002Fp>\n\n\u003Ch2>Parámetros core de localización: gl, hl, google_domain, lr y uule\u003C\u002Fh2>\n\u003Cp>Google acepta varios parámetros de URL para controlar la localización de los resultados:\u003C\u002Fp>\n\u003Cul>\n  \u003Cli>\u003Cstrong>gl\u003C\u002Fstrong>: país del buscador (ej: \u003Ccode>us\u003C\u002Fcode>, \u003Ccode>de\u003C\u002Fcode>, \u003Ccode>es\u003C\u002Fcode>). Equivale al parámetro documentado en la \u003Ca href=\"https:\u002F\u002Fdevelopers.google.com\u002Fcustom-search\u002Fv1\u002Freference\u002Frest\u002Fv1\u002Fcse\u002Flist\" rel=\"noopener noreferrer\">API de Google Custom Search\u003C\u002Fa>.\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>hl\u003C\u002Fstrong>: idioma de la interfaz (ej: \u003Ccode>en\u003C\u002Fcode>, \u003Ccode>es\u003C\u002Fcode>, \u003Ccode>de\u003C\u002Fcode>).\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>google_domain\u003C\u002Fstrong>: dominio de Google (ej: \u003Ccode>google.com\u003C\u002Fcode>, \u003Ccode>google.de\u003C\u002Fcode>, \u003Ccode>google.es\u003C\u002Fcode>). Debe ser coherente con \u003Ccode>gl\u003C\u002Fcode>.\u003C\u002Fli>\n  \u003Cli>\u003Cstrong>lr\u003C\u002Fstrong>: restringe el idioma de los resultados (ej: \u003Ccode>lang_en\u003C\u002Fcode>, \u003Ccode>lang_es\u003C\u002Fcode>). Diferente de \u003Ccode>hl\u003C\u002Fcode>: \u003Ccode>hl\u003C\u002Fcode> controla la interfaz; \u003Ccode>lr\u003C\u002Fcode> filtra los resultados por idioma.\u003C\u002Fli>\n  \u003Cli>uule: codifica una ubicación precisa (ciudad o distrito). Es un parámetro interno no documentado oficialmente, pero ampliamente usado por herramientas SEO.\u003C\u002Fli>\n  \u003Cli>pws=0: desactiva la personalización, devolviendo un baseline no personalizado. Imprescindible para datos reproducibles.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Para scraping SERP local por ciudad, \u003Ccode>uule\u003C\u002Fcode> es el parámetro más potente: permite fijar una ciudad exacta independientemente del país. Combinado con \u003Ccode>gl\u003C\u002Fcode> y \u003Ccode>hl\u003C\u002Fcode> coherentes, obtienes resultados que replican lo que vería un usuario real en esa ciudad.\u003C\u002Fp>\n\n\u003Ch3>Construcción del valor uule\u003C\u002Fh3>\n\u003Cp>El formato del parámetro uule es:\u003C\u002Fp>\n\u003Cp>\u003Ccode>w+CAIQ\u003C\u002Fcode> + \u003Cem>carácter de longitud\u003C\u002Fem> + \u003Cem>base64 del nombre canónico del lugar\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>El carácter de longitud se calcula como \u003Ccode>chr(64 + len(base64_string))\u003C\u002Fcode>. Por ejemplo, para \"New York,New York,United States\":\u003C\u002Fp>\n\u003Col>\n  \u003Cli>Base64: \u003Ccode>TmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw==\u003C\u002Fcode> (44 caracteres)\u003C\u002Fli>\n  \u003Cli>Carácter de longitud: \u003Ccode>chr(64 + 44) = 'l'\u003C\u002Fcode>\u003C\u002Fli>\n  \u003Cli>uule: \u003Ccode>w+CAIQlTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw==\u003C\u002Fcode>\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>El primer ejemplo muestra una llamada básica con curl:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>curl -s &quot;https:\u002F\u002Fwww.google.com\u002Fsearch?q=pizza&amp;gl=us&amp;hl=en&amp;pws=0&amp;uule=w+CAIQlTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw==&quot; \\\n  --proxy &quot;http:\u002F\u002Fuser-country-US-region-new_york-city-new_york_city:pass@gate.proxyhat.com:8080&quot;\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>La geografía de la IP debe coincidir con tus parámetros\u003C\u002Fh2>\n\u003Cp>Google cruzaliza la geografía derivada de la IP con los parámetros gl\u002Fuule. Si hay una discrepancia significativa —por ejemplo, una IP de datacenter en Frankfurt con \u003Ccode>gl=us\u003C\u002Fcode> y \u003Ccode>uule\u003C\u002Fcode> apuntando a Nueva York— Google puede devolver resultados menos precisos, mostrar un intersticial de CAPTCHA o bloquear la solicitud con un error 429. La solución es enrutar cada solicitud a través de un proxy residencial cuya ubicación coincida con el mercado objetivo. ProxyHat permite especificar país y ciudad directamente en el nombre de usuario, garantizando que la IP de salida esté en la geografía correcta. Consulta las \u003Ca href=\"\u002Fes\u002Flocations\">ubicaciones disponibles\u003C\u002Fa> para verificar cobertura.\u003C\u002Fp>\n\n\u003Ctable>\n  \u003Cthead>\n    \u003Ctr>\n      \u003Cth>Tipo de proxy\u003C\u002Fth>\n      \u003Cth>Precisión geográfica\u003C\u002Fth>\n      \u003Cth>Riesgo de detección\u003C\u002Fth>\n      \u003Cth>Coste aprox.\u003C\u002Fth>\n      \u003Cth>Ideal para\u003C\u002Fth>\n    \u003C\u002Ftr>\n  \u003C\u002Fthead>\n  \u003Ctbody>\n    \u003Ctr>\n      \u003Ctd>Datacenter\u003C\u002Ftd>\n      \u003Ctd>País (por IP)\u003C\u002Ftd>\n      \u003Ctd>Alto\u003C\u002Ftd>\n      \u003Ctd>$0.5–2\u002FGB\u003C\u002Ftd>\n      \u003Ctd>Consultas masivas sin geo\u003C\u002Ftd>\n    \u003C\u002Ftr>\n    \u003Ctr>\n      \u003Ctd>Residencial\u003C\u002Ftd>\n      \u003Ctd>Ciudad\u002FDistrito\u003C\u002Ftd>\n      \u003Ctd>Bajo\u003C\u002Ftd>\n      \u003Ctd>$3–15\u002FGB\u003C\u002Ftd>\n      \u003Ctd>Scraping SERP local por ciudad\u003C\u002Ftd>\n    \u003C\u002Ftr>\n    \u003Ctr>\n      \u003Ctd>Móvil\u003C\u002Ftd>\n      \u003Ctd>Ciudad\u002FDistrito\u003C\u002Ftd>\n      \u003Ctd>Muy bajo\u003C\u002Ftd>\n      \u003Ctd>$10–30\u002FGB\u003C\u002Ftd>\n      \u003Ctd>Verificación de anuncios, SERP móvil\u003C\u002Ftd>\n    \u003C\u002Ftr>\n  \u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Ch2>Implementación en Python: uule + gl\u002Fhl con rotación de IPs residenciales\u003C\u002Fh2>\n\u003Cp>El siguiente ejemplo construye el parámetro uule, configura gl\u002Fhl coherentes y enruta la solicitud a través de un proxy residencial de ProxyHat con targeting de ciudad. Primero, la versión con proxy crudo (sin flags de geo), y luego la versión con targeting geo en el nombre de usuario —el equivalente al SDK de ProxyHat.\u003C\u002Fp>\n\n\u003Ch3>Versión con proxy crudo (sin geo-targeting)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>import requests\nimport base64\n\ndef build_uule(canonical_name: str) -&gt; str:\n    &quot;&quot;&quot;Construye el parámetro uule de Google desde un nombre canónico de lugar.&quot;&quot;&quot;\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;ascii&quot;)\n    length_key = chr(64 + len(b64))\n    return f&quot;w+CAIQ{length_key}{b64}&quot;\n\n# Proxy crudo: sin flags de país\u002Fciudad en el nombre de usuario\nraw_proxy = &quot;http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080&quot;\n\nparams = {\n    &quot;q&quot;: &quot;best pizza&quot;,\n    &quot;gl&quot;: &quot;us&quot;,\n    &quot;hl&quot;: &quot;en&quot;,\n    &quot;pws&quot;: &quot;0&quot;,\n    &quot;uule&quot;: build_uule(&quot;New York,New York,United States&quot;),\n}\n\nheaders = {\n    &quot;User-Agent&quot;: &quot;Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) &quot;\n                  &quot;AppleWebKit\u002F537.36 (KHTML, like Gecko) &quot;\n                  &quot;Chrome\u002F124.0.0.0 Safari\u002F537.36&quot;,\n    &quot;Accept-Language&quot;: &quot;en-US,en;q=0.9&quot;,\n}\n\nresp = requests.get(\n    &quot;https:\u002F\u002Fwww.google.com\u002Fsearch&quot;,\n    params=params,\n    headers=headers,\n    proxies={&quot;http&quot;: raw_proxy, &quot;https&quot;: raw_proxy},\n    timeout=15,\n)\nprint(f&quot;Status: {resp.status_code}, Length: {len(resp.text)}&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>Versión con ProxyHat geo-targeting (flags en el username)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>import requests\nimport base64\n\ndef build_uule(canonical_name: str) -&gt; str:\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;ascii&quot;)\n    length_key = chr(64 + len(b64))\n    return f&quot;w+CAIQ{length_key}{b64}&quot;\n\n# ProxyHat con geo-targeting: país + ciudad en el nombre de usuario\nproxy = &quot;http:\u002F\u002Fuser-country-US-region-new_york-city-new_york_city:pass@gate.proxyhat.com:8080&quot;\n\nparams = {\n    &quot;q&quot;: &quot;best pizza&quot;,\n    &quot;gl&quot;: &quot;us&quot;,\n    &quot;hl&quot;: &quot;en&quot;,\n    &quot;pws&quot;: &quot;0&quot;,\n    &quot;uule&quot;: build_uule(&quot;New York,New York,United States&quot;),\n}\n\nheaders = {\n    &quot;User-Agent&quot;: &quot;Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) &quot;\n                  &quot;AppleWebKit\u002F537.36 (KHTML, like Gecko) &quot;\n                  &quot;Chrome\u002F124.0.0.0 Safari\u002F537.36&quot;,\n    &quot;Accept-Language&quot;: &quot;en-US,en;q=0.9&quot;,\n}\n\nresp = requests.get(\n    &quot;https:\u002F\u002Fwww.google.com\u002Fsearch&quot;,\n    params=params,\n    headers=headers,\n    proxies={&quot;http&quot;: proxy, &quot;https&quot;: proxy},\n    timeout=15,\n)\nprint(f&quot;Status: {resp.status_code}, Length: {len(resp.text)}&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>La diferencia clave: en la segunda versión, ProxyHat asigna una IP residencial ubicada en Nueva York, alineada con \u003Ccode>gl=us\u003C\u002Fcode> y el \u003Ccode>uule\u003C\u002Fcode> de Nueva York. Esto reduce drásticamente el riesgo de CAPTCHAs y resultados desviados. Consulta la \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">documentación de ProxyHat\u003C\u002Fa> para más detalles sobre flags de geo-targeting.\u003C\u002Fp>\n\n\u003Ch3>Con curl_cffi e impersonación de Chrome\u003C\u002Fh3>\n\u003Cp>Para mayor realismo, usa \u003Ccode>curl_cffi\u003C\u002Fcode> con \u003Ccode>impersonate=\"chrome\"\u003C\u002Fcode>, que replica la firma TLS de Chrome —incluyendo el orden de cipher suites y extensiones—:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>from curl_cffi import requests as cffi_requests\nimport base64\n\ndef build_uule(canonical_name: str) -&gt; str:\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;ascii&quot;)\n    length_key = chr(64 + len(b64))\n    return f&quot;w+CAIQ{length_key}{b64}&quot;\n\nproxy = &quot;http:\u002F\u002Fuser-country-US-region-new_york-city-new_york_city:pass@gate.proxyhat.com:8080&quot;\n\nparams = {\n    &quot;q&quot;: &quot;best pizza&quot;,\n    &quot;gl&quot;: &quot;us&quot;,\n    &quot;hl&quot;: &quot;en&quot;,\n    &quot;pws&quot;: &quot;0&quot;,\n    &quot;uule&quot;: build_uule(&quot;New York,New York,United States&quot;),\n}\n\nresp = cffi_requests.get(\n    &quot;https:\u002F\u002Fwww.google.com\u002Fsearch&quot;,\n    params=params,\n    impersonate=&quot;chrome&quot;,\n    proxies={&quot;http&quot;: proxy, &quot;https&quot;: proxy},\n    timeout=15,\n)\nprint(f&quot;Status: {resp.status_code}&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Parsing de resultados orgánicos y local pack con selectolax\u003C\u002Fh2>\n\u003Cp>Una vez que tienes el HTML, necesitas extraer los resultados orgánicos y el local pack. \u003Ccode>selectolax\u003C\u002Fcode> es un parser rápido basado en C, ideal para procesar grandes volúmenes de SERPs. Más información sobre pipelines de scraping en nuestro \u003Ca href=\"\u002Fes\u002Fuse-cases\u002Fweb-scraping\">caso de uso de web scraping\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>from selectolax.parser import HTMLParser\n\ndef parse_serp(html: str) -&gt; dict:\n    &quot;&quot;&quot;Extrae resultados orgánicos y local pack del HTML de Google.&quot;&quot;&quot;\n    tree = HTMLParser(html)\n    results = []\n\n    # Resultados orgánicos\n    for node in tree.css(&quot;div.g&quot;):\n        title_node = node.css_first(&quot;h3&quot;)\n        link_node = node.css_first(&quot;a&quot;)\n        if title_node and link_node:\n            results.append({\n                &quot;type&quot;: &quot;organic&quot;,\n                &quot;title&quot;: title_node.text(strip=True),\n                &quot;url&quot;: link_node.attributes.get(&quot;href&quot;, &quot;&quot;),\n            })\n\n    # Local pack (Google Maps)\n    for node in tree.css(&quot;div[data-cid]&quot;):\n        name_node = node.css_first(&quot;div.dbg0p&quot;)\n        if name_node:\n            results.append({\n                &quot;type&quot;: &quot;local_pack&quot;,\n                &quot;name&quot;: name_node.text(strip=True),\n            })\n\n    return {&quot;results&quot;: results, &quot;count&quot;: len(results)}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Nota: los selectores CSS de Google cambian con frecuencia. Debes monitorizar y actualizar los selectores cuando Google modifique su HTML. Una práctica recomendada es guardar el HTML crudo junto con los datos parseados para debugging.\u003C\u002Fp>\n\n\u003Ch2>Sesiones sticky para SERPs multipágina\u003C\u002Fh2>\n\u003Cp>Cuando necesitas recoger múltiples páginas de resultados (page 1, 2, 3...), es crucial mantener la misma IP durante toda la sesión. Si la IP cambia entre páginas, Google puede devolver resultados inconsistentes o mostrar un CAPTCHA. ProxyHat soporta sesiones sticky mediante el flag \u003Ccode>sid-\u003C\u002Fcode> en el nombre de usuario:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>from curl_cffi import requests as cffi_requests\nimport base64\nimport time\n\ndef build_uule(canonical_name: str) -&gt; str:\n    b64 = base64.b64encode(canonical_name.encode(&quot;utf-8&quot;)).decode(&quot;ascii&quot;)\n    length_key = chr(64 + len(b64))\n    return f&quot;w+CAIQ{length_key}{b64}&quot;\n\nsession_id = &quot;nyc-pizza-001&quot;\n# Sesión sticky: la misma IP se mantiene durante toda la sesión\nproxy = f&quot;http:\u002F\u002Fuser-country-US-region-new_york-city-new_york_city-sid-{session_id}:pass@gate.proxyhat.com:8080&quot;\n\nuule = build_uule(&quot;New York,New York,United States&quot;)\nall_pages = []\n\nfor page in range(3):\n    start = page * 10\n    params = {\n        &quot;q&quot;: &quot;best pizza&quot;,\n        &quot;gl&quot;: &quot;us&quot;,\n        &quot;hl&quot;: &quot;en&quot;,\n        &quot;pws&quot;: &quot;0&quot;,\n        &quot;uule&quot;: uule,\n        &quot;start&quot;: str(start),\n    }\n    resp = cffi_requests.get(\n        &quot;https:\u002F\u002Fwww.google.com\u002Fsearch&quot;,\n        params=params,\n        impersonate=&quot;chrome&quot;,\n        proxies={&quot;http&quot;: proxy, &quot;https&quot;: proxy},\n        timeout=15,\n    )\n    if resp.status_code == 429:\n        print(f&quot;429 en página {page + 1}, esperando 30s&quot;)\n        time.sleep(30)\n        continue\n    all_pages.append(resp.text)\n    print(f&quot;Página {page + 1}: {resp.status_code}, {len(resp.text)} bytes&quot;)\n    time.sleep(3)  # Rate limiting respetuoso\n\nprint(f&quot;Total páginas recogidas: {len(all_pages)}&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Estrategias de backoff para CAPTCHA y errores 429\u003C\u002Fh2>\n\u003Cp>Incluso con proxies residenciales y TLS fingerprinting, Google puede devolver 429 o CAPTCHAs. Necesitas un sistema de reintentos con backoff exponencial. El \u003Ca href=\"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc7231#section-6.5.13\" rel=\"noopener noreferrer\">RFC 7231\u003C\u002Fa> define el código 429 como \"Too Many Requests\" y recomienda respetar la cabecera \u003Ccode>Retry-After\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>import time\nimport logging\nfrom curl_cffi import requests as cffi_requests\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(&quot;serp-scraper&quot;)\n\nMAX_RETRIES = 5\nINITIAL_BACKOFF = 2  # segundos\n\ndef fetch_with_retry(url, params, proxy, impersonate=&quot;chrome&quot;):\n    &quot;&quot;&quot;Fetch con backoff exponencial y manejo de 429.&quot;&quot;&quot;\n    backoff = INITIAL_BACKOFF\n    for attempt in range(MAX_RETRIES):\n        try:\n            resp = cffi_requests.get(\n                url,\n                params=params,\n                impersonate=impersonate,\n                proxies={&quot;http&quot;: proxy, &quot;https&quot;: proxy},\n                timeout=15,\n            )\n            if resp.status_code == 200:\n                return resp\n            elif resp.status_code == 429:\n                retry_after = int(resp.headers.get(&quot;Retry-After&quot;, backoff))\n                logger.warning(f&quot;429 en intento {attempt + 1}, esperando {retry_after}s&quot;)\n                time.sleep(retry_after)\n            elif resp.status_code &gt;= 500:\n                logger.warning(f&quot;{resp.status_code} en intento {attempt + 1}&quot;)\n                time.sleep(backoff)\n                backoff *= 2\n            else:\n                logger.error(f&quot;Status inesperado: {resp.status_code}&quot;)\n                return resp\n        except Exception as e:\n            logger.error(f&quot;Error de red: {e}&quot;)\n            time.sleep(backoff)\n            backoff *= 2\n    raise RuntimeError(f&quot;Falló tras {MAX_RETRIES} intentos&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Pools de proxy por país\u003C\u002Fh2>\n\u003Cp>Para datasets SERP multi-país, mantén pools de proxy separados por mercado. Cada pool debe usar el flag de país correspondiente en ProxyHat, y los parámetros gl\u002Fhl\u002Fgoogle_domain deben ser coherentes:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>PROXY_POOLS = {\n    &quot;US&quot;: {\n        &quot;proxy&quot;: &quot;http:\u002F\u002Fuser-country-US-region-new_york-city-new_york_city:pass@gate.proxyhat.com:8080&quot;,\n        &quot;gl&quot;: &quot;us&quot;, &quot;hl&quot;: &quot;en&quot;, &quot;domain&quot;: &quot;google.com&quot;,\n        &quot;uule&quot;: build_uule(&quot;New York,New York,United States&quot;),\n    },\n    &quot;DE&quot;: {\n        &quot;proxy&quot;: &quot;http:\u002F\u002Fuser-country-DE-region-state_of_berlin-city-berlin:pass@gate.proxyhat.com:8080&quot;,\n        &quot;gl&quot;: &quot;de&quot;, &quot;hl&quot;: &quot;de&quot;, &quot;domain&quot;: &quot;google.de&quot;,\n        &quot;uule&quot;: build_uule(&quot;Berlin,Berlin,Germany&quot;),\n    },\n    &quot;ES&quot;: {\n        &quot;proxy&quot;: &quot;http:\u002F\u002Fuser-country-ES-region-madrid-city-madrid:pass@gate.proxyhat.com:8080&quot;,\n        &quot;gl&quot;: &quot;es&quot;, &quot;hl&quot;: &quot;es&quot;, &quot;domain&quot;: &quot;google.es&quot;,\n        &quot;uule&quot;: build_uule(&quot;Madrid,Madrid,Spain&quot;),\n    },\n}\n\ndef scrape_by_country(query: str, country: str):\n    cfg = PROXY_POOLS[country]\n    params = {\n        &quot;q&quot;: query,\n        &quot;gl&quot;: cfg[&quot;gl&quot;],\n        &quot;hl&quot;: cfg[&quot;hl&quot;],\n        &quot;pws&quot;: &quot;0&quot;,\n        &quot;uule&quot;: cfg[&quot;uule&quot;],\n    }\n    resp = fetch_with_retry(\n        f&quot;https:\u002F\u002Fwww.{cfg[&apos;domain&apos;]}\u002Fsearch&quot;,\n        params,\n        cfg[&quot;proxy&quot;],\n    )\n    return parse_serp(resp.text)\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Consideraciones legales y éticas\u003C\u002Fh2>\n\u003Cp>El scraping de resultados de Google plantea cuestiones legales. Debes revisar los términos del servicio de Google y cumplir con normativas aplicables como el GDPR y la CCPA. Más contexto en \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSearch_engine_results_page\" rel=\"noopener noreferrer\">Wikipedia: Search engine results page\u003C\u002Fa>. Recomendaciones:\u003C\u002Fp>\n\u003Cul>\n  \u003Cli>Respeta \u003Ccode>robots.txt\u003C\u002Fcode> y los límites de tasa razonables (3–5 segundos entre solicitudes).\u003C\u002Fli>\n  \u003Cli>No almacenes datos personales innecesarios.\u003C\u002Fli>\n  \u003Cli>Considera usar la \u003Ca href=\"https:\u002F\u002Fdevelopers.google.com\u002Fcustom-search\u002Fv1\u002Freference\u002Frest\u002Fv1\u002Fcse\u002Flist\" rel=\"noopener noreferrer\">Google Custom Search API\u003C\u002Fa> para volúmenes moderados (100 consultas\u002Fdía gratis).\u003C\u002Fli>\n  \u003Cli>Para datasets a gran escala, consulta con asesoría legal sobre el uso de datos públicos.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Conclusiones clave\u003C\u002Fh2>\n\u003Cblockquote>\n  \u003Cp>El scraping SERP geo-segmentado efectivo requiere tres capas alineadas: parámetros URL (uule + gl + hl), geografía de IP coincidente (proxy residencial por ciudad), y fingerprinting TLS realista (curl_cffi impersonate). Si cualquiera de las tres falla, Google puede degradar o bloquear tus solicitudes.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cul>\n  \u003Cli>uule es el parámetro más potente para fijar una ciudad exacta; combínalo siempre con gl y hl coherentes.\u003C\u002Fli>\n  \u003Cli>pws=0 elimina la personalización y da un baseline reproducible.\u003C\u002Fli>\n  \u003Cli>La IP debe coincidir con el uule: usa proxies residenciales con targeting de ciudad en ProxyHat (\u003Ccode>-country-US-region-new_york-city-new_york_city\u003C\u002Fcode>).\u003C\u002Fli>\n  \u003Cli>Sesiones sticky (\u003Ccode>-sid-abc123\u003C\u002Fcode>) mantienen la misma IP para SERPs multipágina.\u003C\u002Fli>\n  \u003Cli>Backoff exponencial con Retry-After para 429; máximo 5 reintentos.\u003C\u002Fli>\n  \u003Cli>Selectores CSS cambian: guarda HTML crudo para debugging y actualiza parsers con frecuencia.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>¿Listo para construir tu pipeline de scraping SERP geo-segmentado? Explora las \u003Ca href=\"\u002Fes\u002Flocations\">ubicaciones de proxy disponibles\u003C\u002Fa>, revisa nuestro \u003Ca href=\"\u002Fes\u002Fuse-cases\u002Fserp-tracking\">caso de uso de SERP tracking\u003C\u002Fa>, o consulta la \u003Ca href=\"\u002Fes\u002Fpricing\">documentación de precios\u003C\u002Fa> de ProxyHat.\u003C\u002Fp>","Mejores prácticas scraping SERP geo-segmentado | ProxyHat","Guía developer-first sobre scraping SERP geo-segmentado: parámetros uule, gl, hl, proxies residenciales por ciudad y código Python listo para producción.","\u002Fes\u002Fblog\u002Fscraping-serp-geo-segmentado-mejores-practicas",null,"https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscraping-serp-geo-segmentado-mejores-practicas-og.webp",[17,20,23],{"question":18,"answer":19},"¿Por qué el scraping SERP geo-segmentado importa para usuarios de proxies?","Porque Google cruzaliza la geografía de la IP con los parámetros de URL. Si tu proxy está en Frankfurt pero envías gl=us y uule=New York, Google puede devolver resultados desviados o mostrar un CAPTCHA. Los proxies residenciales con targeting de ciudad garantizan coherencia entre IP y parámetros, reduciendo bloqueos y mejorando la precisión de los datos recogidos.",{"question":21,"answer":22},"¿Qué tipo de proxy funciona mejor para scraping SERP geo-segmentado?","Los proxies residenciales son la mejor opción porque ofrecen IPs de ISP reales con precisión a nivel de ciudad o distrito, y un riesgo de detección bajo. Los proxies datacenter son más baratos ($0.5-2\u002FGB) pero Google los detecta fácilmente. Los proxies móviles ($10-30\u002FGB) ofrecen el riesgo más bajo, ideales para verificación de anuncios y SERP móvil.",{"question":24,"answer":25},"¿Cómo evitar bloqueos al implementar scraping SERP geo-segmentado?","Usa proxies residenciales con targeting de ciudad coincidente, impersonación TLS con curl_cffi (impersonate='chrome'), rate limiting de 3-5 segundos entre solicitudes, backoff exponencial con Retry-After para errores 429, sesiones sticky para SERPs multipágina, y rotación de IPs entre consultas distintas. Guarda HTML crudo para detectar cambios en selectores y CAPTCHAs.",false,"2026-07-31T16:11:16+00:00","2026-10-03T08:57:46+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscraping-serp-geo-segmentado-mejores-practicas-master.webp","Geo-Targeted SERP Scraping Best Practices for Local SEO Data","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscraping-serp-geo-segmentado-mejores-practicas-card.webp",12,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[38],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},3,"serp-y-seo","SERP y SEO","Guías de SERP y SEO | Blog ProxyHat","Cómo rastrear posiciones en buscadores y extraer datos SERP con proxies.",[],{"en":46,"x-default":46},"\u002Fblog\u002Fgeo-targeted-serp-scraping-best-practices",{"zh":48,"ja":49,"pl":50,"es":13,"it":51,"tr":52,"ko":53,"en":46,"ru":54,"de":55,"fr":56,"pt":57},"\u002Fcn\u002Fblog\u002Fserp-dili-dingwei-zhuaqu-zhinan","\u002Fja\u002Fblog\u002Fgeo-targeted-serp-scraping-guide","\u002Fpl\u002Fblog\u002Fgeotargetowane-scrapowanie-serp-najlepsze-praktyki","\u002Fit\u002Fblog\u002Fscraping-serp-geo-targetato-best-practices","\u002Ftr\u002Fblog\u002Fcografi-hedefli-serp-kazima-rehberi","\u002Fko\u002Fblog\u002Fgeo-targeted-serp-scraping-guide","\u002Fru\u002Fblog\u002Fgeo-targeted-serp-scraping-best-practices","\u002Fde\u002Fblog\u002Fgeo-targeted-serp-scraping-leitfaden","\u002Ffr\u002Fblog\u002Fscraping-serp-geocible-meilleures-pratiques","\u002Fpt\u002Fblog\u002Fpraticas-serp-scraping-geo-targeted",59,[60,77,93,110],{"id":61,"slug":62,"title":63,"excerpt":64,"featured_image_url":65,"featured_image_alt":66,"card_image_url":67,"og_image_url":68,"published_at":69,"updated_at":69,"content_updated_at":70,"reading_time_minutes":71,"is_featured":26,"indexable":26,"views":72,"author":73,"categories":74,"tags":76},155,"seguimiento-ranking-palabras-clave-amazon-proxies","Seguimiento de Ranking de Palabras Clave en Amazon con Proxies: Guía para Desarrolladores","Guía práctica para implementar seguimiento de ranking de palabras clave en Amazon con proxies residenciales. Incluye ejemplos en Python, curl_cffi y Playwright.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fseguimiento-ranking-palabras-clave-amazon-proxies-master.webp","Amazon Keyword Rank Tracking with Proxies: A Developer's Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fseguimiento-ranking-palabras-clave-amazon-proxies-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fseguimiento-ranking-palabras-clave-amazon-proxies-og.webp","2026-07-16T16:05:31+00:00","2026-10-03T08:21:21+00:00",13,98,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[75],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":78,"slug":79,"title":80,"excerpt":81,"featured_image_url":82,"featured_image_alt":83,"card_image_url":84,"og_image_url":85,"published_at":86,"updated_at":86,"content_updated_at":87,"reading_time_minutes":32,"is_featured":26,"indexable":26,"views":88,"author":89,"categories":90,"tags":92},153,"scrapear-people-also-autocomplete-keyword-research","Scrapear People Also Ask y Autocomplete de Google para Keyword Research (Guía Python)","Guía práctica para desarrolladores y SEOs: extrae sugerencias de Autocomplete, preguntas People Also Ask y Related Searches con Python, proxies residenciales y Playwright.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscrapear-people-also-autocomplete-keyword-research-master.webp","Scrape Google People Also Ask and Autocomplete for Keyword Research (Python Guide)","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscrapear-people-also-autocomplete-keyword-research-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fscrapear-people-also-autocomplete-keyword-research-og.webp","2026-07-14T16:06:25+00:00","2026-10-03T08:29:54+00:00",124,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[91],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":94,"slug":95,"title":96,"excerpt":97,"featured_image_url":98,"featured_image_alt":99,"card_image_url":100,"og_image_url":101,"published_at":102,"updated_at":102,"content_updated_at":103,"reading_time_minutes":104,"is_featured":26,"indexable":26,"views":105,"author":106,"categories":107,"tags":109},154,"rastrear-marca-google-ai-overviews-1","Cómo rastrear tu marca en Google AI Overviews: guía estratégica para equipos SEO","Los AI Overviews aparecen en ~36% de búsquedas informativas y la cita de fuentes es el nuevo KPI. Aprende a medir tu visibilidad con un pipeline de proxies residenciales y Playwright.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Frastrear-marca-google-ai-overviews-1-master.webp","How to Track Your Brand in Google AI Overviews: A Strategic Guide for SEO & Data Teams","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Frastrear-marca-google-ai-overviews-1-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Frastrear-marca-google-ai-overviews-1-og.webp","2026-07-14T10:05:37+00:00","2026-10-03T08:29:51+00:00",10,66,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[108],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":111,"slug":112,"title":113,"excerpt":114,"featured_image_url":115,"featured_image_alt":116,"card_image_url":117,"og_image_url":118,"published_at":119,"updated_at":119,"content_updated_at":120,"reading_time_minutes":32,"is_featured":26,"indexable":26,"views":121,"author":122,"categories":123,"tags":125},152,"construir-rastreador-rankings-python-proxies-residenciales","Construye un rastreador de rankings de Google en Python con proxies residenciales","Guía práctica para desarrolladores: modelo de datos, paginación SERP, fingerprinting TLS, proxies residenciales con geo-targeting y endurecimiento en producción usando curl_cffi y el SDK de ProxyHat.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fconstruir-rastreador-rankings-python-proxies-residenciales-master.webp","Build a Google Rank Tracker in Python with Residential Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fconstruir-rastreador-rankings-python-proxies-residenciales-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fes\u002Fconstruir-rastreador-rankings-python-proxies-residenciales-og.webp","2026-07-02T16:04:58+00:00","2026-10-03T23:53:00+00:00",56,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[124],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],[]]