Az elméleti bevezetőt a szemantikus webről megszakítva egy kis PHP 4 beginnerdz következik (bár mi részben php 5 technológiát fogunk használni, mert a PHP 4-es DOM API -t kipakolták és nem akarok senkit külön telepítésekre kényszeríteni).

Van kedvenc online hírportálunknak egy mozirovata, a cinematrix. Sajnos a magyar jog még nem jutott el arra a szintre, hogy a filmkritikát és magát a filmet egymás mellé lehessen tenni, amit mondjuk egy festménnyel jobb helyeken teljes nyugalommal, de saját gépünkön ha AdBlock-ot lehet telepíteni, valószínűleg ezért se fognak ölni.


Mi a terv?

  1. Azonosítsuk, ha filmről van szó, és azt is, melyikről
  2. A filmnek derítsük ki az adatait, legalább az eredeti címét
  3. Az eredeti címe alapján keressünk rá más adatbázisokban magára a filmre
  4. A keresési találatokat jelenítsük meg a film mellett
  5. Ha lehetséges, rakjunk össze egy miniadatlapot a filmhez

A filmek azonosítása

A filmek egyedi azonosításához mi most a Cinematrix adatbázisát fogjuk használni. Egy tipikus filmadatlap címe a következőképpen néz ki:

http://index.hu/kultur/cinematrix/adatlap/20062 (Hajlakk)
http://index.hu/kultur/cinematrix/adatlap/20042 (Utál a csaj)

Ez történetesen az eheti mozibemutatókból kivadászott két link. Némi egyszerűsítéssel (és a hosszadalmas magyarázatot félretéve) azt mondhatjuk, egy olyan webcím, ami index.hu/kultur/cinematrix/adatlap -pal kezdődik, és utána számok vannak, minden valószínűség egy filmet jelent, és minden link, ami ilyen címre mutat, a filmről szól.

Nincs más dolgunk hát, mint az oldal forráskódjában megtalálni az ilyen linkeket. PHP-t feltételezve ezt a következőképp tehetjük meg:

$file=fopen(“http://index.hu/kultur/cinematrix/ccikkek/filmprev0830/”,“r”);
while (
$line=fgets($file)) { // ez soronkent elolvassa az oldalt, es az aktualis sort a $line sztringben tarolja
if (ereg(“index.hu\/kultur\/cinematrix\/adatlap.([0-9]+)”,$line,$eredmeny)){
echo
“van benne film, az azonositoja: “.$eredmeny[1].
;
}
}
?>
Eredményül ez a következőt fogja adni:

van benne film, az azonositoja: 20062
van benne film, az azonositoja: 670
van benne film, az azonositoja: 19331
van benne film, az azonositoja: 19694
van benne film, az azonositoja: 20042
van benne film, az azonositoja: 19152
van benne film, az azonositoja: 20064
van benne film, az azonositoja: 20063
van benne film, az azonositoja: 17772

Az eredmény előhozásához reguláris kifejezéseket használtunk. Dióhéjban annyit róluk, hogy a . az a joker karakter, a / jeleknek is van jelentése, ezért van előttük egy \, és a zárójelben lévő dolgok bekerülnek az eredmény tömbbe, méghozzá ha két zárójel van egymás után, akkor az az eredmény tömb két elemét fogja jelenteni. Nagyon hasznosak tudnak lenni, amikor mintákat keresünk egy dokumentumban.

A filmek adatainak kiderítése.

A film adatainak kiderítésére már magát az űrlapot fogjuk használni, méghozzá irunk egy szép függvényt rá, ami ha kap egy azonosítót, kiírja

  • A film magyar címét
  • A film eredeti (rendszerint angol) címét
  • A film bemutatóképének címét

Egy átlagos cinematrix-adatlap áttekintése után rájöhetünk:

  • A filmcímek <h1> jelek közé
  • Az angol címeket a szemantikus web jegyében a <span class=”engtlite”> jelzés fogja közre
  • A képek a http://img.index.hu/cmx2 könyvtárból származnak

Teljesen analóg módon írunk erre is egy mintaillesztőt. Az else jelzések nem lennének kötelezőek, de ha megszokjuk, hogy kirakjuk, sok problémától kíméljük meg magunkat az életben :) A programunk a következőképpen fog változni:


<?php
function adatok($cinematrix_id){
  
$file=fopen(‘http://index.hu/kultur/cinematrix/adatlap/’.$cinematrix_id.‘/’,‘r’);
  while (
$line=fgets($file)){
    if (
ereg(‘<h1>(.*)<\/h1>’,$line,$eredmeny)){
      echo 
‘A film cime: ’.$eredmeny[1].‘<br>’;
      } else if (
ereg(‘<span id=”engtitle”>(.*)<\/span>’,$line,$eredmeny)){
      echo 
‘A film angol cime: ’.$eredmeny[1].‘<br>’;
      } else if (
ereg(‘<img src=”(http…img.index.hu\/cmx2\/.*)” border=0′,$line,$eredmeny)) {
      echo 
‘A film kepe: <img src=”‘.$eredmeny[1].‘”><br>’;
      }
    }
  }
  
$file=fopen(‘http://index.hu/kultur/cinematrix/ccikkek/filmprev0830/’,‘r’);
  while (
$line=fgets($file)) { // ez soronkent elolvassa az oldalt, es az aktualis sort a $line sztringben tarolja
    
if (ereg(‘index.hu\/kultur\/cinematrix\/adatlap.([0-9]+)’,$line,$eredmeny)){
      echo 
‘van benne film, az azonositoja: ’.$eredmeny[1].‘<br/>’;
      
adatok($eredmeny[1]);
      } 
    }
?>


Ami végsősoron ilyet ad nekünk:

van benne film, az azonositoja: 20062
A film cime: Hajlakk
A film kepe:
van benne film, az azonositoja: 670
A film cime: Hajlakk
A film kepe:

A keresési találatokat jelenítsük meg a film mellett

Az angol cím alapján könnyen megtalálhatjuk a filmet bármelyik megfelelő keresőoldalon, azonban ahhoz, hogy az eredeti címet kezelni tudjuk, “valódi” függvényt kell írnunk, márpedig egy valódi függvény nem ír echo parancsokat, ha nem kérik.

Ehelyett a PHP egyik nyelvi technológiáját, az asszociatív tömböket fogjuk használni - tekintsük őket úgy, mint egy űrlap programozási megfelelőit. A módosított programunk így néz ki:


<?php
function adatok($cinematrix_id){
  
$file=fopen(‘http://index.hu/kultur/cinematrix/adatlap/’.$cinematrix_id.‘/’,‘r’);
  while (
$line=fgets($file)){
    if (
ereg(‘<h1>(.*)<\/h1>’,$line,$eredmeny)){
      
$film[‘cim’]=$eredmeny[1];
      } else if (
ereg(‘<span id=”engtitle”>(.*)<\/span>’,$line,$eredmeny)){
      
$film[‘angolcim’]=$eredmeny[1];
      } else if (
ereg(‘<img src=”(http…img.index.hu\/cmx2\/.*)” border=0′,$line,$eredmeny)) {
      
$film[‘kep’]=$eredmeny[1];
      }
    }
    return 
$film;
  }
  function 
adatokat_kiir($adatok){
  foreach(
$adatok as $mezo=>$ertek){
    switch(
$mezo){
      case 
“kep”:
        echo 
“kep: <img src=”.$ertek.“><br>”;
      break;
      default:
        echo 
$mezo.“:”.$ertek.“<br>”;
      }
    }
  }
  
$file=fopen(‘http://index.hu/kultur/cinematrix/ccikkek/filmprev0830/’,‘r’);
  while (
$line=fgets($file)) { // ez soronkent elolvassa az oldalt, es az aktualis sort a $line sztringben tarolja
    
if (ereg(‘index.hu\/kultur\/cinematrix\/adatlap.([0-9]+)’,$line,$eredmeny)){
      echo 
‘van benne film, az azonositoja: ’.$eredmeny[1].‘<br/>’;
      
adatokat_kiir(adatok($eredmeny[1]));
      } 
    }
?>


Az angol címet felhasználva mi egy népszerű torrent-oldal keresési oldalát fogjuk megjeleníteni a linkek mellett. Ezek címe is illeszkedik egy mintára, méghozzá a következőre

http://thepiratebay.org/search/Filmcím/0/7/200

Igen ám, de nem adhatunk át ékezeteket (francia cím pl.), vagy szóközöket, így a PHP urlencode() függvényét fogjuk használni.


function keresooldal_cime($angol_cim){
    return 
“http://thepiratebay.org/search/”.urlencode($angol_cim).“/0/7/200″;
  }

Amit meghívhatunk pl. így:

$film=adatok($eredmeny[1]);
adatokat_kiir($film);

echo '<a href="'.keresooldal_cime($film['angolcim']).'">Kereses</a><br&gy;';
}
}

Innen már csak mellé kell rakni a dolgokat.

Megoldás DOM-mal

A HTML- és XML-fájlokról a programoknak lehet több elképzelésük is egy mintafájlnál. A DOM a Dokumentum Objektum Model kifejezés rövidítése, és a számítógép HTML-fájlokról alkotott “elképzelését” jelöli. A W3C kitalált egy keresőnyelvet, az XPath -t, amit többek közt a JavaScript alkalmazások használnak a dokumentumok egyes részeinek megtalálására, és ez a DOM segítségével működik. Magyar segédlet is létezik több, többek közt ez vagy ez, mindenesetre röviden ez arra jó, hogy megtaláljunk egy HTML vagy XML fájlban bizonyos elemeket.

Így pl. a mi kis keresőmegoldásunk így néz ki XPath segítségével:


<?
function adatok_dom($cinematrix_id){
  
$url=‘http://index.hu/kultur/cinematrix/adatlap/’.$cinematrix_id.‘/’;
  
$doc = new DOMDocument();
  if (@
$doc->loadHTMLFile($url)){
    
$xpath = new DOMXPath($doc);
    
$film[‘cim’]=$xpath->query(‘//h1′)->item(0)->nodeValue;
    
$film[‘angolcim’]=$xpath->query(‘//span[@id=”engtitle”]’)->item(0)->nodeValue;
    
$film[‘kep’]=$xpath->query(‘//img[contains(@src,”cmx2″)]/@src’)->item(0)->nodeValue;

  return $film;
  } else return 
false;
}
?>


Ezzel már könnyebben boldogulunk egy találati oldal feldolgozásával is, ha az említett kalózkikötőt használjuk, megtehetjük így pl.:


<?
function fetchTPBList($url){
  
$doc = new DOMDocument();

  if (@$doc->loadHTMLFile($url)){
    
$xpath = new DOMXPath($doc);
    
$rows=$xpath->query(‘//table[@id=”searchResult”]/tr’);
    
$results=array();
    foreach (
$rows as $row){
     
$data[‘title’]=$xpath->query(‘td/a[@class=”detLink”]’,$row)->item(0)->nodeValue;
     
$data[‘details’]=$xpath->query(‘td/a[@class=”detLink”]/@href’,$row)->item(0)->nodeValue;
     
$data[‘download’]=$xpath->query(‘td/a/img[@class=”dl”]/../@href’,$row)->item(0)->nodeValue;
     
$results[]=$data;
    }
  return 
$results;
  } else return 
false;
}

A DOM-ot használva pedig megtehetjük azt is, hogy szerkesztjük a HTML-dokumentumot. Pl. ha betöltjük a DOM-ba a kritikát, akkor új elemeket vehetünk fel. Ezt inkább javascriptben szokás. Most csak a teljesen DOM/XPath-alapú feldolgozást mutatjuk:


<?php
require_once(“tpb.php”);

function adatok($cinematrix_id){
  
$file=fopen(‘http://index.hu/kultur/cinematrix/adatlap/’.$cinematrix_id.‘/’,‘r’);
  while (
$line=fgets($file)){
    if (
ereg(‘<h1>(.*)<\/h1>’,$line,$eredmeny)){
      
$film[‘cim’]=$eredmeny[1];
      } else if (
ereg(‘<span id=”engtitle”>(.*)<\/span>’,$line,$eredmeny)){
      
$film[‘angolcim’]=$eredmeny[1];
      } else if (
ereg(‘<img src=”(http…img.index.hu\/cmx2\/.*)” border=0′,$line,$eredmeny)) {
      
$film[‘kep’]=$eredmeny[1];
      }
    }
    return 
$film;
  }
function 
adatok_dom($cinematrix_id){
  
$url=‘http://index.hu/kultur/cinematrix/adatlap/’.$cinematrix_id.‘/’;
  
$doc = new DOMDocument();
  if (@
$doc->loadHTMLFile($url)){
    
$xpath = new DOMXPath($doc);
    
$film[‘cim’]=$xpath->query(‘//h1′)->item(0)->nodeValue;
    
$film[‘angolcim’]=$xpath->query(‘//span[@id=”engtitle”]’)->item(0)->nodeValue;
    
$film[‘kep’]=$xpath->query(‘//img[contains(@src,”cmx2″)]/@src’)->item(0)->nodeValue;

  return $film;
  } else return 
false;
}
function 
adatokat_kiir($adatok){
  
$out=“”;
  foreach(
$adatok as $mezo=>$ertek){
    switch(
$mezo){
      case 
“kep”:
        
$out.= “kep: <img src=”.$ertek.“><br>”;
      break;
      default:
        
$out.= $mezo.“:”.$ertek.“<br>”;
      }
    }
    echo 
$out;
  }
function 
keresooldal_cime($angol_cim){
    return 
“http://thepiratebay.org/search/”.urlencode($angol_cim).“/0/7/200″;
  }

  $url=‘http://index.hu/kultur/cinematrix/ccikkek/filmprev0830/’;
  
header(‘Content-Type: text/html; charset=utf-8′);
  
$doc = new DOMDocument();
  if (@
$doc->loadHTMLFile($url)){
    
$xpath = new DOMXPath($doc);
    
$links=$xpath->query(‘//a[contains(@href,”adatlap”)]/@href’);
 
//   $content=$xpath->query(’//div[@id=”content”]’)->item(0);
    
foreach($links as $link){
      
ereg(‘adatlap.([0-9]+)’,$link->nodeValue,$eredmeny);
      
$azonosito=$eredmeny[1];
      
$film=adatok_dom($azonosito);
      
adatokat_kiir($film);
      
listTPB(keresooldal_cime($film[‘angolcim’]));
    }
  }
?>


ahol a tpb.php fájl tartalma:


<?
function fetchTPBList($url){
  
$doc = new DOMDocument();

  if (@$doc->loadHTMLFile($url)){
    
$xpath = new DOMXPath($doc);
    
$rows=$xpath->query(‘//table[@id=”searchResult”]/tr’);
    
$results=array();
    foreach (
$rows as $row){
     
$data[‘title’]=$xpath->query(‘td/a[@class=”detLink”]’,$row)->item(0)->nodeValue;
     
$data[‘details’]=$xpath->query(‘td/a[@class=”detLink”]/@href’,$row)->item(0)->nodeValue;
     
$data[‘download’]=$xpath->query(‘td/a/img[@class=”dl”]/../@href’,$row)->item(0)->nodeValue;
     
$results[]=$data;
    }
  return 
$results;
  } else return 
false;
}
function 
listTPB($url){
    
$results=fetchTPBList($url);
    foreach(
$results as $result){
      foreach(
$result as $key=>$value){
        switch(
$key){
        case 
‘details’:
          
$rkey=$key;
          
$rvalue=‘http://thepiratebay.org’.$value;
          
$rvalue=‘<a href=”‘.$rvalue.‘”>’.$rvalue.‘</a>’;
        break;
        case 
‘download’:
          
$rkey=$key;
          
$rvalue=‘<a href=”‘.$value.‘”>’.$value.‘</a>’;
        break;
        default:
          
$rkey=$key;
          
$rvalue=$value;
        }
      echo 
“<b class=\”download_”.$key.“\” style=\”color:grey;\”>”.$rkey.“:</b> ”.$rvalue.“<br/>”;
      }
      echo 
“<br/>”;
    }
  }


Ezekből a példákból talán jól látszik, milyen szépen lehet két oldalt csupán az azonosítók alapján összekötni (ez a “mikroformátum” lényege). A filozófia mögötte az, hogyha valami adatbázis, akkor használjuk is adatbázisnak, ne nekünk kelljen két adathalmaz kapcsolását kézzel (linkre rákattint, angol címet kimásol, angol címet megfelelő keresőbe beilleszt, fájlt letölt).

Teljesen analóg módon lehet Youtube-videókat keresni egy adott anyaghoz, vagy ha valahol szerepel a youtube-ra egy link, akkor ahelyett a videót berakni (mint teszi azt a Google Talk Gadget, vagy a Meebo), esetleg térképen ábrázolni egy pontot, aminek csak a címe van feltüntetve. Mindez nem jelentős probléma, ha be vannak jelölve az oldalak szemantikailag.

Amennyiben nincsenek, állapotgépet kell építeni, ami a feladat komplexitását jelentősen megnöveli, vagy bizonytalan kimenetelű XPath-kifejezésekkel kell dolgoznunk, esetleg megoldhatatlanná is válhat.

Ami nagyon hiányzik még, az a JavaScript-megoldás. Talán legközelebb :)