General consideration on this projet

Nous listerons ici l'état de l'art, les projets similaires existants Et les principales difficultées rencontrées dans la réalisation de ce projet

Existing crawlers

Nombreux sont les crawlers en ligne celui différe dans la philosophie générale de l'outil

Web Page Article detection

J'ai testé bon nombre des bibliothèques existantes de detection d'article à l'intérieur d'une page HTML toutes centrée autour du même algorithme:

  • newspaper - News extraction, article extraction and content curation in Python.
  • html2text - Convert HTML to Markdown-formatted text.
  • python-goose - HTML Content/Article Extractor.
  • python-readability - Fast Python port of arc90's readability tool.
  • python-pocket - Pocket API in Python (algo de detection d'article a été retiré depuis)

L'algorithme de l'ensemble de ces bibliothèques est simple il est fondé sur le calcul de densité de texte par tag.

Le constat c'est que dans le cas des blogs et des page d'acceuil de site web les résultats ne sont pas concluants: pour les blogs du type wordpress c'est toujours le bloc A propos/About qui est selectionné. En effet les résumés et les liens vers Read more... fausses les résultats Pour finir, on trouve mon implémentation de l'extraction d'article dans extractor.py composé de plusieurs couches:

  • lxml realise un nettoyage initial du HTML les tags non desiré script, noscript, iframe, form, embed, style, footer

  • beautifulsoup enlève les elements avec les tags non desiré script, noscript, iframe, form, embed, style, footer

  • puis readlibility prend le relais favorise certains block qui contient les tags au détriment des autres
POSITIVE_K = ["entry-content","post","main","content","container","blog","article*","post","entry", "row",]
NEGATIVE_K = ["like*","ad*","comment.*","comments","comment-body","about","access","navbar", 
                "navigation","login", "sidebar.*?","share.*?","relat.*?","widget.*?","menu", "side-nav"]

Comme on ne peut garantir la propreté du HTML n'importe laquelle de ses méthodes peut échouer. Mais il y en a toujours au moins une qui fonctionne.

Dans l'idéal, il faudrait mixer trois approches:

  • l'utilisateur peut modifier la liste des tags qu'il souhaite favoriser / défavoriser
  • l'utilisateur peut modifier la liste des tags a ne pas considérer pour qu'ils soient pris en compte par lxml et via beautifulSoup
  • un systeme d'apprentissage est greffé à cette extracteur qui matche meta_information avec les tags à favoriser et detecte lequels appliquer dans quel cas

Il existe d'autre librairies de detection d'article et qui fonctionnent par apprentissage. telles que :

  • scrapely - Library for extracting structured data from HTML pages. Given some example web pages and the data to be extracted, scrapely constructs a parser for all similar pages.
  • libextract - Extract data from websites.
  • sumy - A module for automatic summarization of text documents and HTML pages.

mais dans la mesure ou notre crawler ne sait pas sur quel type de document ou sur quelle plateforme, il faudrait adopter l'approche mixte déclarative + apprentissage au fur et à mesure des crawls

Database Back End

Pourquoi Mongo? What went wrong....

J'ai fait un choix de départ pour la librairie Mongo qui me semblait initialement adaptée à ma problématique: structuration souple facilité de stockage et d' export (format JSON qui s'interface très bien avec python) grande disponibilité et bonne perf full text search et regex search natif (très important)

Mongo est présenté une des bases NoSQL de référencepour du Big Data mais au final le bilan global de cette base de données est assez negatif sinon très négatif. J'en rencontré en effet de gros problème de stockage et de performance

Performance, limit storage and some hugly problem of structuration

  • limite au niveau du document

    • taille limite d'enregistrement du document
    • accès au niveau 1 seulement de l'object JSON
    • accès au liste: premier element seulement est disponible sans agrégation
  • limite de requetage et edition/insertion multiple/:

    • pour appliquer un tri à une base de données mongo il faut que celle ci ne dépasse pas X nombres d'enregistrement
    • pour selectionner les documents uniques en fonction d'un critère il est nécessaire de faire soit un agregate soit une double requete pour accéder aux valeurs annexes
    • lorsqu'un index est créer pour forcer l'enregsitrement de données uniques en fonction d'une clé: l'insertion multiple est inopérante : en cas d'entrée dupliquée impossible de catcher l'erreur
  • limite de performance de la BDD: En raison des temps de parsing de mon crawler, la connexion a la base n'était pas persistante, il faut donc forcer la base à ne pas se refermer à chaque enregistrement

Crawl vertical vs Crawl horizontal

ON ne peut donc pas en l'état avec Mongo simplement réaliser le tri des urls par niveau (la liste est trop longue) en favorisant un crawl horizontal on se retrouve donc au niveau 0 à savoir envisager un simple Set() dans un pickle et des algo d'optimisation de tri par profondeur et par Index

Some solution

EN l'état le texte et le HTML ne sont pas stocké dans la BDD mais en dur dans le fichier de résultats et les documents référencé dans la base de donnée. Pareil pour les versions en fonction de la date à chaque crawl corespond une base de donnée de résultat qui porte la date de début du crawl.

Si j'avais du temps je changerai donc de SGBD en proposant 2 bases une très simple en NOSQL pour la queue de traitement et une pour le stockage final resultats avec un POSTGRES + des fichiers en bases (en effet la question critique est ici comment filtrer efficacement les articles pertinents sachant qu'on utilise Whoosh et que Whoosh lui même se crée un index pour scannerles docs). En l'état le système de Backend est donc tout pourri.

Execution time and paralelization

Pour ce crawler, la question du temps reste porblématique malgré le fait que j'ai introduit dans la dernière version du requetage asynchrone des page HTML

On a deux points de traitement très lourds et très longs: le téléchargement d'une page est fonction de la disponibilité du serveur de cette page le parsing en raison du nettoyage et de la detection de l'article et du texte

Ensuite on traite un nombre très important de pages dont on ignore à l'avance combien de pges à traiter pertinente et sur combien de niveau il est donc contraiement à un crawler sur site très difficile de prévoir le temps de traitement De plus comme je le disais précédemment, le backend ne permet pas le tri des urls par niveau (la liste est trop longue) on ne peux pas donc favoriser un crawl horizontal sur un crawl vertical en l'état. Le crawl horizontal qui traite les pages dans l'ordre croissant de profondeur me paraissait en effet important dans la logique de la constitution du corpus avec l'effet boule de neige et donc les graines seeds partent d'un moteur de recherche en favorisant par la même unenotion annexe de visibilité.