Kontynuujemy poznawanie OOP w PHP. Tym razem klasa Parser, która otwiera, pobiera i parsuje zawartość strony internetowej. Poznajemy pola prywatne oraz kompozycję – czyli instancję innej klasy jako pole klasy. Do dzieła.
Rzecz pierwsza, czyli nasza klasa i konstruktor:
<?php
class DomDocumentParser {
private $doc;
public function __construct($url) {
$options = array(
'http'=>array('method'=>"GET", 'header'=>"User-Agent: scraperBot/0.1\n")
);
$context = stream_context_create($options);
$this->doc = new DomDocument();
@$this->doc->loadHTML(file_get_contents($url, false, $context));
}
}
Doc jest prywatny, czyli tylko wewnątrz klasy możemy się nim bawić metodami. Samego doc „po strzałce” na obiekcie wykonać nie możemy i się do niego dostać.
Kompozycja to przedostatnia linijka konstruktora, gdzie jako pole klasy przypisujemy obiekt innej klasy, tutaj wbudowanej w PHP klasy DomDocument.
Ładujemy HTML z urla (zakładam, że mamy allow_url_fopen w php.ini) i robimy to pod error supressor operator, czyli „@”, zatem błędy nas nie interesują.
Teraz metoda getTags i getById:
<?php
class DomDocumentParser {
private $doc;
/(...)
public function getTags($tag) {
return $this->doc->getElementsByTagName($tag);
}
public function getById($elem_id){
return $this->doc->getElementById($elem_id);
}
}
Doc jest prywatny, więc metody wewnątrz klasy mogą się nim bawić, metody publiczne, a zatem w ten sposób tworzymy interfejs dla użytkownika końcowego, który będzie obsługiwać obiekt naszej klasy.
Doc jest sam w sobie obiektem innej klasy (kompozycja) i posiada własne metody (getElementsByTagName, getElementById).
Robimy z tych dwóch rzeczy użytek. Teraz funkcja showTags:
<?php
class DomDocumentParser {
private $doc;
//(...)
public function getTags($tag) {
return $this->doc->getElementsByTagName($tag);
}
public function showTags($tag){
$iter = $this->getTags($tag)->getIterator();
foreach($iter as $element){
echo $element->textContent;
echo "</br>";
}
}
public function getById($elem_id){
return $this->doc->getElementById($elem_id);
}
}
$parser = new DomDocumentParser("https://www.scrapethissite.com/pages/simple/");
$parser->showTags("h3");
Od razu z przykładem do użycia. getTags zwraca klasę, która ma funkcję getIterator. Po tym iteratorze możemy przejść wyświetlając każdy element, a w zasadzie jego textContent.
Dokładnie to robimy. Łączymy się ze stroną do scrapowania, pobieramy jej HTML, łapiemy tagi h3 i wyświetlamy.
Teraz kolejna metoda:
class DomDocumentParser {
private $doc;
//(...)
public function getTagsWithClass($tag, $class){
$tags = $this->doc->getElementsByTagName($tag)->getIterator();
$tagsWithClass = array();
foreach($tags as $tag){
if(stripos($tag->getAttribute('class'), $class) !== false){
$tagsWithClass[] = $tag;
}
}
return $tagsWithClass;
}
//(...)
}
$parser = new DomDocumentParser("https://www.scrapethissite.com/pages/simple/");
$iter = $parser->getTagsWithClass("div", "container");
print_r($iter[0]->textContent);
Pobieramy elementy z doc po tagu i łapiemy iterator. Iterujemy dodając do output array tylko te, które zawierają szukaną przez nas klasę. Zwracamy tablicę.
Teraz możemy tam sobie wejść i złapać element div o klasie container i wyświetlić jego textContent.
Dodam, że tutaj lepiej by się sprawdził XPath, ale nie wszystko od razu. Temat będziemy kontynuować.