Cada vez que haces una petición, el cliente devuelve una instancia del Crawler
. Este objeto permite recorrer documentos HTML, seleccionar nodos, encontrar enlaces y formularios.
10.5.1. Recorriendo documentos HTML y XML
Al igual que jQuery, el Crawler
tiene métodos para recorrer el DOM de un documento HTML/XML. El siguiente código por ejemplo encuentra todos los elementos input[type=submit]
, selecciona el último en la página, y luego selecciona su elemento padre :
$newCrawler = $crawler->filter('input[type=submit]')
->last()
->parents()
->first()
;
Este objeto dispone de muchos otros métodos:
Método | Descripción |
---|---|
filter('h1.title') |
Nodos que coinciden con el selector CSS indicado |
filterXpath('h1') |
Nodos que coinciden con la expresión XPath indicada |
eq(1) |
Nodo correspondiente al índice especificado |
first() |
El primer nodo |
last() |
El último nodo |
siblings() |
Los nodos hermanos del nodo seleccionado |
nextAll() |
Los nodos hermanos siguientes |
previousAll() |
Los nodos hermanos anteriores |
parents() |
Los nodos padre del nodo seleccionado |
children() |
Los nodos hijo del nodo seleccionado |
reduce($lambda) |
Devuelve los nodos para los que la función anónima $lambda no devuelve false |
Como cada uno de estos métodos devuelve una nueva instancia del Crawler
, puedes seleccionar nodos encadenando varios métodos:
$crawler
->filter('h1')
->reduce(function ($node, $i)
{
if (!$node->getAttribute('class')) {
return false;
}
})
->first();
Truco Puedes utilizar la función count()
para obtener el número de nodos almacenados en un Crawler
: count($crawler)
10.5.2. Extrayendo información
El Crawler
también puede extraer información de los nodos:
// Devuelve el valor del atributo del primer nodo
$crawler->attr('class');
// Devuelve el valor del nodo para el primer nodo
$crawler->text();
// Extrae un array de atributos de todos los nodos
// (_text devuelve el valor del nodo)
// devuelve un array de cada elemento en 'crawler',
// cada uno con su valor y href
$info = $crawler->extract(array('_text', 'href'));
// Ejecuta una función anónima por cada nodo y
// devuelve un array de resultados
$data = $crawler->each(function ($node, $i)
{
return $node->attr('href');
});
10.5.3. Enlaces
Para seleccionar enlaces, puedes usar los métodos anteriores para recorrer el código HTML de la página o mejor utilizar el atajo selectLink()
:
$crawler->selectLink('Click here');
Este método selecciona todos los enlaces que contienen el texto indicado o todas las imágenes pinchables cuyo atributo alt
contiene el texto indicado. Al igual que los otros métodos de filtrado, también devuelve un objeto Crawler
.
Una vez seleccionado un enlace, puedes acceder a un objeto especial de tipo Link
que contiene métodos útiles y específicos para enlaces (tales como getMethod()
y getUri()
). Para pinchar el enlace, usa el método click()
del cliente y pásale un objeto Link
:
$link = $crawler->selectLink('Click here')->link();
$client->click($link);
10.5.4. Formularios
Al igual que sucede con los enlaces, existe un método para seleccionar directamente los formularios:
$buttonCrawlerNode = $crawler->selectButton('submit');
Nota Observa que el código anterior selecciona un botón de formulario y no el propio formulario. Esto es especialmente importante porque los formularios pueden contener varios botones y debes tenerlo en cuenta al recorrer el contenido de la página.
El método selectButton()
puede seleccionar etiquetas <button>
y etiquetas <input>
de envío de formularios. Para encontrar estos últimos botones, utiliza diferentes estrategias:
- El valor del atributo
value
del botón. - El valor del atributo
id
oalt
de botones creados con imágenes. - El valor del atributo
id
oname
de las etiquetas<button>
.
Una vez que tienes un Crawler
que representa un botón, utiliza el método form()
para obtener el formulario que contiene a ese botón. El resultado que obtienes es una instancia de la clase Form
:
$form = $buttonCrawlerNode->form();
Cuando utilizas el método form()
, también puedes pasar un array de valores para reemplazar a los valores originales del formulario:
$form = $buttonCrawlerNode->form(array(
'name' => 'Fabien',
'my_form[subject]' => 'Symfony rocks!',
));
Y si quieres simular un método HTTP específico para el formulario, pásalo como segundo argumento:
$form = $buttonCrawlerNode->form(array(), 'DELETE');
Por último, envía el formulario pasando el objeto Form
al cliente con el que realizas las peticiones:
$client->submit($form);
El formulario también se puede rellenar pasando un array de valores como segundo parámetro del método submit()
:
$client->submit($form, array(
'name' => 'Fabien',
'my_form[subject]' => 'Symfony rocks!',
));
Para tests más complejos, utiliza la instancia de Form
como un array para establecer el valor de cada campo individualmente:
// Cambia el valor de un campo
$form['name'] = 'Fabien';
$form['my_form[subject]'] = 'Symfony rocks!';
También existe una API bastante completa para manipular los valores de los campos de acuerdo a su tipo:
// selecciona una opción o radiobutton
$form['country']->select('France');
// marca una casilla de verificación (checkbox)
$form['like_symfony']->tick();
// carga un archivo
$form['photo']->upload('/ruta/a/lucas.jpg');
Truco Puedes utilizar el método getValues()
del objeto Form
para acceder a los valores que contiene el formulario que se va a enviar. Los archivos subidos están disponibles en un array separado devuelto por getFiles()
. Los métodos getPhpValues()
y getPhpFiles()
también devuelven los valores enviados, pero en "formato PHP" (transforma las claves con corchetes como my_form[subject]
a valores normales de un array PHP).