* @copyright Tela-Botanica 1999-2009 * @link http://www.tela-botanica.org/wikini/eflore * @licence GPL v3 & CeCILL v2 * @version $Id: Robot.class.php 2057 2011-05-13 16:39:06Z Jean-Pascal MILCENT $ */ // +-------------------------------------------------------------------------------------------------------------------+ class Robot extends ScriptCommande { /** * Indique le nom du Robot. */ private $robot_nom; /** * Indique le fichier de config de la gestion des cookies du Robot. */ private $cookie; /** * Indique l'url de départ du Robot. */ private $page; /** * Tableau des URLs à analyse */ private $pages = array(); /** * Chemin vers un fichier contenant les noms des pages à analyser (un nom de page par ligne). */ private $page_fichier; /** * Contient soit False soit le chemin vers le dossier où mettre les pages en cache. */ private $cache = false; /** * Contient le squelette de l'url à utiliser pour récupérer les pages web. */ private $url_tpl = ''; /** * Contient false ou l'encodage des pages d'un site web si celui-ci n'est pas en UTF-8. */ private $encodage = false; /** * Contient la chaine de caractères indiquant où commencer une recherche d'informations dans la page web. */ private $chaine_debut = ''; /** * Contient la chaine de caractères indiquant où terminer une recherche d'informations dans la page web. */ private $chaine_fin = ''; /** * Tableau des expressions régulières récupérant des données lors de l'analyse */ private $regexps = array(); /** * Indique le dossier ou fichier où le Robot doit sotcker les informations collectées. */ private $sortie; public $parametres = array( '-pgf' => array(false, '', 'Fichier contenant les pages que le Robot doit analyser'), '-s' => array(false, '', 'Fichier où stocker les données récupérées par le Robot'), '-pg' => array(false, '', 'Nom de la page que le Robot doit analyser')); public function executer() { $this->page = $this->getParam('pg'); $this->page_fichier = $this->getParam('pgf'); $this->cookie = dirname(__FILE__).DS.'configuration'.DS.'cookieconf.txt'; $this->sortie = $this->getParam('s'); // Construction du tableau contenant les noms des pages à analyser if (empty($this->page_fichier)) { $this->pages[] = $this->page; } else { $this->pages = $this->convertirFichierEnTableau($this->page_fichier); } // Création du chemin du cache si le fichier ini du projet l'indique if ($this->getIni('cache_chemin')) { $this->cache = $this->getIni('cache_chemin'); } // Lancement du Robot demandé $cmd = $this->getParam('a'); switch ($cmd) { case 'wp' : $this->lancerRobotWikipedia(); break; case 'wp-pays' : $this->lancerRobotWikipediaPays(); break; case 'wp-liste-communes' : $this->lancerRobotWikipediaListeCommunes(); break; case 'ipni' : $this->lancerRobotIpni(); break; case 'cassini' : $this->lancerRobotCassini(); break; case 'utm' : $this->lancerRobotUtmConverter(); break; default : $this->traiterErreur('Erreur : la commande "%s" n\'existe pas!', array($cmd)); } } /** * Robot analysant les pages de Wikipedia correspondant à des communes. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pgf ~/importation/robots/eFloreBotWp_INSEE_C.txt -s ~/importation/robots/wp_communes.tsv * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier -s ~/importation/robots/wp_communes.tsv * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier * * @return unknown_type */ private function lancerRobotWikipedia() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotWp'; $this->url_tpl = 'http://fr.wikipedia.org/wiki/%s'; $this->regexp_ligne = '/(.*)/umsi'; $this->regexps = array( 'CodeInsee' => 'Code commune<\/a><\/th>(?:\n|\r\n)(\d+)<\/td>', 'Nom' => 'class="entete map" style="[^"]+">(.*)<', 'Latitutde' => '(.*)<\/span>', 'Longitude' => '.*<\/span>, (.*)<\/span>', 'Superficie' => 'Superficie<\/a>(?:<\/b><\/td>|<\/th>)(?:\n|\r\n)((?:[0-9]| | )+(?:,[0-9]+)?) km2<\/sup>', 'AltitudeMin' => 'Altitudes<\/a><\/th>(?:\n|\r\n)mini. (-?[0-9]+) m — maxi. [ 0-9]+ m<\/td>', 'AltitudeMax' => 'Altitudes<\/a><\/th>(?:\n|\r\n)mini. -?[0-9]+ m — maxi. ([ 0-9]+) m<\/td>', 'Population' => 'Population<\/a><\/th>(?:\n|\r\n)(.*) hab.', 'PopulationAnnee' => 'Population<\/a><\/th>(?:\n|\r\n).* hab. \(([0-9]+)<\/a>', 'CodePostal' => 'Code postal<\/a><\/th>(?:\n|\r\n)([0-9]{5}).*<\/td>', 'PageWikipedia' => '(?:Ce document provient|Récupérée) de « ' ); // Préparation des noms des pages foreach ($this->pages as $id => $nom) { $this->pages[$id] = str_replace(' ', '_', $nom); } $this->analyserUrls(); } /** * Robot analysant les pages de Wikipedia correspondant à des pays. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p wp_commune -a wp-pays -pgf ~/importation/robots/eFloreBotWp_pays.txt -s ~/importation/robots/wp-pays.tsv * * @return unknown_type */ private function lancerRobotWikipediaPays() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotWp'; $this->url_tpl = 'http://fr.wikipedia.org/wiki/%s'; $this->regexp_ligne = '/(.*)/umsi'; $this->regexps = array( 'Nom' => '(?:\n|\r\n)(.*)?<\/tr>/Uumsi'; $this->mode = 'MULTI'; $this->regexps = array( 'PageWikipedia' => '^
(.*)<\/b>', 'Latitutde' => '(.*)<\/span>', 'Longitude' => '.*<\/span>, (.*)<\/span>', 'Superficie' => 'Superficie<\/a><\/b><\/td>(?:\n|\r\n)
((?:[0-9]|\s*| )+(?:,[0-9]+)?)(?: |\s*)km2<\/sup>', 'Population' => 'Population<\/a><\/b>(?: |\s)*\([0-9]+\)<\/small><\/td>(?:\n|\r\n)(.*)(?: |\s*)hab.', 'PopulationAnnee' => 'Population<\/a><\/b>(?: |\s)*\(([0-9]+)\)', 'Capitale' => 'Capitale<\/a><\/b><\/td>(?:\n|\r\n)(?:|)(.+)<', 'PageWikipedia' => '(?:Ce document provient|Récupérée) de « ' ); // Préparation des noms des pages foreach ($this->pages as $id => $nom) { $this->pages[$id] = str_replace(' ', '_', $nom); } $this->analyserUrls(); } /** * Robot analysant une page de wikipedia à la recherche de plusieurs données par page. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pgf ~/importation/robots/eFloreBotWp_INSEE_C.txt -s ~/importation/robots/wp_communes.tsv * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier -s ~/importation/robots/wp_communes.tsv * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier * * @return unknown_type */ private function lancerRobotWikipediaListeCommunes() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotWpListe'; $this->url_tpl = 'http://fr.wikipedia.org/wiki/%s'; $this->regexp_ligne = '/
'^.+<\/td>(?:\n|\r\n)(\d+)<\/td>', 'CodePostal' => '^(?:.+<\/td>(?:\n|\r\n)){2}(\d+)<\/td>', 'Superficie' => '^(?:.+<\/td>(?:\n|\r\n)){4}((?:[0-9]| | )+(?:,[0-9]+)?)<\/td>', 'Population' => '^(?:.+<\/td>(?:\n|\r\n)){5}((?:[0-9]| | )+)<\/td>' ); // Préparation des noms des pages foreach ($this->pages as $id => $nom) { $this->pages[$id] = str_replace(' ', '_', $nom); } $this->analyserUrls(); } /** * Robot analysant les pages du site de l'IPNI. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pgf ~/importation/robots/eFloreBotIpni_auteur.txt -s ~/importation/robots/ipni_auteurs.tsv * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pg Z -s ~/importation/robots/ipni_auteurs.tsv * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pg Z * * @return unknown_type */ private function lancerRobotIpni() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotIpni'; $this->url_tpl = 'http://ipni.org/ipni/advAuthorSearch.do?output_format=delimited&find_surname=%s*'; $this->regexp_ligne = '/^(.*)$/umi'; $this->regexps = array( 'Id' => '^([^%]+)%' , 'Version' => '^(?:[^%]*%){1,}([^%]*)%' , 'DefaultAuthorName' => '^(?:[^%]*%){2,}([^%]*)%' , 'DefaultAuthorForename' => '^(?:[^%]*%){3,}([^%]*)%' , 'DefaultAuthorSurname' => '^(?:[^%]*%){4,}([^%]*)%' , 'StandardForm' => '^(?:[^%]*%){5,}([^%]*)%' , 'NameNotes' => '^(?:[^%]*%){6,}([^%]*)%' , 'NameSource' => '^(?:[^%]*%){7,}([^%]*)%' , 'Dates' => '^(?:[^%]*%){8,}([^%]*)%' , 'DateTypeCode' => '^(?:[^%]*%){9,}([^%]*)%' , 'DateTypeString' => '^(?:[^%]*%){10,}([^%]*)%' , 'AlternativeAbbreviations' => '^(?:[^%]*%){11,}([^%]*)%' , 'AlternativeNames' => '^(?:[^%]*%){12,}([^%]*)%' , 'TaxonGroups' => '^(?:[^%]*%){13,}([^%]*)%' , 'ExampleOfNamePublished' => '^(?:[^%]*%){14,}([^%]*)$' ); $this->analyserUrls(); } /** * Robot analysant les pages du site de Cassini. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pgf ~/importation/robots/eFloreBotCassini.txt -s ~/importation/robots/cassini.tsv * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 -s ~/importation/robots/cassini.tsv * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 * * @return unknown_type */ private function lancerRobotCassini() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotCassini'; $this->url_tpl = 'http://cassini.ehess.fr/cassini/fr/html/fiche.php?select_resultat=%s'; $this->encodage = 'ISO-8859-1'; $this->regexp_ligne = '/\s*var\s+chaine1\s+\t=\s+"(.*?)";/umsi'; $this->regexps = array( 'NomCommune' => '^([^\\\\]+)\\\\n' , 'Superficie' => '\\\\nsuperficie;([^\\\\]+)\\\\n', 'AltitudeMin' => '\\\\naltitude;([^;]+);', 'AltitudeMax' => '\\\\naltitude;[^;]+;([^\\\\]+)\\\\n', 'LambertIIEtenduX' => '\\\\ncoordonnées;Lambert II étendu\\\\n;x;([^\\\\]+)\\\\n', 'LambertIIEtenduY' => '\\\\ncoordonnées;Lambert II étendu\\\\n;x;[^\\\\]+\\\\n;y;([^\\\\]+)\\\\n', 'Latitude' => '\\\\n;Latitude;(.+)?\\\\ncode', 'Longitude' => '\\\\n;Longitude;(.+?)\\\\n;Latitude', 'CodeInsee' => '\\\\ncode insee;([^\\\\]+)\\\\nstatut', 'Statut' => '\\\\nstatut\(s\);([^\\\\]+)\\\\n\\\\n'); $this->analyserUrls(); } /** * Robot analysant les pages du site de Cassini. * Exemples d'utilisation : * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pgf ~/importation/robots/eFloreBotCassini.txt -s ~/importation/robots/cassini.tsv * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 -s ~/importation/robots/cassini.tsv * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 * * @return unknown_type */ private function lancerRobotUtmConverter() { // Valeur spécifique de ce Robot $this->robot_nom = 'eFloreBotUtmConverter'; $this->url_tpl = 'http://www.rcn.montana.edu/resources/tools/coordinates.aspx?nav=11&c=DD&md=83&mdt=NAD83/WGS84&lat=%s&lath=N&lon=%s&lonh=E'; $this->encodage = 'ISO-8859-1'; $this->regexp_ligne = '/Universal Transverse Mercator \(UTM\):<\/td>(.*?)<\/table><\/td>/umsi'; $this->regexps = array( 'UTM_Zone' => 'Zone: ([0-9]+)<' , 'UTM_Est_x' => 'Easting: ([0-9]+)<', 'UTM_Nord_y' => 'Northing: ([0-9]+)<'); $this->analyserUrls(); } private function analyserUrls() { // Lancement de l'analyse $heure_debut = date('c',time()); echo "Analyse de l'URL # : "; $pagesNum = 0;// Pages $lignesNum = 0;// Lignes $sortie = ''; foreach ($this->pages as $paramsPage) { $xhtml_page = $this->getHtml($this->url_tpl, $paramsPage); $xhtml_lignes = $this->extraireChaine($this->regexp_ligne, $xhtml_page); // Pour chaque chaine début/fin trouvées au sein de la page, nous recherchons les regexps des données. if (count($xhtml_lignes) > 1 && $this->mode != 'MULTI') { $this->traiterAttention("Plusieurs lignes correspondent à votre expression régulière de limitation du contenu :\n %s", array($this->regexp_ligne)); } else if ($xhtml_lignes) { print_r($xhtml_lignes ); foreach ($xhtml_lignes as $xhtml) { $champsNum = 1;// Champs $ligne = ''; foreach ($this->regexps as $chp => $regexp) { // Si nous traitons la première ligne nous ajoutons les noms des champs en début de fichier de sortie if ($lignesNum == 0) { $sortie .= $chp.(($champsNum == count($this->regexps)) ? "\n" : "\t"); $champsNum++; } // Ajout de la valeur trouvée grâce à l'expression régulière à la ligne de sortie if (preg_match('/'.$regexp.'/Umsi', $xhtml, $match)) { $ligne .= $this->nettoyer($match[1])."\t"; } else { $ligne .= "\t"; } } $lignesNum++; $ligne = trim($ligne); $sortie .= $ligne."\n"; // Affichage en console... if (empty($this->sortie)) { echo "\t".$ligne."\n"; } } } else { $this->traiterAttention("Impossible de trouver les chaines début et fin dans la page «%s» avec la regexp :\n%s", array($this->getNomPage($paramsPage), $this->regexp_ligne)); } // Affichage en console... echo str_repeat(chr(8), ( strlen( $pagesNum ) + 1 ))."\t".$pagesNum++; } echo "\n"; $heure_fin = date('c',time()); // Ajout de métadonnées $metadonnees = "Début d'importation : $heure_debut\nFin d'importation : $heure_fin\n"; $metadonnees .= "Source des données : ".$this->url_tpl."\n"; $sortie = $metadonnees.$sortie; // Écriture du fichier de sortie ou retour dans la console if (!empty($this->sortie)) { file_put_contents($this->sortie, $sortie); } } private function nettoyer($txt) { $txt = trim($txt); $txt = preg_replace('/(?: | )/', ' ', $txt); return $txt; } private function getHtml($url_tpl, $paramsPage) { // Lancement en ligne de commande pour tester : //curl -v --url "http://fr.wikipedia.org/wiki/Montpellier" --config /home/jpm/web/eflore_bp/consultation/scripts/modules/robot/configuration/cookieconf.txt if ($this->cache && file_exists($fichier_cache = $this->cache.$this->getNomPage($paramsPage))) { $html = file_get_contents($fichier_cache); } else { $url = vsprintf($url_tpl, $paramsPage); $this->traiterAttention(" Url : ".$url); // Initialisation CURL $curl = curl_init(); curl_setopt($curl, CURLOPT_COOKIEFILE, $this->cookie); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'); $html = curl_exec($curl); // Mise en cache if ($this->cache) { file_put_contents($fichier_cache, $html); } } // Nettoyage des entités html $html = $this->encoderUtf8($html, 'HTML-ENTITIES'); // Nettoyage de l'encodage des urls $html = urldecode($html); // Convertion en UTF-8 si nécessaire if ($this->encodage) { $html = $this->encoderUtf8($html, $this->encodage); } return $html; } /** * Méthode récupérant seulement une partie du texte passé en paramétre. * * @param $debut chaine de caractère indiquant le début du texte à prendre en compte. * @param $fin chaine de caractère indiquant la fin du texte à prendre en compte. * @param $txt le texte duquel extraire une partie bornée par $debut et $fin. * @return le texte extrait. */ private function extraireChaine($regexp, $txt) { if (preg_match_all($regexp, $txt, $match)) { return $match[1]; } else { return false; } } /** * Charge les lignes d'un fichier dans un tableau et le retourne. * Supprime les caractères blancs et les nouvelles lignes. * * @param $fichier * @return unknown_type */ private function convertirFichierEnTableau($fichier) { $tableau = array(); $handle = fopen($fichier,'r'); if ($handle) { while ($ligne = fgets($handle)) { $tableau[] = explode("\t", trim($ligne)); } fclose($handle); } return $tableau; } private function getNomPage($paramsPage) { return str_replace(' ', '_', implode('_', $paramsPage)).'.html'; } } ?>