Después de una interrupción de tres meses (increíble cómo pasa el tiempo), por fin he encontrado un hueco para continuar los tutoriales de programación de add-ons abordando algunos de los problemas que te encontrarás cuando programes add-ons en el mundo real.

Y es que no todos los sitios web son sencillos cuando quieres acceder con un plugin, así que en ocasiones es necesario acudir a algunos trucos para conseguir tu objetivo.

He tenido que hacer algunas mejoras en la librería Plugin Tools para permitirle hacer algunos de estos trucos, así que la entrada de hoy empieza explicando en qué consisten estas mejoras para verlas luego en acción sobre casos prácticos.


Añadiendo más funciones de HTTP en PluginTools

Los ejemplos que hemos visto hasta ahora han utilizado la función “read” de PluginTools de una forma muy sencilla: le pasas la URL que quieres leer y te devuelve una cadena con el contenido de esa URL.

body = plugintools.read("http://www.mimediacenter.info")

Cuando esto no funcione habrá que recurrir a la nueva función “read_body_and_headers” de PluginTools, como una versión mejorada de la función “read” que permitirá un montón de posibilidades nuevas:

body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=request_headers, post=custom_post, follow_redirects=True, timeout=10)

Entre las que se incluyen:

  • Gestión de cookies transparente
  • Cabeceras personalizadas (parámetro “headers”)
  • Aumentar el tiempo de espera ante conexiones lentas (parámetro “timeout”)
  • Tratamiento automático de páginas comprimidas con Gzip
  • Envios POST (parámetro “post”)
  • Procesar las redirecciones manualmente (parámetro “follow_redirects”)
  • Acceder a las cabeceras de respuesta
  • Información de depuración adicional

El diseño de la función puede que no sea muy elegante, pero lo que perseguía era tener una función compacta, rápida y sencilla. Si quieres una librería para hacer esto de una forma más “pythonica” puedes recurrir a la librería Python Requests, o a la popular Mechanize. Ambas muy utilizadas y recomendables.

Ahora vamos con algunos ejemplos de uso de “read_body_and_headers”.

Que hacer si el sitio web verifica el User-Agent

Empecemos con un caso sencillo. Cuando haces una llamada HTTP utilizando un navegador cualquiera, dentro de la llamada se envía una cabecera especial llamada “User-Agent” que identifica el navegador que está haciendo la llamada.

Este es el ejemplo de lo que se envía en una llamada HTTP hecha con Firefox para leer la página principal de este blog:

GET / HTTP/1.1
Host: www.mimediacenter.info
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive

Puedes observar que una de las líneas empieza por “User-Agent” e identifica al navegador exacto con el que has hecho la petición:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0

Sin embargo cuando haces una llamada HTTP desde Python usando la función “read” de PluginTools, el navegador empleado es el módulo estándar urllib2 de Python. Y el User-Agent que se manda así lo indica:

GET / HTTP/1.1
User-Agent: Python-urllib/2.1
Host: www.mimediacenter.info
Accept: */*

Puedes ver que en este caso la llamada tiene menos cabeceras, y que el User-Agent identifica claramente a Python como originador de la misma:

Python-urllib/2.1

El caso es que hay sitios web que detectan el User-Agent y lo utilizan con diversos fines, como mostrar un sitio web adaptado al navegador desde el que accedes (útil para móviles) o incluso para bloquear el acceso a ciertos dispositivos.

Por suerte HTTP es un protocolo abierto y bien documentado, de hecho su especificación es una lectura muy recomendable si te dedicas a esto. Con la suficiente habilidad es fácil engañar a cualquier servidor web, y en este caso no podría ser más sencillo ya que basta con enviar la cabecera User-Agent que queramos para que el sitio web no sea capaz de identificarnos como un plugin.

Esto del User-Agent es tan importante que por defecto la función “read_body_and_headers” de PluginTools utiliza un User-Agent de ordenador, concretamente Firefox 18.0 para Mac, siempre que la usas. Si quieres indicar cualquier otro User-Agent basta con que añadas una cabecera HTTP con el parámetro “headers”.

body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=[["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"]])

Verás que “headers” es una lista de cabeceras, que contiene a su vez dos elementos para el nombre de la cabecera y el valor. En el ejemplo la petición se lanza identificándose como “Google Chrome” para Mac.

GET / HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31
Host: www.mimediacenter.info
Accept: */*

Una forma de hacer lo mismo pero más legible, especialmente cuando necesitas añadir varias cabeceras, es añadirlas una por una al array en lugar de declararlo todo en la misma línea:

request_headers=[]
request_headers.append(["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"])
body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info", headers=request_headers)

Cuestión de gustos, pero la legibilidad del código es importante :)

Qué hacer si el sitio web verifica el Referer

Si User-Agent es la cabecera que se envía para que el sitio web sepa qué programa estás utilizando, Referer es la cabecera que se envía para informarle de la página desde donde vienes.

Esta información se utiliza en los sitios web para seguir la navegación del usuario (saber el camino que sigue en un sitio web), y también se utiliza en muchos casos como medida de protección contra el hot-linking.

Te la encontrarás por ejemplo si quieres datos de una página que se encuentran dentro de un iframe, o cuando quieras realizar una llamada AJAX para resolver la paginación. Son casos bastante habituales, y los detectarás cuando pidas una página y el sitio web te devuelva otra, o un error.

La solución es tan sencilla como añadir una segunda cabecera a nuestro ejemplo, poniendo una nueva cabecera “Referer” en la lista para indicar la página de origen que el sitio web esté esperando.

Supongamos que para acceder a la página principal de Plugin Tools en Mi Media Center (http://www.mimediacenter.info/plugintools) fuera necesario hacerlo desde la página principal del sitio (http://www.mimediacenter.info). Bastará con indicar la URL de la página principal como “Referer” al hacer la petición.

request_headers=[]
request_headers.append(["User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"])
request_headers.append(["Referer","http://www.mimediacenter.info/"])
body,response_headers = plugintools.read_body_and_headers("http://www.mimediacenter.info/plugintools/", headers=request_headers)

Puedes ver ejemplos de sitios web que utilizan la verificación del Referer en el código fuente de pelisalacarta, por ejemplo AnimeID, Beeg, Cuevana, JKAnime, Tucinecom, …

Próxima entrada

Todavía quedan algunos trucos más que contar, pero esta entrada ya se está haciendo demasiado larga. En la próxima entrada veremos algunos más incluyendo cómo resolver el caso de un sitio web que requiere login.

Descarga ya la nueva versión de Plugin Tools y anímate a hacer tus propios proyectos, es fácil :)

3 comentarios

  1. Muchísimas gracias.
    Ya pensaba que no ibas a continuar…
    Precisamente hoy te acabo de escribir preguntando por las funciones read y read_body_and_headers. Si tienes un minuto ya me contestarás.

    Un saludo y gracias

  2. Si no los continúo reviento, pero es que he estado ocupado :(

  3. Estimado Jesús, vivo en los Estados Unidos y he tratado de configurar el plug Pelisalacarta utilizando el add-on de XBMC pero me dice que no puedo porque tengo un problema con scrit, no se mucho de esto pero me gusta el cine y las series, será acaso que no existe un plug que trabaje para USA, puede usted ayudarnos, se que esta muy ocupado pero le suplico que cuando pueda me de una respuesta. Jesús QA

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *