IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Extraction de données sur un site internet

VI L'application Php - code partie 2

Extraction des données : les fiches films [extraction2.php]

1) Principe

Le procédé est similaire à celui décrit précédemment.
Il s'agit de repérer dans la page html le bloc de code contenant les informations.


Le résultat sera placé dans un tableau associatif $film qui contiendra les champs :
'TITRE', 'PAYS', 'ANNEE', 'GENRES', 'DUREE', 'DATE_DE_SORTIE', 'ACTEURS', 'REALISATEUR' et 'SYNOPSIS'.
Les champs 'GENRES' et 'ACTEURS' sont eux-mêmes des tableaux.
$film sera ensuite donné en paramètre à la fonction de traitement correspondant.


2) L'extraction
  2-1) Voici le dump du code html concerné. Lorsque l'on regarde le source complet de la page, c'est le morceau commençant par la balise "<FONT Class="titrePage">" et finissant par "</TABLE>". Nous conviendrons d'appeler ce morceau "bloc fiche".

   
<FONT Class="titrePage">Jackie Brown</FONT></TD></TR><TR>

<TD><font >Film</font> <FONT Class="size2">américain</FONT> <font >(1997)</font>. <FONT Class="size2">Policier</FONT>, <FONT Class="size2">Drame</FONT>. <FONT Class="size2">Durée : 2h 30mn. </FONT></TD></TR><TR><TD><FONT Class="titreDescription">Date de sortie : </FONT><A href='/film/agenda_gen_semaine=01/04/1998.html#Semaine' Class="link1">01 Avril 1998</A></TD></TR>

<TR><TD><FONT Class="titreDescription">Avec </FONT><A Href="/personne/fichepersonne_gen_cpersonne=20218.html" Class="link1">Pam Grier</A>, <A Href="/personne/fichepersonne_gen_cpersonne=14454.html" Class="link1">Samuel L. Jackson</A>, <A Href="/personne/fichepersonne_gen_cpersonne=8.html" Class="link1">Robert De Niro</A>, <A Href="/personne/fichepersonne_gen_cpersonne=11404.html" Class="link1">Bridget Fonda</A>, <A Href="/personne/fichepersonne_gen_cpersonne=11657.html" Class="link1">Michael Keaton</A>  <a href="/film/casting_gen_cfilm=16876.html" class="link14">Plus...</a></TD></TR>

<TR><TD><FONT Class="titreDescription">Réalisé par </FONT><A Href="/personne/fichepersonne_gen_cpersonne=15570.html" Class="link1">Quentin Tarantino</A></TD></TR></TABLE>


2-2) Si on regarde attentivement la fiche il est possible d'effectuer un traitement assez simple :
- remplacement des fins de ligne de tableau par un retour chariot
- suppression du html
Le résultat donne :
   
Jackie Brown
Film américain (1997). Policier, Drame. Durée : 2h 30mn.
Date de sortie : 01 Avril 1998
Avec Pam Grier, Samuel L. Jackson, Robert De Niro, Bridget Fonda, Michael Keaton Plus...
Réalisé par Quentin Tarantino
L'extraction des données est facile à appréhender !

Le traitement est en fait un tout petit peu plus compliqué. Il est réalisé dans la fonction suivante :
  <?php
  function filtre_html($s) {
  $s = str_replace("\r\n","",$s);
    $s = str_replace("\n","",$s);
    $s = str_replace("</TR>","</TR>\n",$s);
    $s = strip_tags($s);
    $s = str_replace(" "," ",$s);
    return($s);
  }
  ?>


Il n'est pas nécessaire de s'attarder sur le code d'extraction. Le script Php est commenté.
  <?php
  $html = get_html($url,$parametres);
  
  $pos1 = strpos($html, "<FONT Class=\"titrePage\">");
  $pos2 = strpos($html, "<FONT Class=link7>Synopsis</FONT>",$pos1);
  $data_brut = filtre_html(substr($html,$pos1,$pos2-$pos1));
  
  /* suite à cette manipulation $data_brut est de la forme :
  l0 : Jackie Brown
  l1 : Film américain (1997). Policier, Drame. Durée : 2h 30mn.
  l2 : Date de sortie : 01 Avril 1998
  l3 : Avec Pam Grier, Samuel L. Jackson, Robert De Niro, Bridget Fonda, Michael Keaton Plus...
  l4 : Réalisé par Quentin Tarantino
  (etc)    
  */
  $data=split("\n", $data_brut);
  $no_ligne=0;
  // ligne 0 : titre
  $titre = trim($data[$no_ligne]);
  
  // ligne 1 :
  $no_ligne++;
  list($pays, $genres, $duree) = split("\.", $data[$no_ligne]);
  // $pays = "Film américain (1997)"
  $pos1b=strpos_reverse($pays,'(', strlen($pays));
  $pos2b=strpos($pays,')',$pos1b);
  $annee = trim(substr($pays,$pos1b+1,$pos2b-$pos1b-1));
  $pays=trim(substr($pays,0,$pos1b));
  // $genres : tableau
  // $genres = "Policier, Drame"
  $genres = explode(",",$genres);
  trim_tableau($genres);
  // $duree = "Durée : 2h 30mn";
  // convertie en minutes
  $duree = trim(str_replace("Durée : ","",$duree));
  $duree = hoursmin_to_minutes($duree);
  if ($duree==0) $duree='';

  // ligne 2 :
  // $date_de_sortie = "Date de sortie : 01 Avril 1998"
  // attention, cette ligne n'est pas obligatoire
  $no_ligne++;
  if (strpos($data[$no_ligne],'Date de sortie')===FALSE)
    $date_de_sortie = "";
  else {    
    $date_de_sortie = trim(str_replace("Date de sortie : ","",$data[$no_ligne]));
    $no_ligne++;
  }

  // ligne 3 :
  // $acteurs : tableau
  // $acteurs = "Avec Pam Grier, Samuel L. Jackson, Robert De Niro, Bridget Fonda, Michael Keaton Plus...";
  $acteurs = trim(str_replace("Avec","",$data[$no_ligne]));
  $acteurs = trim(str_replace("Plus...","",$acteurs));
  $acteurs=explode(",",$acteurs);
  trim_tableau($acteurs);
  $no_ligne++;
  
  // ligne 4 :
  // $réalisateur = "Réalisé par Quentin Tarantino"
  $realisateur = trim(str_replace("Réalisé par ","",$data[$no_ligne]));

  // extraction du synopsis
  // on reprend le fichier à partir de $pos2 (position du Synopsis)
  $pos1 = $pos2;
  $pos2 = strpos($html, "</FONT></DIV></TD></TR>",$pos1);
  $synopsis = filtre_html(substr($html,$pos1,$pos2-$pos1));
  $synopsis = trim(str_replace("Synopsis","",$synopsis));
  ?>


On notera l'utilisation de fonctions situées dans lib.php comme hoursmin_to_minutes(). Cette fonction convertit une durée de la forme "2h 29mn" en son équivalent en minutes :
  <?php
  function hoursmin_to_minutes($s) {
    // convertit une heure "2h 29mn" en minutes => 149
    $r=0;
    $s=trim($s);
    $pos1 = strpos($s, "h");
    if ((!$pos1===FALSE)) {
      $r=substr($s,0,$pos1);
      $r=((int)substr($s,0,$pos1)) * 60;
      $pos2 = strpos($s, "mn", $pos1);
      if ((!$pos2===FALSE)) {
        $r += (int)trim(substr($s,$pos1+1,$pos2-$pos1-1));
      }
    }
    return($r);
  }
  ?>

Le résultat est stocké dans les variables : $titre, $pays, $annee, $genres, $duree, $date_de_sortie, $acteurs, $realisateur, $synopsis.
Ensuite, ces variables viennent alimenter un tableau associatif :
  <?php
  $film = array (
    'TITRE' => $titre,
    'PAYS' => $pays,
    'ANNEE' => $annee,
    'GENRES' => $genres,
    'DUREE' => $duree,
    'DATE_DE_SORTIE' => $date_de_sortie,
    'ACTEURS' => $acteurs,
    'REALISATEUR' => $realisateur,
    'SYNOPSIS' => $synopsis
  );
  ?>

Puis, le traitement se poursuit en fonction du choix de la sortie :
  <?php
  if ($HTTP_POST_VARS['format_resultat']=="html") {
    ... TRAITEMENT SORTIE HTML ...
  }
  else if ($HTTP_POST_VARS['format_resultat']=="xml") {
    ... TRAITEMENT FLUX XML ...
  }
  else if ($HTTP_POST_VARS['format_resultat']=="mysql") {
    ... TRAITEMENT INSERTION MySQL ...
  }
  ?>


3) Sortie Html

C'est le traitement le plus simple. Il n'est là que pour contrôler le fonctionnement du script.
  <?php
  if ($HTTP_POST_VARS['format_resultat']=="html") {
    echo genere_html_film($film)."<br>\n";
  }
  ?>

La fonction genere_html_film() crée une chaîne html contenant les informations. On notera que les tableaux ont un traitement particulier (boucle foreach).
  <?php
  function genere_html_film($a) {
    $r = "<b>Titre :</b> " . $a['TITRE'] . "<br>\n";
    $r .= "<b>Pays :</b> " . $a['PAYS'] . "<br>\n";
    $r .= "<b>Année :</b> " . $a['ANNEE'] . "<br>\n";
    $r .= "<b>Genres :</b> ";
      foreach($a['GENRES'] as $i)
        $r .= "$i, ";
      $r = substr($r, 0, strlen($r) - 2) . "<br>\n";
    $r .= "<b>Durée :</b> " . $a['DUREE'] . " minutes<br>\n";
    $r .= "<b>Date de sortie :</b> " . $a['DATE_DE_SORTIE'] . "<br>\n";
    $r .= "<b>Acteurs :</b> ";
      foreach($a['ACTEURS'] as $i)
        $r .= "$i, ";
      $r = substr($r, 0, strlen($r) - 2) . "<br>\n";
    $r .= "<b>Réalisateur :</b> " . $a['REALISATEUR'] . "<br>\n";
    $r .= "<b>Synopsis :</b> " . $a['SYNOPSIS'] . "<br>\n";
    return($r);  
  }
  ?>


4) Flux XML

Le traitement est presque identique au précédent. En amont, il a fallu préciser l'en-tête de la page :
<?xml version="1.0" encoding="ISO-8859-1"?>
et ouvrir une balise XML <LISTE_FILMS>. Elle contiendra tous les films, chacun placé dans une balise <FILM>.
  <?php
  else if ($HTTP_POST_VARS['format_resultat']=="xml") {
    echo genere_xml_film($film);
  }
  ?>

La sortie XML sera de la forme :
<?xml version="1.0" encoding="ISO-8859-1" ?>
 - <LISTE_FILMS>
   - <FILM>
    <TITRE>Jackie Brown</TITRE>
    <PAYS>Film américain</PAYS>
    <ANNEE>1997</ANNEE>
    <GENRE>Policier</GENRE>
    <GENRE>Drame</GENRE>
    <DUREE>150</DUREE>
    <DATE_DE_SORTIE>01 Avril 1998</DATE_DE_SORTIE>
    <ACTEUR>Pam Grier</ACTEUR>
    <ACTEUR>Samuel L. Jackson</ACTEUR>
    <ACTEUR>Robert De Niro</ACTEUR>
    <ACTEUR>Bridget Fonda</ACTEUR>
    <ACTEUR>Michael Keaton</ACTEUR>
    <REALISATEUR>Quentin Tarantino</REALISATEUR>
    <SYNOPSIS>Jackie Brown, hôtesse de l'air, arrondit ses fins de mois en convoyant de l'argent liquide pour le compte d'un trafiquant d'armes, Ordell Robbie. Un jour, un agent federal et un policier de Los Angeles la cueillent à l'aéroport. Ils comptent sur elle pour faire tomber le trafiquant. Jackie échafaude alors un plan audacieux pour doubler tout le monde lors d'un prochain transfert qui porte sur la modeste somme de cinq cent mille dollars. Mais il lui faudra compter avec les complices d'Ordell, qui ont des méthodes plutôt expéditives.</SYNOPSIS>
   </FILM>
 </LISTE_FILMS>

Il est possible d'exploiter directement le XML en appelant extraction2.php depuis une application, avec les mêmes paramètres que ceux envoyés en POST depuis le script extraction1.php, et de récupérer le flux.


5) Insertion MySQL

L'insertion se fait sur les tables principales : PAYS, REALISATEUR, FILM, ACTEUR et GENRE, puis ensuite sur les tables associatives ACTEUR_FILM et GENRE_FILM.
Avant une insertion, on vérifie que l'enregistrement n'existe pas dans la base. Cette opération étant très répétitive, elle a été factorisée en une fonction : insertion_table()
Les paramètres : la valeur à insérer, le nom de la table, le nom de l'index primaire de la table et le nom du champ. Si l'enregistrement existe, son id est retourné, sinon, l'enregistrement est créé et le nouvel id retourné.
  <?php
  function insertion_table($element, $table, $id_primaire_table, $nom_champ_element) {
    // insertion de l'élément $element dans la table $table et renvoie son id
    // si l'élément existe déjà, retourne son id
    global $mysql_link;
    $element=trim($element);
    $sql = "SELECT $id_primaire_table FROM $table WHERE $nom_champ_element LIKE '$element'";
    $result = mysql_query($sql, $mysql_link);
    if (mysql_num_rows($result)==0) {
      mysql_free_result($result);
      $sql = "INSERT INTO $table($nom_champ_element) VALUES('$element')";
      mysql_query($sql, $mysql_link);
      $id_primaire_table = mysql_insert_id($mysql_link);
    }
    else {
      $row = mysql_fetch_row($result);
      $id_primaire_table = $row[0];
      mysql_free_result($result);
    }
    return($id_primaire_table);
  }
  ?>

Pour les besoins de notre application, une fonction similaire existe_table() vérifie l'existence d'un enregistrement dans une table et retourne son id, ou 0 s'il n'existe pas.

Voici le code d'insertion dans la base :
  <?php
  // ajout du film
  $id_film = existe_table($film['TITRE'], 'FILM', 'ID_FILM', 'TITRE');
  if ($id_film==0) {
    // ajout du pays
    $id_pays=insertion_table($film['PAYS'], 'PAYS', 'ID_PAYS', 'NOM_PAYS');
    // ajout du réalisateur
    $id_realisateur=insertion_table($film['REALISATEUR'], 'REALISATEUR', 'ID_REALISATEUR', 'NOM_REALISATEUR');
    if ($film['ANNEE']!='') $film['ANNEE']=$film['ANNEE'].'-01-01';
    $sql="INSERT INTO FILM(TITRE, PAYS_ID, ANNEE, DUREE, DATE_SORTIE, REALISATEUR_ID, SYNOPSIS)
    VALUES('".addslashes($film['TITRE'])."', $id_pays, '".$film['ANNEE']."', '".$film['DUREE']."',
    '".$film['DATE_DE_SORTIE']."', $id_realisateur, '".addslashes($film['SYNOPSIS'])."')";
    mysql_query($sql, $mysql_link);
    $id_film=mysql_insert_id($mysql_link);

    // ajout des acteurs
    foreach($film['ACTEURS'] as $acteur) {
     $id_acteur=insertion_table($acteur, 'ACTEUR', 'ID_ACTEUR', 'NOM_ACTEUR');
      $sql="INSERT INTO ACTEUR_FILM(ACTEUR_ID,FILM_ID) VALUES($id_acteur, $id_film)";
      mysql_query($sql, $mysql_link);
    }

    // ajout des genres
    foreach($film['GENRES'] as $acteur) {
     $id_genre=insertion_table($acteur, 'GENRE', 'ID_GENRE', 'NOM_GENRE');
      $sql="INSERT INTO GENRE_FILM(GENRE_ID,FILM_ID) VALUES($id_genre, $id_film)";
      mysql_query($sql, $mysql_link);
    }
  }
  ?>