Página 1 de 4

Mejorar scrapertools

Publicado: 06 Ene 2016, 22:27
por SeiTaN
Buenas,

Estoy mirando de crear una versión nueva de scrapertools, y he hecho este pequeño codigo, de momento he utilizado la libreria "requests", queda pendiente de hacer para urllib2, ya que requests no es compatible con todas las plataformas.

scrapertoolsv2.py

Código: Seleccionar todo

from lib import requests

def get_page(url):
    try:
        response = requests.get(url)
        response.raise_for_status()

    except requests.exceptions.ConnectTimeout as e:
        raise RequestError("Timeout: {0}".format(url), e)
    except requests.exceptions.HTTPError as e:
        raise RequestError("HTTPError: {0}".format(url), e)
    except requests.exceptions.ConnectionError as e:
        # TODO internacionalizar el texto
        raise RequestError("No se ha podido encontrar: {0}".format(url), e)
    except requests.exceptions.RequestException as e:
        # TODO internacionalizar el texto
        raise RequestError("Se ha producido un error: {0}".format(url), e)

    return response.content


class RequestError(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super(RequestError, self).__init__(message)

        logger.info("{0} {1}".format(message, errors))

canal.py

Código: Seleccionar todo

from core import scrapertoolsv2 as scrapertools
from core.scrapertoolsv2 import RequestError



def series(item):
    logger.info("pelisalacarta.seriesblanco series")

    itemlist = []

    try:
        data = scrapertools.get_page(item.url)

        data = re.sub(r"\n|\r|\t|\s{2}|&nbsp;|<Br>|<BR>|<br>|<br/>|<br />|-\s", "", data)
        data = re.sub(r"<!--.*?-->", "", data)
        data = unicode(data, "iso-8859-1", errors="replace").encode("utf-8")

        patron = "<li><a href='([^']+)' title='([^']+)'>[^<]+</a></li>"

        matches = re.compile(patron, re.DOTALL).findall(data)

        # como no viene el thumbnail en esta pagina ponemos el thumbnail generico del canal
        thumbnail = channel_xml["thumbnail"]

        for scrapedurl, scrapedtitle in matches:
            itemlist.append(Item(channel=__channel__, title=scrapedtitle, url=urlparse.urljoin(HOST, scrapedurl),
                                 action="episodios", show=scrapedtitle, thumbnail=thumbnail, context=CONTEXT))

    except RequestError as err:
        item = Item(title="{0}".format(err))
        itemlist.append(item)

    return itemlist
Para poder usarlo sería tan simple como encapsular el codigo en un try/catch y añadir la excepcion personalizada que guarda el error en itemlist

Con esto se consigue que si hay un error al obtener datos de una página, nos añadiria un item con el titulo del error, sería más visible para el usuario que ha habido un error y no que devuelva un itemlist vacío.

¿Qué os parece?¿Alguna cosa para mejorar?

Re: Mejorar scrapertools

Publicado: 07 Ene 2016, 22:41
por divadr
La verdad es que no me he mirado mucho la librería "requests", pero realmente merece la pena usarla? que ventajas tiene sobre usar urllib como se hace hasta ahora?

Re: Mejorar scrapertools

Publicado: 07 Ene 2016, 23:15
por SeiTaN
divadr escribió:La verdad es que no me he mirado mucho la librería "requests", pero realmente merece la pena usarla? que ventajas tiene sobre usar urllib como se hace hasta ahora?
Es más sencillo de hacer todo:

Requests is an Apache2 Licensed HTTP library, written in Python, for human beings.

Most existing Python modules for sending HTTP requests are extremely verbose and cumbersome. Python's builtin urllib2 module provides most of the HTTP capabilities you should need, but the api is thoroughly broken. It requires an enormous amount of work (even method overrides) to perform the simplest of tasks.



Aqui un ejemplo:
https://gist.github.com/kennethreitz/973705

Para la nueva versión quiero hacer la misma funcionalidad para tanto requests como urllib2 para que sea transparente a la plataforma, si veo un poco más adelante que no merece la pena pues se utiliza una sola opción (la de urllib2), pero de momento me resulta más sencillo montar una nueva versión sobre requests ya que es más fácil de hacer las cosas.



Sobre el fichero scrapertools...

1) He visto que hay mucho metodo encadenado.

get_page --> cachePage (ahora mismo no se cachea nada siempre se carga la web) --> downloadpage

Por lo que cambiando un par de llamadas (la mayoria van a get_page), se podría eliminar tanto metodo innecesario.

2) ¿porque se usa para establecer el timeout "socket"?

Código: Seleccionar todo

def cache_page(url, post=None, headers=None, modo_cache=CACHE_ACTIVA, timeout=socket.getdefaulttimeout()):
https://docs.python.org/2/library/socket.html
documentacion escribió:socket.getdefaulttimeout()
Return the default timeout in seconds (float) for new socket objects. A value of None indicates that new socket objects have no timeout. When the socket module is first imported, the default is None.
Si se está obteniendo "None" que es no tener timeout, por que no usar...

Código: Seleccionar todo

def cache_page(url, post=None, headers=None, modo_cache=CACHE_ACTIVA, timeout=None):
en vez de

Código: Seleccionar todo

def cache_page(url, post=None, headers=None, modo_cache=CACHE_ACTIVA, timeout=socket.getdefaulttimeout()):
¿Se me escapa algo?

He subido el codigo que llevo de momento a un gist para que resulta más legible, AQUI

Un saludo.

Re: Mejorar scrapertools

Publicado: 07 Ene 2016, 23:34
por divadr
Esto me interesa, porque pensaba abrir yo este tema... pero por falta de tiempo no lo he echo...

Yo hace tiempo modifique el scrapertools... nunca lo he llegado a subir, aunque en mis versiones lo uso, y funciona correctamente...

hay 10 funciones diferentes para hacer peticiones a paginas, y eso es demasiado, es un lio cuando quieres modificar algo...

Yo lo modifique porque cuando hice el "Buscador global" con la opción multithread, para buscar mas rápidamente en paralelo, tuve un problema, y es que el scrapertools usa un fichero de cookies para todas las paginas, de manera que 100 threads, leyendo y escribiendo al mismo tiempo en el mismo fichero daba error, lo solucione modificando la función para que guardara las cookies en un fichero para cada dominio dentro de una carpeta llamada "cookies"...

pero me encontré con semejante lio... y había que modificar en un montón de sitios así que decidí dejar una sola función para peticiones, que por medio de pasar argumentos, pudiera hacer lo mismo que las otras 10, que básicamente es devolver headers o no, devolver un solo header, usar o no cookies, etc...

deje dos funciones downloadpage y cache_page, la primera para peticiones, y la segunda para gestionar el chache, y si se tiene que volver a descargar la pagina, llama a la primera. De este modo se concentra todo en una única función...

si te interesa, te lo paso, quizá te sirva para coger alguna idea...

Por otra parte:

Lo del timeout = None, no me parece correcto, yo creo que habría que dejar un timeout por defecto, algo razonable, y si la pagina no responde en ese tiempo, que de error

y lo de mostrar los errores, me parece una buena idea, pero no creo que el try / except deba estar en los canales, sino en el launcher, de lo contrario es repetir un montón de código innecesariamente.

Re: Mejorar scrapertools

Publicado: 07 Ene 2016, 23:59
por SeiTaN
divadr escribió: si te interesa, te lo paso, quizá te sirva para coger alguna idea...

Por otra parte:

Lo del timeout = None, no me parece correcto, yo creo que habría que dejar un timeout por defecto, algo razonable, y si la pagina no responde en ese tiempo, que de error

y lo de mostrar los errores, me parece una buena idea, pero no creo que el try / except deba estar en los canales, sino en el launcher, de lo contrario es repetir un montón de código innecesariamente.
- Claro que me interesa, muchas gracias.

- Lo del timeout es que tenía la duda, indagaré a falta de que tengais alguna sugerencia de que valor poner por defecto.

- lo del try/except lo pensé, pero como estamos pendientes del tema del launcher no lo toque. Probaré a ver, si lo hago funcionar correctamente y si es asi pues no habría que tocar nada de codigo en los canales :mrgreen:

Un saludo.

Re: Mejorar scrapertools

Publicado: 08 Ene 2016, 01:33
por robalo
urllib2 y httplib son más completos que urllib si lo que quieres es recuperarar datos extras de la respuesta y controlar errores aunque para lo que hacemos aquí con el open y el read y con un poco de imaginación vamos sobraos :)

El timeout es cuestión de gustos y de la paciencia que tenga cada uno, una web bien pensada no debería necesitar usarlo y si lo necesita, cuanto tiempo estaría dispuesto a esperar?

Re: Mejorar scrapertools

Publicado: 08 Ene 2016, 08:06
por SeiTaN
Me lo apunto robalo, gracias.

httplib and httplib2 handles HTTP/HTTPs request and response directly and give you more space to do your own job.

urllib and urllib2 are build upon httplib, they are more abstract and powerful, but sometimes won't fulfill your specified need about some HTTP related operations.


http://hustcalm.me/blog/2013/11/14/http ... ifference/



Por otro lado una cosa que recordé anoche, deberíamos definir los exception que usamos, ya que si se usa el try/except en el launcher para los errores, en donde haya un exception "generica", no se ejecutaría y se pararía el programa, vease el ejemplo del método "search" que tiene cada canal.

Re: Mejorar scrapertools

Publicado: 08 Ene 2016, 21:46
por SeiTaN
He tocado dos tonterias https://gist.github.com/SeiTaN80/2df49e574dd08886ef47

Estoy repasando lo siguiente para ver si implementarlo o no, la caché que ya comenté que no se está usando y las cookies que parece que tampoco.

De las cookies, he visto que se usa cookielib y ClientCookie (muy antiguo).

¿sabeis si se usan las cookies para algo en algun sitio?

Si fuera el caso, ¿alguien sabe si se necesita ClientCookie para algo?

Un saludo.

Re: Mejorar scrapertools

Publicado: 09 Ene 2016, 11:09
por robalo
El tema de las cookies es simple, se necesitan si no a que viene tanto curro de parte de jesus en el tema de cookies? que existe una forma más moderna de hacerlo? pues vale, pero si el método funciona no veo por qué cambiarlo.

He visto el código del v2 y creo que ahora mismo es igual a esto sin comprobar excepciones

Código: Seleccionar todo

## Cargar los datos con la librería 'requests'
def request_page( url, post=None, headers={ 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0' } ):
    try: from lib import requests
    except: import requests
    if post:
        response = requests.post( url, data=post, headers=headers )
    else:
        response = requests.get( url, headers=headers )
    return response.content
Por qué es igual? por que no gestiona la sesiones con las cookies.
Lo único que debes hacer para probar si se necesita gestionar las cookies es probar el code v2 tal está o el mini v2 en un canal que lo necesite :)

Re: Mejorar scrapertools

Publicado: 09 Ene 2016, 11:36
por SeiTaN
Gracias robalo por las observaciones.

Probaré con pordede, que tengo cuenta y me supongo que se tendrá que mandar cookies.