Scraping

Cómo hacer coincidir la geolocalización, la zona horaria y el idioma del proxy residencial para sesiones limpias

Una salida alemana que informa una zona horaria de Nueva York es una contradicción que ningún visitante real produce. Deriva cada señal de configuración regional del país de salida y no podrán desincronizarse.

Chris Collins

Chris Collins

27 de agosto de 2026 · 8 min de lectura

Estableces una salida alemana, la dirección geolocaliza correctamente, y el objetivo sigue tratando la sesión como sospechosa o te sirve contenido pensado para otro lugar. La IP era correcta. Todo lo demás en la petición seguía describiendo a un visitante en otro país.

La ubicación no es una sola señal. Es un conjunto de ellas, y un visitante real las produce todas desde el mismo lugar porque proceden de una máquina en un país. Un scraper las ensambla a partir de fuentes distintas: el país viene de un parámetro del proxy, la zona horaria del reloj del servidor, el idioma regional de un valor predeterminado de una librería, y la cabecera de idioma de lo que se haya codificado a mano. Cuando estas señales no coinciden, la contradicción es más detectable que cualquier valor individual, y además puede alterar lo que recopilas.

Las señales que tienen que coincidir

Seis cosas le indican a un sitio dónde estás, y merece la pena enumerarlas explícitamente porque la mayoría de los scrapers controlan una o dos.

La dirección IP es la señal principal y la que fija tu proxy. Accept-Language es la cabecera HTTP que expresa la preferencia de idioma, y muchos sitios sirven contenido directamente a partir de ella. La zona horaria se puede observar en un navegador a través de la API de fecha de JavaScript y, con más precisión, a través de la zona horaria resuelta de la API Intl. El idioma regional (locale) abarca navigator.language y las convenciones de formato que resuelve la API Intl, que determinan cómo se representan fechas, números y moneda. La moneda y las unidades, cuando un sitio permite que el cliente las indique. Y la resolución DNS, que suena ajena al tema pero no lo es: si tu cliente resuelve nombres de host localmente mientras sale por una ubicación remota, la resolución se produce desde tu ubicación real y puede entregarte un endpoint regionalmente incorrecto, que es el problema de la fuga de DNS.

Para trabajo HTTP sencillo solo son visibles las dos primeras y el DNS, razón por la cual el artículo sobre cabeceras trata Accept-Language como el emparejamiento principal. Para la automatización de navegador las seis son observables, y ahí es donde suelen aparecer las discrepancias.

Deriva todo de una única fuente de verdad

La solución es estructural, no una lista de comprobación. Si el país se elige en un lugar y la zona horaria en otro, ambos divergirán la primera vez que alguien añada un mercado. Define cada mercado una sola vez, con todas las señales que implica, y deriva toda la sesión a partir de ese registro.

MARKETS = {
    "de": {"lang": "de-DE,de;q=0.9,en;q=0.8", "locale": "de-DE",
           "tz": "Europe/Berlin",   "currency": "EUR"},
    "us": {"lang": "en-US,en;q=0.9", "locale": "en-US",
           "tz": "America/New_York", "currency": "USD"},
    "jp": {"lang": "ja-JP,ja;q=0.9,en;q=0.8", "locale": "ja-JP",
           "tz": "Asia/Tokyo",      "currency": "JPY"},
    "br": {"lang": "pt-BR,pt;q=0.9,en;q=0.8", "locale": "pt-BR",
           "tz": "America/Sao_Paulo", "currency": "BRL"},
}

def proxy_for(country, session=None):
    user = f"customer-USERNAME-country-{country}"
    if session:
        user += f"-sid-{session}-ttl-600"
    url = f"http://{user}:PASSWORD@p.shifter.io:443"
    return {"http": url, "https": url}

Ahora un mercado es un único argumento, y no existe ninguna ruta de código en la que el país y la zona horaria puedan discrepar, porque nadie los establece por separado.

Aplicándolo a una sesión de navegador

Los frameworks de automatización de navegador exponen la zona horaria y el idioma regional como opciones de contexto, que es el lugar correcto para fijarlos: se aplican antes de que se ejecute ningún script de la página, de modo que la página no puede observar los valores reales de la máquina.

# Playwright: proxy, zona horaria e idioma regional, todos derivados de un único registro de mercado
m = MARKETS[country]
context = browser.new_context(
    proxy={"server": "http://p.shifter.io:443",
           "username": f"customer-USERNAME-country-{country}-sid-{sid}",
           "password": "PASSWORD"},
    locale=m["locale"],                  # navigator.language y el formato de Intl
    timezone_id=m["tz"],                 # zona horaria resuelta por Intl y el desfase de Date
    extra_http_headers={"Accept-Language": m["lang"]},
)

Importa fijar esto a nivel de contexto en lugar de parchear las propiedades después, porque un Intl.DateTimeFormat parcheado que no coincida con el desfase de Date es en sí mismo una inconsistencia detectable, y los scripts de detección suelen comprobar ambos de forma cruzada.

Precisión, y cuánta necesitas

La granularidad de país basta para la mayoría de los trabajos, ya que la zona horaria y el idioma regional son en su mayoría nacionales. Tres casos requieren más cuidado.

Los países con varias zonas horarias hacen que un valor predeterminado nacional sea incorrecto para parte de la población. Una salida en EE. UU. es plausible en varias zonas, así que si estás trabajando con segmentación a nivel de ciudad deberías derivar la zona horaria de la ciudad en lugar del país, y si no es el caso, elige la zona que coincida con la mayor parte de los usuarios y mantente consistente en lugar de aleatorizar.

Los países con varios idiomas oficiales necesitan una elección deliberada: una salida suiza o canadiense puede ser plausiblemente varios idiomas regionales, y la respuesta correcta suele ser la que coincida con el contenido que estás recopilando, mantenida constante.

Las diferencias regionales de formato son más sutiles y rara vez merece la pena perseguirlas, pero si presentas un idioma regional, deja que la API Intl haga el formateo en lugar de construir a mano formatos de fecha y número que puedan no coincidir con lo que ese idioma regional realmente produce.

Consistencia durante toda la sesión

Una sesión es una historia, y la historia no debe cambiar a mitad de camino. Si una sesión persistente (sticky session) mantiene una única dirección para un flujo de varios pasos, cada petición de ese flujo debe llevar el mismo idioma, zona horaria e idioma regional. Cambiar cualquiera de ellos a mitad del flujo describe a un visitante que se ha movido de país entre hacer clic en buscar y ver un resultado, lo cual es una anomalía más fuerte que cualquier discrepancia estática.

Aquí es donde derivar de un único registro de mercado vuelve a dar sus frutos: el identificador de sesión y el conjunto de idioma regional proceden del mismo lugar y duran lo mismo. Vincúlalos explícitamente, de modo que liberar la sesión libere toda la identidad, y una sesión nueva empiece una identidad fresca e internamente consistente. La misma lógica rige el emparejamiento de huellas digitales de dispositivo con la identidad de red en los navegadores antidetección.

Verificar que lo has hecho bien

No asumas nada y comprueba en los dos niveles.

Primero, lo que el navegador informa sobre sí mismo. Ejecuta una página que lea la zona horaria resuelta, navigator.language, y una fecha formateada, y confirma que coinciden con el mercado que pretendías. Esto detecta errores de configuración de inmediato.

JSON.stringify({
  tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
  lang: navigator.language,
  langs: navigator.languages,
  offset: new Date().getTimezoneOffset(),
})

Segundo, y más significativo, lo que hace el objetivo. Solicita una página sensible a la geolocalización y confirma que la moneda, el idioma y el contenido regional son los que vería un visitante local. El comportamiento del propio sitio es el veredicto real, ya que las bases de datos de geolocalización y la opinión de un objetivo no siempre coinciden, y para eso está probar la precisión de la ubicación. Si la dirección geolocaliza correctamente pero el contenido es incorrecto, sospecha primero de la resolución DNS.

En resumen

La ubicación es un conjunto de señales, y un sitio las lee en conjunto. Establecer un país en el proxy mientras se dejan la zona horaria, el idioma regional y el idioma en lo que sea que traiga tu servidor por defecto produce un visitante que no puede existir, lo cual es a la vez una señal de detección y una fuente de datos silenciosamente erróneos. Define cada mercado una sola vez con todas las señales que implica, deriva los parámetros del proxy y el contexto del navegador a partir de ese único registro para que no puedan divergir, fija la zona horaria y el idioma regional a nivel de contexto en lugar de parchearlos después de la carga, mantén todo el conjunto constante durante toda la vida de una sesión, y verifica en ambos niveles, lo que informa el navegador y lo que realmente sirve el objetivo. Entonces lo único que tu tráfico dirá sobre su ubicación será lo único que hayas elegido.

La geografía en sí proviene de los proxies residenciales, direcciones reales de tipo doméstico con segmentación por país y ciudad, de modo que la ubicación que reclama tu sesión sea una ubicación desde la que realmente estás saliendo, con precios por GB adecuados para ejecutar el mismo trabajo en muchos mercados.

¿Listo para empezar?

Prueba los proxies residenciales de Shifter, más de 205M IPs, más de 195 países, desde 0,75 $/GB.

Comenzar