Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 343 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
343 jpm 1
<?php
2
// Encodage : UTF-8
3
// +-------------------------------------------------------------------------------------------------------------------+
4
/**
5
* Robots
6
*
7
* Description : classe permettant d'analyser les pages d'un site web.
8
* Notes : les noms des pages doivent être dans la bonne casse. http://fr.wikipedia.org/wiki/ambronay ne renvera rien alors que
9
* http://fr.wikipedia.org/wiki/Ambronay renvera un résultat (Notez le A ou a).
10
*
11
//Auteur original :
12
* @author       Jean-Pascal MILCENT <jpm@tela-botanica.org>
13
* @copyright	Tela-Botanica 1999-2009
14
* @link			http://www.tela-botanica.org/wikini/eflore
15
* @licence		GPL v3 & CeCILL v2
16
* @version		$Id: Robot.class.php 2057 2011-05-13 16:39:06Z Jean-Pascal MILCENT $
17
*/
18
// +-------------------------------------------------------------------------------------------------------------------+
19
class Robot extends ScriptCommande {
20
	/**
21
	 * Indique le nom du Robot.
22
	 */
23
	private $robot_nom;
24
	/**
25
	 * Indique le fichier de config de la gestion des cookies du Robot.
26
	 */
27
	private $cookie;
28
	/**
29
	 * Indique l'url de départ du Robot.
30
	 */
31
	private $page;
32
	/**
33
	 * Tableau des URLs à analyse
34
	 */
35
	private $pages = array();
36
	/**
37
	 * Chemin vers un fichier contenant les noms des pages à analyser (un nom de page par ligne).
38
	 */
39
	private $page_fichier;
40
	/**
41
	 * Contient soit False soit le chemin vers le dossier où mettre les pages en cache.
42
	 */
43
	private $cache = false;
44
	/**
45
	 * Contient le squelette de l'url à utiliser pour récupérer les pages web.
46
	 */
47
	private $url_tpl = '';
48
	/**
49
	 * Contient false ou l'encodage des pages d'un site web si celui-ci n'est pas en UTF-8.
50
	 */
51
	private $encodage = false;
52
	/**
53
	 * Contient la chaine de caractères indiquant où commencer une recherche d'informations dans la page web.
54
	 */
55
	private $chaine_debut = '';
56
	/**
57
	 * Contient la chaine de caractères indiquant où terminer une recherche d'informations dans la page web.
58
	 */
59
	private $chaine_fin = '';
60
	/**
61
	 * Tableau des expressions régulières récupérant des données lors de l'analyse
62
	 */
63
	private $regexps = array();
64
	/**
65
	 * Indique le dossier ou fichier où le Robot doit sotcker les informations collectées.
66
	 */
67
	private $sortie;
68
 
69
	public $parametres = array(	'-pgf' => array(false, '', 'Fichier contenant les pages que le Robot doit analyser'),
70
								'-s' => array(false, '', 'Fichier où stocker les données récupérées par le Robot'),
71
								'-pg' => array(false, '', 'Nom de la page que le Robot doit analyser'));
72
 
73
 
74
	public function executer() {
75
		$this->page = $this->getParam('pg');
76
		$this->page_fichier = $this->getParam('pgf');
77
		$this->cookie = dirname(__FILE__).DS.'configuration'.DS.'cookieconf.txt';
78
		$this->sortie = $this->getParam('s');
79
 
80
		// Construction du tableau contenant les noms des pages à analyser
81
		if (empty($this->page_fichier)) {
82
			$this->pages[] = $this->page;
83
		} else {
84
			$this->pages = $this->convertirFichierEnTableau($this->page_fichier);
85
		}
86
 
87
		// Création du chemin du cache si le fichier ini du projet l'indique
88
		if ($this->getIni('cache_chemin')) {
89
			$this->cache = $this->getIni('cache_chemin');
90
		}
91
 
92
		// Lancement du Robot demandé
93
		$cmd = $this->getParam('a');
94
    	switch ($cmd) {
95
			case 'wp' :
96
				$this->lancerRobotWikipedia();
97
				break;
98
			case 'wp-pays' :
99
				$this->lancerRobotWikipediaPays();
100
				break;
101
			case 'wp-liste-communes' :
102
				$this->lancerRobotWikipediaListeCommunes();
103
				break;
104
			case 'ipni' :
105
				$this->lancerRobotIpni();
106
				break;
107
			case 'cassini' :
108
				$this->lancerRobotCassini();
109
				break;
110
			case 'utm' :
111
				$this->lancerRobotUtmConverter();
112
				break;
113
			default :
114
				$this->traiterErreur('Erreur : la commande "%s" n\'existe pas!', array($cmd));
115
		}
116
    }
117
 
118
    /**
119
     * Robot analysant les pages de Wikipedia correspondant à des communes.
120
     * Exemples d'utilisation :
121
	 * /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
122
	 * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier -s ~/importation/robots/wp_communes.tsv
123
	 * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier
124
	 *
125
     * @return unknown_type
126
     */
127
    private function lancerRobotWikipedia() {
128
		// Valeur spécifique de ce Robot
129
		$this->robot_nom = 'eFloreBotWp';
130
		$this->url_tpl = 'http://fr.wikipedia.org/wiki/%s';
131
		$this->regexp_ligne = '/<!-- bodytext -->(.*)<!-- \/bodytext -->/umsi';
132
		$this->regexps = array(	'CodeInsee' => 'Code commune<\/a><\/th>(?:\n|\r\n)<td>(\d+)<\/td>',
133
								'Nom' => 'class="entete map" style="[^"]+">(.*)<',
134
								'Latitutde' => '<span class="geo-dec geo" title=".*"><span class="latitude">(.*)<\/span>',
135
								'Longitude' => '<span class="geo-dec geo" title=".*">.*<\/span>, <span class="longitude">(.*)<\/span>',
136
								'Superficie' => 'Superficie<\/a>(?:<\/b><\/td>|<\/th>)(?:\n|\r\n)<td>((?:[0-9]| |&#160;)+(?:,[0-9]+)?) km<sup>2<\/sup>',
137
								'AltitudeMin' => 'Altitudes<\/a><\/th>(?:\n|\r\n)<td>mini. (-?[0-9]+) m — maxi. [ 0-9]+ m<\/td>',
138
								'AltitudeMax' => 'Altitudes<\/a><\/th>(?:\n|\r\n)<td>mini. -?[0-9]+ m — maxi. ([ 0-9]+) m<\/td>',
139
								'Population' => 'Population<\/a><\/th>(?:\n|\r\n)<td>(.*) hab.',
140
								'PopulationAnnee' => 'Population<\/a><\/th>(?:\n|\r\n)<td>.* hab. <small>\(<a href="\/wiki\/[0-9]+"(?: title="[0-9]+")?>([0-9]+)<\/a>',
141
								'CodePostal' => 'Code postal<\/a><\/th>(?:\n|\r\n)<td>([0-9]{5}).*<\/td>',
142
								'PageWikipedia' => '(?:Ce document provient|Récupérée) de « <a href="http:\/\/fr.wikipedia.org\/wiki\/(.*)">'
143
								);
144
    	// Préparation des noms des pages
145
	    foreach ($this->pages as $id => $nom) {
146
	    	$this->pages[$id] = str_replace(' ', '_', $nom);
147
	    }
148
		$this->analyserUrls();
149
    }
150
 
151
	/**
152
     * Robot analysant les pages de Wikipedia correspondant à des pays.
153
     * Exemples d'utilisation :
154
	 * /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
155
	 *
156
     * @return unknown_type
157
     */
158
    private function lancerRobotWikipediaPays() {
159
		// Valeur spécifique de ce Robot
160
		$this->robot_nom = 'eFloreBotWp';
161
		$this->url_tpl = 'http://fr.wikipedia.org/wiki/%s';
162
		$this->regexp_ligne = '/<!-- bodytext -->(.*)<!-- \/bodytext -->/umsi';
163
		$this->regexps = array(	'Nom' => '<table class="infobox_v2" cellspacing="[^"]+" style="[^"]+">(?:\n|\r\n)<caption style="[^"]+"><b>(.*)<\/b>',
164
								'Latitutde' => '<span class="geo-dec geo" title=".*"><span class="latitude">(.*)<\/span>',
165
								'Longitude' => '<span class="geo-dec geo" title=".*">.*<\/span>, <span class="longitude">(.*)<\/span>',
166
								'Superficie' => 'Superficie<\/a><\/b><\/td>(?:\n|\r\n)<td>((?:[0-9]|\s*|&#160;)+(?:,[0-9]+)?)(?:&#160;|\s*)km<sup>2<\/sup>',
167
								'Population' => 'Population<\/a><\/b>(?:&#160;|\s)*<small>\([0-9]+\)<\/small><\/td>(?:\n|\r\n)<td>(.*)(?:&#160;|\s*)hab.',
168
								'PopulationAnnee' => 'Population<\/a><\/b>(?:&#160;|\s)*<small>\(([0-9]+)\)',
169
								'Capitale' => 'Capitale<\/a><\/b><\/td>(?:\n|\r\n)<td>(?:<a href="\/wiki\/[^"]+" title="[^"]+">|)(.+)<',
170
								'PageWikipedia' => '(?:Ce document provient|Récupérée) de « <a href="http:\/\/fr.wikipedia.org\/wiki\/(.*)">'
171
								);
172
    	// Préparation des noms des pages
173
	    foreach ($this->pages as $id => $nom) {
174
	    	$this->pages[$id] = str_replace(' ', '_', $nom);
175
	    }
176
		$this->analyserUrls();
177
    }
178
 
179
	/**
180
     * Robot analysant une page de wikipedia à la recherche de plusieurs données par page.
181
     * Exemples d'utilisation :
182
	 * /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
183
	 * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier -s ~/importation/robots/wp_communes.tsv
184
	 * /opt/lampp/bin/php script.php robot -p wp_commune -a wp -pg Montpellier
185
	 *
186
     * @return unknown_type
187
     */
188
    private function lancerRobotWikipediaListeCommunes() {
189
		// Valeur spécifique de ce Robot
190
		$this->robot_nom = 'eFloreBotWpListe';
191
		$this->url_tpl = 'http://fr.wikipedia.org/wiki/%s';
192
		$this->regexp_ligne = '/<tr>(.*)?<\/tr>/Uumsi';
193
		$this->mode = 'MULTI';
194
		$this->regexps = array(	'PageWikipedia' => '^<td align="left"><a href="\/wiki\/([^"]+)"',
195
								'CodeInsee' => '^<td>.+<\/td>(?:\n|\r\n)<td>(\d+)<\/td>',
196
								'CodePostal' => '^(?:<td>.+<\/td>(?:\n|\r\n)){2}<td>(\d+)<\/td>',
197
								'Superficie' => '^(?:<td>.+<\/td>(?:\n|\r\n)){4}<td><span.+span>((?:[0-9]| |&#160;)+(?:,[0-9]+)?)<\/td>',
198
								'Population' => '^(?:<td>.+<\/td>(?:\n|\r\n)){5}<td><span.+span>((?:[0-9]| |&#160;)+)<\/td>'
199
								);
200
    	// Préparation des noms des pages
201
	    foreach ($this->pages as $id => $nom) {
202
	    	$this->pages[$id] = str_replace(' ', '_', $nom);
203
	    }
204
		$this->analyserUrls();
205
    }
206
 
207
    /**
208
     * Robot analysant les pages du site de l'IPNI.
209
     * Exemples d'utilisation :
210
	 * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pgf ~/importation/robots/eFloreBotIpni_auteur.txt -s ~/importation/robots/ipni_auteurs.tsv
211
	 * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pg Z -s ~/importation/robots/ipni_auteurs.tsv
212
	 * /opt/lampp/bin/php script.php robot -p ipni_auteur -a wp -pg Z
213
	 *
214
     * @return unknown_type
215
     */
216
	private function lancerRobotIpni() {
217
    	// Valeur spécifique de ce Robot
218
		$this->robot_nom = 'eFloreBotIpni';
219
		$this->url_tpl = 'http://ipni.org/ipni/advAuthorSearch.do?output_format=delimited&find_surname=%s*';
220
		$this->regexp_ligne = '/^(.*)$/umi';
221
		$this->regexps = array(	'Id' => '^([^%]+)%' ,
222
								'Version' => '^(?:[^%]*%){1,}([^%]*)%' ,
223
								'DefaultAuthorName' => '^(?:[^%]*%){2,}([^%]*)%' ,
224
								'DefaultAuthorForename' => '^(?:[^%]*%){3,}([^%]*)%' ,
225
								'DefaultAuthorSurname' => '^(?:[^%]*%){4,}([^%]*)%' ,
226
								'StandardForm' => '^(?:[^%]*%){5,}([^%]*)%' ,
227
								'NameNotes' => '^(?:[^%]*%){6,}([^%]*)%' ,
228
								'NameSource' => '^(?:[^%]*%){7,}([^%]*)%' ,
229
								'Dates' => '^(?:[^%]*%){8,}([^%]*)%' ,
230
								'DateTypeCode' => '^(?:[^%]*%){9,}([^%]*)%' ,
231
								'DateTypeString' => '^(?:[^%]*%){10,}([^%]*)%' ,
232
								'AlternativeAbbreviations' => '^(?:[^%]*%){11,}([^%]*)%' ,
233
								'AlternativeNames' => '^(?:[^%]*%){12,}([^%]*)%' ,
234
								'TaxonGroups' => '^(?:[^%]*%){13,}([^%]*)%' ,
235
								'ExampleOfNamePublished' => '^(?:[^%]*%){14,}([^%]*)$' );
236
		$this->analyserUrls();
237
    }
238
 
239
	/**
240
     * Robot analysant les pages du site de Cassini.
241
     * Exemples d'utilisation :
242
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pgf ~/importation/robots/eFloreBotCassini.txt -s ~/importation/robots/cassini.tsv
243
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 -s ~/importation/robots/cassini.tsv
244
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1
245
	 *
246
     * @return unknown_type
247
     */
248
	private function lancerRobotCassini() {
249
    	// Valeur spécifique de ce Robot
250
		$this->robot_nom = 'eFloreBotCassini';
251
		$this->url_tpl = 'http://cassini.ehess.fr/cassini/fr/html/fiche.php?select_resultat=%s';
252
		$this->encodage = 'ISO-8859-1';
253
		$this->regexp_ligne = '/\s*var\s+chaine1\s+\t=\s+"(.*?)";/umsi';
254
		$this->regexps = array(	'NomCommune' => '^([^\\\\]+)\\\\n' ,
255
								'Superficie' => '\\\\nsuperficie;([^\\\\]+)\\\\n',
256
								'AltitudeMin' => '\\\\naltitude;([^;]+);',
257
								'AltitudeMax' => '\\\\naltitude;[^;]+;([^\\\\]+)\\\\n',
258
								'LambertIIEtenduX' => '\\\\ncoordonnées;Lambert II étendu\\\\n;x;([^\\\\]+)\\\\n',
259
								'LambertIIEtenduY' => '\\\\ncoordonnées;Lambert II étendu\\\\n;x;[^\\\\]+\\\\n;y;([^\\\\]+)\\\\n',
260
								'Latitude' => '\\\\n;Latitude;(.+)?\\\\ncode',
261
								'Longitude' => '\\\\n;Longitude;(.+?)\\\\n;Latitude',
262
								'CodeInsee' => '\\\\ncode insee;([^\\\\]+)\\\\nstatut',
263
								'Statut' => '\\\\nstatut\(s\);([^\\\\]+)\\\\n\\\\n');
264
		$this->analyserUrls();
265
    }
266
 
267
	/**
268
     * Robot analysant les pages du site de Cassini.
269
     * Exemples d'utilisation :
270
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pgf ~/importation/robots/eFloreBotCassini.txt -s ~/importation/robots/cassini.tsv
271
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1 -s ~/importation/robots/cassini.tsv
272
	 * /opt/lampp/bin/php script.php robot -p cassini -a cassini -pg 1
273
	 *
274
     * @return unknown_type
275
     */
276
	private function lancerRobotUtmConverter() {
277
    	// Valeur spécifique de ce Robot
278
		$this->robot_nom = 'eFloreBotUtmConverter';
279
		$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';
280
		$this->encodage = 'ISO-8859-1';
281
		$this->regexp_ligne = '/Universal Transverse Mercator \(UTM\):<\/td>(.*?)<\/table><\/td>/umsi';
282
		$this->regexps = array(	'UTM_Zone' => 'Zone: ([0-9]+)<' ,
283
								'UTM_Est_x' => 'Easting: ([0-9]+)<',
284
								'UTM_Nord_y' => 'Northing: ([0-9]+)<');
285
		$this->analyserUrls();
286
    }
287
 
288
    private function analyserUrls() {
289
    	// Lancement de l'analyse
290
		$heure_debut = date('c',time());
291
 
292
		echo "Analyse de l'URL # : ";
293
		$pagesNum = 0;// Pages
294
		$lignesNum = 0;// Lignes
295
		$sortie = '';
296
		foreach ($this->pages as $paramsPage) {
297
			$xhtml_page = $this->getHtml($this->url_tpl, $paramsPage);
298
			$xhtml_lignes = $this->extraireChaine($this->regexp_ligne, $xhtml_page);
299
 
300
			// Pour chaque chaine début/fin trouvées au sein de la page, nous recherchons les regexps des données.
301
			if (count($xhtml_lignes) > 1 && $this->mode != 'MULTI') {
302
				$this->traiterAttention("Plusieurs lignes correspondent à votre expression régulière de limitation du contenu :\n %s", array($this->regexp_ligne));
303
			} else if ($xhtml_lignes) {
304
				print_r($xhtml_lignes );
305
				foreach ($xhtml_lignes as $xhtml) {
306
					$champsNum = 1;// Champs
307
					$ligne = '';
308
					foreach ($this->regexps as $chp => $regexp) {
309
						// Si nous traitons la première ligne nous ajoutons les noms des champs en début de fichier de sortie
310
						if ($lignesNum == 0) {
311
							$sortie .= $chp.(($champsNum == count($this->regexps)) ? "\n" : "\t");
312
							$champsNum++;
313
						}
314
						// Ajout de la valeur trouvée grâce à l'expression régulière à la ligne de sortie
315
						if (preg_match('/'.$regexp.'/Umsi', $xhtml, $match)) {
316
							$ligne .= $this->nettoyer($match[1])."\t";
317
						} else {
318
							$ligne .= "\t";
319
						}
320
					}
321
					$lignesNum++;
322
					$ligne = trim($ligne);
323
					$sortie .= $ligne."\n";
324
 
325
					// Affichage en console...
326
					if (empty($this->sortie)) {
327
						echo "\t".$ligne."\n";
328
					}
329
				}
330
 
331
			} else {
332
				$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));
333
			}
334
			// Affichage en console...
335
			echo str_repeat(chr(8), ( strlen( $pagesNum ) + 1 ))."\t".$pagesNum++;
336
		}
337
		echo "\n";
338
		$heure_fin = date('c',time());
339
 
340
		// Ajout de métadonnées
341
		$metadonnees = "Début d'importation : $heure_debut\nFin d'importation : $heure_fin\n";
342
		$metadonnees .= "Source des données : ".$this->url_tpl."\n";
343
		$sortie = $metadonnees.$sortie;
344
 
345
		// Écriture du fichier de sortie ou retour dans la console
346
		if (!empty($this->sortie)) {
347
			file_put_contents($this->sortie, $sortie);
348
		}
349
    }
350
 
351
    private function nettoyer($txt) {
352
    	$txt = trim($txt);
353
    	$txt = preg_replace('/(?:&nbsp;|&#160;)/', ' ', $txt);
354
    	return $txt;
355
    }
356
 
357
    private function getHtml($url_tpl, $paramsPage) {
358
		// Lancement en ligne de commande pour tester :
359
		//curl -v --url "http://fr.wikipedia.org/wiki/Montpellier" --config /home/jpm/web/eflore_bp/consultation/scripts/modules/robot/configuration/cookieconf.txt
360
		if ($this->cache && file_exists($fichier_cache = $this->cache.$this->getNomPage($paramsPage))) {
361
			$html = file_get_contents($fichier_cache);
362
		} else {
363
	    	$url = vsprintf($url_tpl, $paramsPage);
364
	    	$this->traiterAttention(" Url : ".$url);
365
	    	// Initialisation CURL
366
	    	$curl = curl_init();
367
		    curl_setopt($curl, CURLOPT_COOKIEFILE, $this->cookie);
368
		    curl_setopt($curl, CURLOPT_URL, $url);
369
		    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
370
		    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1');
371
 
372
		    $html = curl_exec($curl);
373
 
374
		    // Mise en cache
375
		    if ($this->cache) {
376
		    	file_put_contents($fichier_cache, $html);
377
		    }
378
		}
379
 
380
		// Nettoyage des entités html
381
		$html = $this->encoderUtf8($html, 'HTML-ENTITIES');
382
		// Nettoyage de l'encodage des urls
383
		$html = urldecode($html);
384
 
385
		// Convertion en UTF-8 si nécessaire
386
		if ($this->encodage) {
387
			$html = $this->encoderUtf8($html, $this->encodage);
388
		}
389
 
390
	    return $html;
391
	}
392
 
393
	/**
394
	 * Méthode récupérant seulement une partie du texte passé en paramétre.
395
	 *
396
	 * @param $debut chaine de caractère indiquant le début du texte à prendre en compte.
397
	 * @param $fin chaine de caractère indiquant la fin du texte à prendre en compte.
398
	 * @param $txt le texte duquel extraire une partie bornée par $debut et $fin.
399
	 * @return le texte extrait.
400
	 */
401
	private function extraireChaine($regexp, $txt) {
402
	    if (preg_match_all($regexp, $txt, $match)) {
403
	    	return $match[1];
404
	    } else {
405
	    	return false;
406
	    }
407
	}
408
	/**
409
	 * Charge les lignes d'un fichier dans un tableau et le retourne.
410
	 * Supprime les caractères blancs et les nouvelles lignes.
411
	 *
412
	 * @param $fichier
413
	 * @return unknown_type
414
	 */
415
	private function convertirFichierEnTableau($fichier) {
416
		$tableau = array();
417
		$handle = fopen($fichier,'r');
418
		if ($handle) {
419
			while ($ligne = fgets($handle)) {
420
				$tableau[] = explode("\t", trim($ligne));
421
			}
422
			fclose($handle);
423
		}
424
		return $tableau;
425
	}
426
 
427
	private function getNomPage($paramsPage) {
428
		return str_replace(' ', '_', implode('_', $paramsPage)).'.html';
429
	}
430
 
431
}
432
?>