Symfony: tutorial 14: navegando con DomCrawler, BrowserKit y CssSelector

Navegando por páginas web con Symfony..

Hoy les traigo otro tutorial sobre Symfony 4 y Symfony Flex. Siguiendo con la puesta al día que llevo con Symfony 4, hoy llego a cómo navegar por las páginas web. Es decir, los fundamentos de cómo utilizar el DomCrawler, el BrowserKit y el CssSelector de Symfony.

Esto puede servir para dos cosas. La primera utilidad es para comprobar que el proyecto en el que estamos trabajando funciona como debe hacer. Podemos automatizar pruebas funcionales navegando por el proyecto, comprobando que los resultados son los esperados, mientras que desarrollamos y antes de que llegue a producción ningún fallo. La segunda utilidad es para navegar por páginas web remotas que estén en servidores remotos, no en local. Quizá necesitamos hacer comprobaciones en producción, o puede que necesitemos obtener contenidos, información relevante, o ficheros remotos alojados en páginas web mediante el protocolo HTTP que necesitemos recoger por alguna razón. És decir, la segunda utilidad es para conectar tu proyecto con sistemas informaticos remotos mediante el protocolo HTTP.

Un poco de teoría, cómo se navega

La navegación HTTP ocurre en la capa de aplicación, con lo que Symfony te abstrae de todo para darte una forma sencilla de consultar páginas web. Una vez que tienes una respuesta se puede escudriñar en los resultados, en el DOM devuelto, viendo las etiquetas HTML, CSS, etc.. También se pueden consultar cookies, rellenar formularios, hacer logins, etc..

Se puede hacer prácticamente todo lo que un navegador como Chrome o Firefox puede hacer consultando páginas web a un servidor. Sólo hay que saber inspeccionar las páginas web para luego simular esta navegación programándola en Symfony.

Me remito a los conceptos básicos de XML y del DOM, porque todo esto se basa y se ayuda de esos conceptos para funcionar y simplificarnos la vida.

Al grano, creando el proyecto de pruebas

Para este post, sólo hace falta un proyecto con un comando de consola y así se vé todo fácil. Es más fácil ver el código que explicarlo ahora. Así que ejecutando desde línea de comandos:

composer create-project symfony/skeleton symfony-testing-browsing
cd symfony-testing-browsing/
composer require symfony/browser-kit symfony/dom-crawler symfony/css-selector fabpot/goutte
composer require --dev symfony/maker-bundle

Con ésto ya tenemos el proyecto listo para programar. Ahora creamos un comando de consola:

php bin/console make:command

Le he llamado app:testing-browsing, así ejecutando lo siguiente hago pruebas viendo los resultados:

php bin/console app:testing-browsing

Lo siguiente es el código fuente del comando que está en el fichero src/Command/TestingBrowsingCommand.php:

<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
//use Symfony\Component\BrowserKit\Client;
use Goutte\Client;

class TestingBrowsingCommand extends Command
{
    protected static $defaultName = 'app:testing-browsing';

    protected function configure()
    {
        $this
            ->setDescription('Este comando es una prueba del navegador de Symfony.')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        $client = new Client();
        //$crawler = $client->xmlHttpRequest('GET', 'https://jnjsite.com/');
        $crawler = $client->request('GET', 'https://jnjsite.com/');

        //var_dump($client);
        $output->writeln('============>> ESTO ES TODO EL CONTENIDO DE LA WEB: ');
        $output->writeln($crawler->html());

        $output->writeln('============>> AHORA SÓLO LOS ENLACES: ');
        foreach ($crawler->filter('a') as $linkNode) {
            //var_dump($linkNode);
            /*foreach ($linkNode->attributes as $key => $value) {
                if($key == 'href') {
                    var_dump($key);
                    var_dump($value);
                }
            }*/
            if (isset($linkNode->attributes['href'])) {
                $output->writeln($linkNode->nodeValue.': '.$linkNode->attributes['href']->value);
            }
        }

        $io->success('¡Este comando ha terminado con éxito!');
    }
}

He tratado de complementarlo con el caso base de la documentación oficial. Date cuenta que incluí el componente Goutte, se podría haber hecho con otro componente pero así queda hecho en menos líneas de código y funciona muy bien.

Aclaraciones, explicaciones

Lo que hace el código del comando anterior es navegar por la página de inicio de https://jnjsite.com/ simplemente imprimiendo todo el contenido HTML. Luego, haciendo unas pocas pruebas con el DOM que tenemos guardado como respuesta en el $crawler, he llegado a listar todos los enlaces viendo de cada uno dos cosas: el texto del enlace, y el valor del atributo href.

Una línea de código importante comprender es la de la petición:

$crawler = $client->request('GET', 'https://jnjsite.com/');

..que lo que hace es pedir la página al servidor y convertir la respuesta en un objeto DomCrawler. Esto es un gran paso. Que luego complementándolo con el concepto de filtrado de nodos del DOM usando selectores CSS nos agilizaremos más todavía. Por ejemplo, la siguiente instrucción importante es:

foreach ($crawler->filter('a') as $linkNode) {

Podemos hacer estos filtrados porque hemos incluido el componente symfony/css-selector en el proyecto. Con esto que podríamos obtener por ejemplo todas las imágenes de la página usando:

foreach ($crawler->filter('img') as $linkNode) {

..o todos los items del menú de navegación así:

foreach ($crawler->filter('li.menu-item') as $linkNode) {

..dependiendo de cada proyecto habrá que filtrar con un selector CSS o con otro.

Terminando

Si ejecutamos el código del ejemplo y todo ha ido bien, se debería de ver por pantalla algo parecido a esto:

Crawleando home de una página, listando los enlaces, texto y URL de enlace..

Sólo me queda remitirme a la documentación oficial para el que necesite más sobre algúna funcionalidad en concreto:
https://symfony.com/doc/current/components/browser_kit.html

Compartir..

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *