Pesquisando HTML de maneira fácil

Por Jean Hertel, 21/03/2017

symfony , silex , domcrawler , xpath , cssselector

Você certamente já teve que pegar algum HTML e buscar algum conteúdo dentro dele com PHP. Sempre que você precisa fazer isso, a solução mais comum é usar regex e funções como strpos. Alguns desenvolvedores tentam manter o código limpo utilizando classes como o DomDocument, mas acabam tendo que voltar para as expressões regulares por causa de HTML mal formado. Outros tentam se aventurar no mundo do XPath, mas acabam enfrentando as mesmas dificuldades das expressões regulares.

Felizmente existe uma solução muito melhor e simples, o componente DomCrawler do Symfony. Este componente lhe permite atravessar fácilmente o HTML, buscando outros elementos ou texto. Caso o seu HTML seja mal formado, ele irá fazer todo o possível para corrigir o HTML e permite que você busque nele. Para deixar tudo ainda melhor, é possível utilizar o componente CSSSelector que permite escrever seletores CSS e transformá-los em querys XPath.

Vamos ver um exemplo em ação.

<?php
require "vendor/autoload.php";

use Symfony\Component\DomCrawler\Crawler;

$html = <<<'HTML'
<!DOCTYPE html>
<html>
    <body>
        <p class="message">Hello World!</p>
        <p>Hello Crawler!</p>
        <div>
            <span>Hellouuww</span>
            <span customAttribute="monster">Not too quick!</span>
            <p id="ninja">A ninja paragraph!</p>
        </div>
    </body>
</html>
HTML;

/* Cria o crawler */
$crawler = new Crawler($html);

/* Busca através do ID ninja */
$subCrawler = $crawler->filter('#ninja');

foreach($subCrawler as $domElement) {
    var_dump($domElement->nodeName);
    var_dump($domElement->nodeValue);
}

$subCrawler2 = $crawler->filter('body > p');

foreach($subCrawler2 as $domElement) {
    var_dump($domElement->nodeValue);
}

Note que as consultas são bem simples utilizando os seletores CSS. Assim como na biblioteca jQuery, sempre que você fizer uma consulta, um array vai ser retornado.

Existem diversos métodos úteis, como children, parent, first, last, siblings, etc. O bacana aqui é que a maioria dos desenvolvedores php já teve contato com o jQuery, e portanto, os métodos vão parecer muito familiares.

Para finalizar, vamos pegar o valor de uma classe que muda dinamicamente no segundo span.

<?php
require "vendor/autoload.php";

use Symfony\Component\DomCrawler\Crawler;

$html = <<<'HTML'
<!DOCTYPE html>
<html>
    <body>
        <p class="message">Hello World!</p>
        <p>Hello Crawler!</p>
        <div>
            <span>Hellouuww</span>
            <span class="monster">Not too quick!</span>
            <p id="ninja">A ninja paragraph!</p>
        </div>
    </body>
</html>
HTML;

$crawler = new Crawler($html);

$unknowClass = $crawler->filter('span')->last()->attr('class');

var_dump($unknowClass);

Caso você saiba utilizar XPath corretamente, você pode usar o método filterXPath diretamente, evitando o overhead de traduzir o seletor CSS para XPath.