Back-End

23 ago, 2017

Desenvolvendo web crawler e bots com Selenium web driver em PHP

Publicidade

Uma das tarefas mais comuns em desenvolvimento web é a “captura” de dados de diversos sites para alimentar uma base. Grandes empresas como Google, Microsoft e Yahoo! utilizam esse tipo de técnica, por exemplo, para alimentar sua base de dados de sites e conteúdo, que são exibidos em seus buscadores.

Comumente, chamamos esse mecanismo de captura de “WebCrawler”, já que eles funcionam como Vormes – entram em um site e vão capturando o conteúdo, além de entrarem em cada link do site e também capturarem seu conteúdo, e assim por diante… Em PHP, é muito comum utilizarmos a função cURL para “crawlearmos”. Realmente, é uma função muito boa para isso, já que ela retorna toda a requisição HTTP que é recebida ao chamarmos uma determinada URI. Só que manipular sessão, controlar cookies, validar formulário e JavaScript são coisas quase impossíveis com o cURL, já que ele literalmente só trabalha com strings.

O Selenium é um motor de automatização de tarefas, feito em Java, largamente utilizado para desenvolver testes de aceitação em sistemas web. Ele funciona em conjunto com o que chamamos de “drive do navegador”, que seria uma capa do navegador. Por exemplo: o drive do Chrome seria um navegador Chrome com todas as suas funcionalidades básicas de navegação.

Um adendo sobre os drivers: a maioria deles necessita de interface gráfica para funcionar. Caso você esteja em um servidor ou em um sistema operacional sem interface gráfica, deverá utilizar um driver que não necessite, como o do PhantomJS.

Podemos enviar comandos ao Selenium através de diversas bibliotecas em várias linguagens, e ele replica esse comando ao driver do navegador e realiza a ação dentro do browser. Assim, ele acaba trabalhando como um “bot” e simulando toda a iteração dentro do navegador. Dessa forma, ao realizar uma tarefa como um login, enquanto o driver não for fechado, ele irá manter a sessão logada.

Para trabalhar com comandos no Selenium em PHP, o Facebook desenvolveu uma biblioteca chamada WebDriver. E será essa biblioteca que iremos utilizar para nosso estudo de caso. Agora, vamos instalar nossa stack para desenvolvermos os crawlers e os bots com o Selenium. Primeiramente, caso você não tenha o Java instalado, será necessário instalar o Java correspondente ao seu sistema operacional. Após isso, você deverá baixar o servidor Selenium, na versão Standalone Server, para um diretório de fácil acesso. Então, deverá baixar o driver correspondente ao navegador que você gostará de utilizar. Por exemplo, para utilizar o driver do Chrome, você deverá baixar o driver nesta URL. No link de cada driver, os mantenedores mostram onde o drive deverá estar dentro do seu sistema operacional. Além disso, você deverá definir o driver como variável de ambiente no seu sistema operacional.

Depois dos passos acima, para deixar o Selenium “funcional”, basta ir até a pasta onde está o Selenium Standalone Server pelo terminal e digitar o comando: java -jar “arquivo correspondente ao Selenium Standalone Server”. Após isso, o Selenium ficará ativo.

Enquanto seu Selenium estiver ativo, todos os comandos do Webdriver serão reconhecidos e enviados ao driver escolhido – caso o driver esteja como variável de ambiente. Agora, para usar o Webdriver, basta executar um composer require na pasta do seu projeto:

composer require facebook/webdriver

Então, o seu projeto terá tudo o que for preciso para rodar os comandos do Selenium através da biblioteca do Webdriver. Vamos a um exemplo de chamada básica ao Selenium através do Webdriver:

example.php

<?php

namespace Facebook\WebDriver; //Definição do namespace
use Facebook\WebDriver\Remote\DesiredCapabilities; //chamada à classe de drivers
use Facebook\WebDriver\Remote\RemoteWebDriver; //chamada à classe de WebDriver

header("Content-type: text/html; charset=utf-8"); //definindo o cabeçalho para utf-8

require_once('vendor/autoload.php'); //realizando o autoload das classes pelo composer

$url = 'https://google.com'; // definindo a url como a do google

$host = 'http://localhost:4444/wd/hub'; // Host default
$capabilities = DesiredCapabilities::chrome(); // escolhendo o driver como chrome
$driver = RemoteWebDriver::create($host, $capabilities, 5000); // criando uma nova conexão com o driver

$driver->get($url); // realizando uma requisição HTTP get na $url

Ao salvar o arquivo acima e executar (com o Selenium ativo em background), será aberto um driver do Chrome com a página do Google.

Para interagir com os elementos da página, devemos usar o método findElement da classe Driver. No caso, a barra de pesquisa do google.com possui o id “lst-ib”. Podemos usar o id para digitar alguma coisa na barra. Além do id, podemos também utilizar o WebDriverBy::cssSelector($seletor), passando a string do seletor CSS correspondente ao elemento.

Por exemplo, adicionando o código abaixo no fim do arquivo example.php, faremos uma pesquisa sobre o Dia dos Namorados.

$pesquisa = $driver->findElement(     //método findElement encontra um elemento do html
    WebDriverBy::id('lst-ib')     //WebDriverBy::id definimos aqui o id do elemento
)->sendKeys('Dia dos Namorados'); //método sendKeys "digita" na barra de pesquisa

Perceba que o Selenium encontrou o id da barra de pesquisas e digitou a pesquisa que queríamos, mas não enviou os dados para a pesquisa. Para fazer isso, basta digitarmos um ENTER.

$pesquisa->sendKeys(array(WebDriverKeys::ENTER)); //método sendKeys enviando um ENTER na pesquisa

Assim como o ENTER, outras teclas especiais são mapeadas pelo WebDriverKeys. Podemos clicar também no elemento utilizando o método click(). Para clicar num link $link, podemos fazer $link->click();.

O que fizemos acima pode ser replicado para o que você quiser, como preencher formulários, logar em algum site, acessar links dentro de sites. Mas como podemos, por exemplo, pegar dados de algum elemento do site? Do mesmo jeito que fizemos com o sendKeys ou o click. Primeiramente, encontramos o elemento, e daí utilizamos o método getText(). Caso tenhamos um elemento $td, podemos fazer um $texto = $td->getText();, então todos os valores de texto no elemento $td serão parseados e estarão na variável $texto.

Agora é só deixar a imaginação te levar. Podemos fazer muitas coisas utilizando o WebDriver, e acho que deu para ver que é bem fácil e prático.

Para saber ainda mais sobre o Webdriver, basta entrar no repositório oficial do GitHub: https://github.com/facebook/php-webdriver. E caso queira ver mais exemplos de código que usamos aqui no artigo, acesse http://bit.ly/selenium-webdriver.

Um grande abraço, até mais!