Table of Contents
Questions & Feedback
Found a typo or an error?
Want to improve this document? Edit it.
Need support or have a technical question?
Post to the user mailing-list.
Master Symfony2 fundamentals
Symfony hosting done right
Discover the SensioLabs Support
Il componente DomCrawler
Il componente DomCrawler¶
Il componente DomCrawler semplifica la navigazione nel DOM dei documenti HTML e XML.
Note
Dove possibile, il componente DomCrawler non è progettato per manipolare il DOM o per ri-esportare HTML/XML.
Installazione¶
È possibile installare il componente in diversi modi:
- Utilizzando il repository ufficiale su Git (https://github.com/symfony/DomCrawler);
- Installandolo via Composer (
symfony/dom-crawlersu Packagist).
Utilizzo¶
La classe Crawler mette a disposizione metodi
per effettuare query e manipolare i documenti HTML e XML.
Un'istanza di Crawler rappresenta un insieme (SplObjectStorage) di
oggetti DOMElement, che sono, in pratica, nodi facilmente
visitabili:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use Symfony\Component\DomCrawler\Crawler;
$html = <<<'HTML'
<!DOCTYPE html>
<html>
<body>
<p class="messaggio">Ciao Mondo!</p>
<p>Ciao Crawler!</p>
</body>
</html>
HTML;
$crawler = new Crawler($html);
foreach ($crawler as $elementoDom) {
print $elementoDom->nodeName;
}
|
Le classi specializzate Link e
Form sono utili per interagire con
collegamenti html e i form durante la visita dell'albero HTML.
Filtrare i nodi¶
È possibile usare facilmente le espressioni di XPath:
1 | $crawler = $crawler->filterXPath('descendant-or-self::body/p');
|
Tip
internamente viene usato DOMXPath::query per eseguire le query XPath.
La ricerca è anche più semplice se si è installato il componente CssSelector.
In questo modo è possibile usare lo stile jQuery per l'attraversamento:
1 | $crawler = $crawler->filter('body > p');
|
È possibile usare funzioni anonime per eseguire filtri complessi:
1 2 3 4 | $crawler = $crawler->filter('body > p')->reduce(function ($node, $i) {
// filtra anche i nodi
return ($i % 2) == 0;
});
|
Per rimuovere i nodi, la funzione anonima dovrà restituire false.
Note
Tutti i metodi dei filtri restituiscono una nuova istanza di Crawler
contenente gli elementi filtrati.
Attraversamento dei nodi¶
Accedere ai nodi tramite la loro posizione nella lista:
1 | $crawler->filter('body > p')->eq(0);
|
Ottenere il primo o l'ultimo nodo della selezione:
1 2 | $crawler->filter('body > p')->first();
$crawler->filter('body > p')->last();
|
Ottenere i nodi allo stesso livello della selezione attuale:
1 | $crawler->filter('body > p')->siblings();
|
Ottenere i nodi, allo stesso livello, precedenti o successivi alla selezione attuale:
1 2 | $crawler->filter('body > p')->nextAll();
$crawler->filter('body > p')->previousAll();
|
Ottenere tutti i nodi figlio o padre:
1 2 | $crawler->filter('body')->children();
$crawler->filter('body > p')->parents();
|
Note
Tutti i metodi di attraversamento restituiscono un nuova istanza di
Crawler.
Accedere ai nodi tramite il loro valore¶
Accedere al valore del primo nodo della selezione attuale:
1 | $message = $crawler->filterXPath('//body/p')->text();
|
Accedere al valore dell'attributo del primo nodo della selezione attuale:
1 | $class = $crawler->filterXPath('//body/p')->attr('class');
|
Estrarre l'attributo e/o il valore di un nodo da una lista di nodi:
1 2 3 4 | $attributes = $crawler
->filterXpath('//body/p')
->extract(array('_text', 'class'))
;
|
Note
L'attributo speciale _text rappresenta il valore di un nodo.
Chiamare una funzione anonima su ogni nodo della lista:
1 2 3 | $nodeValues = $crawler->filter('p')->each(function ($nodo, $i) {
return $nodo->nodeValue;
});
|
La funzione anonima riceve la posizione e il nodo come argomenti. Il risultato è un array contenente i valori restituiti dalle chiamate alla funzione anonima.
Aggiungere contenuti¶
Il crawler supporta diversi modi per aggiungere contenuti:
1 2 3 4 5 6 7 8 9 10 | $crawler = new Crawler('<html><body /></html>');
$crawler->addHtmlContent('<html><body /></html>');
$crawler->addXmlContent('<root><node /></root>');
$crawler->addContent('<html><body /></html>');
$crawler->addContent('<root><node /></root>', 'text/xml');
$crawler->add('<html><body /></html>');
$crawler->add('<root><node /></root>');
|
Essendo l'implementazione del Crawler basata sull'estensione di DOM, è anche
possibile interagire con le classi native DOMDocument, DOMNodeList
e DOMNode:
1 2 3 4 5 6 7 8 9 10 | $documento = new \DOMDocument();
$documento->loadXml('<root><node /><node /></root>');
$listaNodi = $documento->getElementsByTagName('node');
$nodo = $documento->getElementsByTagName('node')->item(0);
$crawler->addDocument($documento);
$crawler->addNodeList($listaNodi);
$crawler->addNodes(array($nodo));
$crawler->addNode($nodo);
$crawler->add($documento);
|
Supporto per i collegamenti e per i form¶
Per i collegamenti e i form, contenuti nell'albero DOM, è riservato un trattamento speciale.
Collegamenti¶
Per trovare un collegamento tramite il suo nome (o un'immagine cliccabile tramite il suo
attributo alt) si usa il metodo selectLink in un crawler esistente. La chiamata
restituisce un'istanza di Crawler contenente il/i solo/i collegamento/i selezionato/i. La chiamata link()
restituisce l'oggetto speciale Link:
1 2 3 4 5 | $linksCrawler = $crawler->selectLink('Vai altrove...');
$link = $linksCrawler->link();
// oppure, in una sola riga
$link = $crawler->selectLink('Vai altrove...')->link();
|
L'oggetto Link ha diversi utili metodi per
avere ulteriori informazioni relative al collegamento selezionato:
1 2 | // restituisce la URI che può essere utilizzata per effettuare nuove richieste
$uri = $link->getUri();
|
Note
Il metodo getUri() è specialmente utile perché pulisce il valore di href e
lo trasforma nel modo in cui dovrebbe realmente essere processato. Ad esempio, un collegamento
del tipo href="#foo" restituirà l'URI completo della pagina corrente
con il suffisso #foo. Il valore restituito da getUri() è sempre un URI completo,
sul quale è possibile lavorare.
I Form¶
Un trattamento speciale è riservato anche ai form. È disponibile, in Crawler,
un metodo selectButton() che restituisce un altro Crawler relativo
al pulsante (input[type=submit], input[type=image], o button) con
il testo dato. Questo metodo è specialmente utile perché può essere usato per restituire
un oggetto Form, che rappresenta
il form all'interno del quale il pulsante è definito:
1 2 3 4 5 6 | $form = $crawler->selectButton('Valida')->form();
// o "riempie" i campi del form con dati
$form = $crawler->selectButton('Valida')->form(array(
'nome' => 'Ryan',
));
|
L'oggetto Form ha molti utilissimi
metodi che permettono di lavorare con i form:
$uri = $form->getUri();
$metodo = $form->getMethod();
Il metodo getUri() fa più che
restituire il mero attributo action del form. Se il metodo del form è
GET, allora, imitando il comportamento del browser, restituirà l'attributo
dell'azione seguito da una stringa di tutti i valori del form.
È possibile impostare e leggere virtualmente i valori nel form:
1 2 3 4 5 6 7 8 9 10 11 12 | // imposta, internamente, i valori del form
$form->setValues(array(
'registrazione[nomeutente]' => 'fandisymfony',
'registrazione[termini]' => 1,
));
// restituisce un array di valori in un array "semplice", come in precedenza
$values = $form->getValues();
// restituisce i valori come li vedrebbe PHP
// con "registrazione" come array
$values = $form->getPhpValues();
|
Per lavorare con i campi multi-dimensionali:
1 2 3 4 5 | <form>
<input name="multi[]" />
<input name="multi[]" />
<input name="multi[dimensionale]" />
</form>
|
È necessario specificare il nome pienamente qualificato del campo:
1 2 3 4 5 6 7 8 | // Imposta un singolo campo
$form->setValue('multi[0]', 'valore');
// Imposta molteplici campi in una sola volta
$form->setValue('multi', array(
1 => 'valore',
'dimensionale' => 'un altro valore'
));
|
Se questo è fantastico, il resto è anche meglio! L'oggetto Form permette di
interagire con il form come se si usasse il browser, selezionando i valori dei radio,
spuntando i checkbox e caricando file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $form['registrazione[nomeutente]']->setValue('fandisymfony');
// cambia segno di spunta a un checkbox
$form['registrazione[termini]']->tick();
$form['registrazione[termini]']->untick();
// seleziona un'opzione
$form['registrazione[data_nascita][anno]']->select(1984);
// seleziona diverse opzioni da una lista di opzioni o da una serie di checkbox
$form['registrazione[interessi]']->select(array('symfony', 'biscotti'));
// può anche imitare l'upload di un file
$form['registrazione[foto]']->upload('/percorso/al/file/lucas.jpg');
|
A cosa serve tutto questo? Se si stanno eseguendo i test interni, è possibile recuperare informazioni da tutti i form esattamente come se fossero stati inviati utilizzando i valori PHP:
1 2 | $valori = $form->getPhpValues();
$files = $form->getPhpFiles();
|
Se si utilizza un client HTTP esterno, è possibile usare il form per recuperare tutte le informazioni necessarie per create una richiesta POST dal form:
1 2 3 4 5 6 | $uri = $form->getUri();
$metodo = $form->getMethod();
$valori = $form->getValues();
$files = $form->getFiles();
// a questo punto si usa un qualche client HTTP e si inviano le informazioni
|
Un ottimo esempio di sistema integrato che utilizza tutte queste funzioni è Goutte. Goutte usa a pieno gli oggetti del Crawler di Symfony e, con essi, può inviare i form direttamente:
1 2 3 4 5 6 7 8 9 10 11 12 13 | use Goutte\Client;
// crea una richiesta a un sito esterno
$client = new Client();
$crawler = $client->request('GET', 'https://github.com/login');
// seleziona il form e riempie alcuni valori
$form = $crawler->selectButton('Log in')->form();
$form['login'] = 'fandisymfony';
$form['password'] = 'unapassword';
// invia il form
$crawler = $client->submit($form);
|





is a trademark of Fabien Potencier. All rights reserved.