Goutte - Web Crawler на PHP (паук)
Goutte - отличный инструмент для автоматизации серфинга по Web страницам из консоли или скрипта. Этот кроулер используется для автоматизации тестирования в таких PHP фреймворках, как Symfony 2 и Laravel 4. Он позволяет искать DOM элементы на странице, заполнять поля формы и отправлять форму, следовать по редиректу и изменять контент Web страницы. Goutte не выполняет JavaScript! Если вам это нужно - смотрите в сторону Selenium Web Driver, ZombieJS и прочих движков.
Документация:
Внимание!
Если внутри формы встречается следующая разметка, то Goutte не получает поля формы после тега input:
<script type="text/html">
<input type="text" name="field"/>
<div></div>
</script>
Если заменить script на div, или убрать вложенный div - все будет работать. Но все это явный баг.
Создал тикет: https://github.com/fabpot/Goutte/issues/155
Траверсинг
Получить DOM элемент содержащий текст:
$crawler->filter('h1:contains("Hello World!")')
Отфильтровать или изменить набор DOM узлов:
$templates = $crawler->filter('script[type="text/html"]');
$crawler = $templates->reduce(function (\Symfony\Component\DomCrawler\Crawler $node, $i) {
$node->getNode(0)->setAttribute('class', 'some-class');
return false; // false - исключить элемент из новой коллекции
});
Получить кнопку с текстом "Назад" и нажать на нее:
$link = $crawler->selectLink('Назад');
$this->assertCount(1, $link, 'На странице нет кнопки "Назад"');
$this->client->click($link->link());
Куки
Получить куки:
$cookieJar = $this->client->getCookieJar();
* Почему в getCookieJar() не возвращает куки SESSION_ID, laravel_session?
Пример теста с отправкой формы
// $btn = $form->selectLink('Добавить настройку'); // не работает
$url = URL::route('route_name', $id);
$crawler = $this->client->request('GET', $url);
// OR:
//$this->call('GET', $url);
//$crawler = $this->client->getCrawler();
$this->assertResponseOk();
// Проверить, что в шаблон передана переменная
$this->assertViewHas('sale_location');
$form_node = $crawler->filter('#id-name');
$this->assertCount(1, $form_node, 'На странице нет формы редактирования магазина');
$form = $form_node->form();
// filter() всегда возвращает объект
$btn = $form_node->filter('.class-name');
$this->assertCount(1, $btn, 'Нет кнопки "Добавить настройку"');
/** @var \Symfony\Component\DomCrawler\Field\ChoiceFormField $select */
$form['settings[type_id][0]']->select(1); // select option only by value
/** @var \Symfony\Component\DomCrawler\Field\ChoiceFormField $textarea */
$textarea = $form['settings[value][0]'];
$this->assertEquals('agnitas 123', $textarea->getValue());
$textarea->setValue('TEST');
// Set Form Data
$form->setValues(array(
'settings[type_id][0]' => 1,
'settings[value][0]' => 'Some text',
));
$save_url = $form->getUri();
$method = $form->getMethod();
$values = $form->getValues();
$this->client->submit($form);
$crawler = $this->client->followRedirect(true);
$info = $crawler->filter('div.alert.alert-success');
$this->assertCount(1, $info, "Нет блока с сообщением об успешном сохранении");
// Check saved values
$crawler = $this->client->request('GET', $url);
$form_node = $crawler->filter('#sale_locations_form');
$field = $form_node->form()['settings[value][0]'];
$this->assertEquals('TEST', $field->getValue());
#goutte, #tdd, #crawler, #scraper, #traversing