Voltar ao blogue
Guias
Sorin-Gabriel MaricaLast updated on Apr 22, 202612 min read

Web Scraping com PHP: O Guia Definitivo sobre Web Scraping

Web Scraping com PHP: O Guia Definitivo sobre Web Scraping

A Internet é um espaço imenso, com mais de 4,7 mil milhões de utilizadores, e está em constante crescimento. Para se ter uma ideia, em 2018, mais de 50% da população mundial utilizava a Internet.

É claro que mais utilizadores significam também mais dados. Neste momento, a Internet é tão grande que estima-se que só o Google, a Amazon, a Microsoft e o Facebook armazenem cerca de 1,2 milhões de terabytes.

Mesmo uma fração dessa informação pode criar novas oportunidades de negócio. Tendo isso em conta, não é de admirar que o web scraping se tenha tornado tão popular.

Compreender o web scraping

A riqueza de dados da Internet está lamentavelmente dispersa por milhares de milhões de sites. Como tal, os programadores precisam de uma forma de recolher e processar esses dados, para oferecer aos utilizadores novos produtos inovadores. No entanto, a recolha manual de informações não é, definitivamente, uma boa ideia, uma vez que o volume é frequentemente demasiado grande e os dados mudam continuamente.

A solução é extraí-los automaticamente. É isso que o web scraping faz, em poucas palavras.

Por que deve extrair dados

Mais informação traz mais ideias, oportunidades e benefícios. Uma vez processada, pode ser inestimável para si ou para os seus clientes. Aqui estão apenas algumas formas como o web scraping pode ser utilizado:

  • Ferramentas de comparação de preços - Recolher dados de vários sites para obter uma visão geral de como um tipo de produto é cotado.
  • Estudo de mercado - Descobrir quem são os seus concorrentes mais importantes e o que estão a fazer.
  • Aprendizagem automática - Recolher conjuntos de dados de treino e teste para um modelo de aprendizagem automática.
  • Qualquer ideia que requeira acesso a uma quantidade considerável de dados.

Por exemplo, um possível caso de utilização é a criação de uma aplicação nutricional que permita aos utilizadores adicionarem as suas refeições. Idealmente, os utilizadores apenas abrirão a aplicação, pesquisarão os produtos que comeram, adicioná-los-ão à ferramenta e acompanharão quantas calorias mais podem consumir posteriormente.

No entanto, a ferramenta precisa de fornecer uma lista extensa de todos os produtos possíveis e dos seus valores nutricionais. Esta lista pode ser criada e atualizada automaticamente através da extração de informações nutricionais de vários sites.

Os desafios do web scraping

Embora o web scraping seja muito útil para quem utiliza o bot, por vezes os sites não gostam de partilhar o seu conteúdo e podem tentar impedi-lo. Algumas das formas que podem escolher para o fazer são:

  • Códigos Captcha - Qualquer página pode utilizar Captchas, mesmo que não os mostre. Quando faz várias solicitações, um código Captcha pode aparecer e interromper o seu web scraper.
  • Bloqueio de IP - Alguns sites optam por bloquear o seu IP assim que detetam tráfego excessivo proveniente do seu lado.
  • Bloqueio geográfico - Alguns conteúdos podem estar disponíveis apenas em países específicos, ou poderá receber dados relativos a uma região quando pretende informações sobre outra.
  • JavaScript - A maioria dos sites atuais utiliza JavaScript de uma forma ou de outra. Alguns podem apresentar o seu conteúdo dinamicamente, o que complica as coisas, uma vez que o código-fonte da página não é o mesmo que o conteúdo da página apresentado.

Superar estes desafios pode exigir muito trabalho, mas existem opções. Para o ajudar, criámos a WebscrapingAPI, que trata de todos estes problemas enquanto o ajuda a construir a sua solução mais rapidamente e com menos dores de cabeça.

Compreender a Web

Sempre que um utilizador da Internet acede a um site, o navegador cria um pedido HTTP (Hypertext Transfer Protocol). Pode pensar num pedido como uma mensagem do cliente (o computador do utilizador) para o servidor (o computador onde o site está localizado), na qual o cliente especifica o que deseja receber.

Para cada pedido enviado, receberá uma resposta. A resposta pode ser bem-sucedida ou um erro, como o famoso código de erro «404 página não encontrada». O conteúdo de um site é normalmente encontrado no corpo da resposta recebida do servidor.

Tanto as solicitações como a resposta contêm um cabeçalho e um corpo, utilizados para trocar informações. Além disso, as solicitações podem ser de vários métodos, sendo o mais comum o GET (utilizado ao aceder a uma página web). Estes métodos indicam a ação que o cliente pretende realizar.

Por exemplo, ao registar-se ou atualizar a sua palavra-passe num site, pretende que os seus dados fiquem ocultos no navegador, e os sites podem utilizar o método POST ou PUT para este tipo de pedido.

O cabeçalho de uma solicitação contém várias propriedades. Vamos rever as mais importantes:

  • Host - O nome de domínio do servidor.
  • User-Agent - Detalhes sobre o cliente que efetuou a solicitação, como navegador e sistema operativo.
  • Cookie - Um conjunto de propriedades associadas ao cliente.
  • Accept - Um parâmetro utilizado para receber a resposta do servidor num tipo específico, como text/plain ou application/json.

No entanto, as solicitações não são exclusivas das páginas web. Elas também são feitas para imagens, estilos e código JavaScript, separadamente da página. Pode ver rapidamente todas as solicitações que o seu navegador Google Chrome faz ao aceder a uma página web premindo F12 numa página, selecionando o separador «Rede» e atualizando a página em que se encontra. Deverá ver no final algo semelhante a isto:

Compreender o PHP

O PHP é uma das linguagens de programação web mais antigas e populares utilizadas para back-ends de aplicações. Existe desde 1995 e está agora na sua 8.ª versão.

Os programadores escolhem esta linguagem de programação devido à sua sintaxe simples e facilidade de execução, já que tudo o que é necessário para executar código PHP é um computador com o PHP instalado. Além disso, como existe há tanto tempo, existem muitos recursos e suporte para resolver e depurar erros de PHP.

O PHP também conta com muitos frameworks e CMSs (Sistemas de Gestão de Conteúdos) populares construídos nesta linguagem de programação. Exemplos famosos são o WordPress, o Drupal, o Magento e o Laravel.

Ainda assim, existem também algumas desvantagens. Por exemplo, é mais difícil extrair conteúdo dinâmico em comparação com o Python ou o Javascript. No entanto, se precisar apenas de informações de páginas simples, o PHP é definitivamente uma boa solução e pode ajudá-lo a guardar ou armazenar os dados extraídos com muito mais facilidade.

O que vai precisar

Tudo bem até agora? Pronto para criar o seu primeiro web scraper? Antes de começar, deve ter uma forma de executar o seu código PHP. Pode escolher um servidor Apache/Nginx com PHP instalado e executar o código diretamente do seu navegador, ou pode executar o código a partir da linha de comandos.

Vamos facilitar a nossa vida usando uma biblioteca para processar o conteúdo extraído. Algumas das bibliotecas de scraping PHP mais populares são Goutte, Simple HTML DOM, Panther e htmlSQL. Em alternativa, pode optar por processar o conteúdo usando expressões regulares.

Para este guia, utilizaremos a Simple HTML DOM. No entanto, para pedidos mais avançados, utilizaremos também a biblioteca PHP chamada CURL.

Usando o Simple HTML DOM

A Simple HTML DOM é uma biblioteca desenvolvida para versões do PHP a partir da 5.6 e permite-nos aceder ao conteúdo da página de uma forma muito mais fácil — com seletores. Pode descarregar a biblioteca aqui e deve também ler a documentação.

Do ficheiro zip no link de download, só precisará do ficheiro simple_html_dom.php, que deve colocar na mesma pasta onde irá escrever o código para o scraper.

Para incluir a biblioteca no código, basta esta única linha de código:

include 'simple_html_dom.php'; // If the library is in another folder you should do include 'path_to_library/simple_html_dom.php'

Instalar o PHP-CURL

Embora nem sempre seja necessário, terá de enviar cabeçalhos diferentes para pedidos mais avançados. A utilização da biblioteca PHP-CURL irá ajudar.

Para a instalar numa máquina Ubuntu, pode utilizar o seguinte comando:

sudo apt-get install php-curl

Após instalar a biblioteca, não se esqueça de reiniciar o seu servidor Apache/Nginx.

Criar o seu próprio web scraper

Agora que temos tudo o que precisamos, está na hora de extrair dados! Primeiro, deve decidir qual o site e o conteúdo que pretende extrair. Para este artigo, iremos extrair o conteúdo da Lista de Filmes Mais Bem Classificados do IMDB.

1. Analise o conteúdo do site

A maior parte do conteúdo web é apresentado utilizando HTML. Uma vez que precisamos de extrair conteúdo específico da fonte HTML, é também necessário compreendê-la. Precisamos primeiro de inspecionar como é a fonte da página para saber quais os elementos a extrair da página.

Pode fazer isto no Google Chrome clicando com o botão direito do rato no elemento que pretende extrair e, em seguida, selecionando “Inspecionar Elemento”. Isto deverá abrir uma janela no seu navegador com o código-fonte da página e os estilos renderizados dos elementos. Nesta janela, o único separador que precisamos de verificar é “Elementos”, que nos mostrará como o DOM HTML da página está estruturado.

Por exemplo, a página contém uma tabela com as classes “chart” e “full-width” na imagem acima. Nesta tabela, cada célula tem a sua própria classe (posterColumn, titleColumn, etc.), que podemos usar para criar um seletor. Assim, podemos aceder apenas aos dados necessários.

Confuso? Não se preocupe, os passos seguintes vão esclarecer tudo.

2. Enviar um pedido a partir de PHP

Enviar uma solicitação, neste caso, significa basicamente aceder ao HTML de uma página diretamente com código PHP. Existem duas maneiras de fazer isso.

Primeiro, podemos usar a biblioteca PHP-CURL, que também nos permite modificar os cabeçalhos e o corpo que enviamos na nossa solicitação.

<?php
 
header("Content-Type: text/plain"); // We choose to display the content as plain text
 
$ch = curl_init("https://www.imdb.com/chart/top/");
curl_setopt($ch, CURLOPT_HEADER, 0);
$response = curl_exec($ch); // Running the request
 
if (curl_error($ch)) {
    echo curl_error($ch); // Displaying possible errors from the request
} else {
    echo $response; // Displaying the content of the response
}
 
curl_close($ch);
?>

Outra opção é uma linha única, utilizando o método file_get_contents($url), mas isto pode ser insuficiente em alguns casos. Para enviar cabeçalhos para esta solicitação, é necessário utilizar um contexto criado com o método stream_context_create.

<?php

header("Content-Type: text/plain"); // We choose to display the content as plain text

echo file_get_contents('https://www.imdb.com/chart/top/'); // We retrieve and display the contents of the response in a single line

?>

Deve decidir qual o método a utilizar com base na complexidade do scraper que pretende construir.

Os dois trechos de código acima irão exibir o código-fonte HTML da página que estamos a extrair, o mesmo que é visível quando inspeciona o site. Iremos utilizar a primeira linha do código para exibir os resultados como texto simples. Caso contrário, será renderizado diretamente como HTML.

Se houver diferenças na estrutura HTML, significa que um código JavaScript está a ser executado no site e a alterar o conteúdo assim que um utilizador acede ao mesmo. Preparámos uma dica sobre como lidar com isso mais adiante neste artigo.

3. Extrair os dados

Da página que escolhemos, iremos extrair apenas o título dos filmes e a classificação associada a cada um deles. Como vimos anteriormente, o conteúdo é apresentado numa tabela onde cada célula tem a sua classe.

Usando isto, podemos optar por extrair todas as linhas da tabela. Depois, procuramos em cada linha individual as células que nos interessam.

O seguinte trecho de código deve fazer exatamente isso:

<?php
 
header("Content-Type: text/plain"); // We choose to display the content as plain text
 
include 'simple_html_dom.php';
 
$html_dom = file_get_html('https://www.imdb.com/chart/top/'); // We retrieve the contents using file_get_html from simple_html_dom
$table_rows = $html_dom->find('table.chart tbody tr'); // Getting all of the table rows
foreach($table_rows as $table_row) {
    $title_element = $table_row->find('.titleColumn a', 0);
    $rating_element = $table_row->find('.ratingColumn strong', 0);
    if (!is_null($title_element) && !is_null($rating_element)) { // Checking if the row has a title and a rating column
        echo $title_element->innertext . ' has rating ' . $rating_element->innertext . PHP_EOL; // If it does then we print it
    }
}
 
?>

Pode reparar que utilizámos o seletor “table.chart tbody tr” para extrair todas as linhas da tabela. É aconselhável utilizar seletores tão específicos quanto possível, para que possa diferenciar os elementos de que necessita dos restantes.

Depois de recuperar as linhas, percorremos todas elas, procurando por elementos com a classe titleColumn ou ratingColumn. Se o código encontrasse algum, exibia a sua propriedade innerText.

É importante notar que utilizámos file_get_html em vez de file_get_contents para este exemplo. Isto porque esta função provém da biblioteca simple_html_dom e funciona como um wrapper para a função file_get_contents.

4. Exportar os dados

Nos exemplos acima, recolhemos os dados do site e exibimo-los diretamente no ecrã. No entanto, também é possível guardar os dados em PHP com bastante facilidade.

Pode guardar os dados extraídos num ficheiro .txt, como JSON, como CSV, ou até enviá-los diretamente para uma base de dados. O PHP é muito bom nisso. Basta armazená-los numa matriz e colocar o conteúdo da matriz num novo ficheiro.

<?php
 
include 'simple_html_dom.php';
 
$scraped_data = [];
 
$html_dom = file_get_html('https://www.imdb.com/chart/top/'); // We retrieve the contents using file_get_html from simple_html_dom
$table_rows = $html_dom->find('table.chart tbody tr'); // Getting all of the table rows
foreach($table_rows as $table_row) {
    $title_element = $table_row->find('.titleColumn a', 0);
    $rating_element = $table_row->find('.ratingColumn strong', 0);
    if (!is_null($title_element) && !is_null($rating_element)) { // Checking if the row has a title and a rating column
        $scraped_data[] = [
            'title' => $title_element->innertext,
            'rating' => $rating_element->innertext,
        ];
    }
}
 
file_put_contents('file.json', json_encode($scraped_data)); // Saving the scraped data in a .json file
 
// Saving the scraped data as a csv
$csv_file = fopen('file.csv', 'w');
fputcsv($csv_file, array_keys($scraped_data[0]));
 
foreach ($scraped_data as $row) {
    fputcsv($csv_file, array_values($row));
}
 
fclose($csv_file);
 
?>

O código acima utiliza o mesmo conteúdo que extraímos anteriormente e cria dois ficheiros, um CSV e um JSON, com todos os filmes mais bem classificados e as suas classificações.

Dicas e Truques

1. Tratamento de erros

Ao programar em PHP e extrair dados de sites que podem mudar a qualquer momento, é normal que surjam erros. Um bom trecho de código que pode usar para depuração são as três linhas seguintes, colocadas no início de qualquer script PHP:

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

Estas irão ajudá-lo a identificar problemas no seu código mais rapidamente e a atualizar o seu script quando necessário.

2. Definir cabeçalhos em pedidos para PHP

Por vezes, ao efetuar um pedido, poderá ser necessário enviar também alguns cabeçalhos. Por exemplo, ao trabalhar com uma API, poderá ser necessário um token de autorização, ou poderá querer que o conteúdo seja fornecido como JSON em vez de texto simples. Pode adicionar cabeçalhos tanto com o curl como com o file_get_contents. Veja aqui como fazê-lo com o curl:

$ch = curl_init("http://httpbin.org/ip");
curl_setopt($ch, CURLOPT_HEADER, [
    'accept: application/json'
]);
$response = curl_exec($ch); // Running the request

E para o file_get_contents:

$opts = [
    "http" => [
        "method" => "GET",
        "header" => "accept: application/json\r\n"
    ]
];
$context = stream_context_create($opts);
$result = file_get_contents("http://httpbin.org/ip", false, $context);

3. Utilizar o curl ou o file_get_contents com o simple_html_dom

Quando extraímos conteúdo do IMDB, utilizámos a função file_get_html do simple_html_dom para fazer o scraping. Esta abordagem funciona para pedidos simples, mas não necessariamente para os mais complicados. Se precisar de enviar cabeçalhos, é melhor utilizar um dos métodos usados na dica anterior.

Para usá-los em vez de file_get_html, basta extrair o conteúdo e, em seguida, usar str_get_html para convertê-lo num objeto DOM, assim:

$opts = [
    "http" => [
        "method" => "GET",
        "header" => "accept: text/html\r\n"
    ]
];
$context = stream_context_create($opts);
$result = file_get_contents("https://www.imdb.com/chart/top/", false, $context);
$html_dom = str_get_html($result);

Além disso, tenha em mente que o simple_html_dom tem, por predefinição, alguns limites (que podem ser encontrados no ficheiro simple_html_dom.php). Por exemplo, o conteúdo do site pode ter até 600 000 caracteres. Se quiser alterar este limite, basta defini-lo no início do seu código antes de incluir a biblioteca simple_html_dom:

define('MAX_FILE_SIZE', 999999999);

4. Extrair conteúdo dinâmico

Se estiver a extrair dados de um site dinâmico, terá de aceder ao mesmo como um navegador faria. Caso contrário, não conseguirá extrair os dados reais e obterá código JS em vez disso.

Terá de instalar um driver de navegador, como o chromium-chromedriver ou o firefox-geckodriver. Extrair o conteúdo dinâmico em PHP é uma lição mais avançada, mas se estiver interessado, pode tentar fazê-lo lendo a documentação da biblioteca panther.

Em alternativa, uma solução muito mais simples é utilizar a WebScrapingAPI, que elimina a maioria dos problemas. A API contorna bloqueios de IP e Captchas utilizando a nossa rede de proxies, ao mesmo tempo que executa javascript. O resultado: dispõe imediatamente de um scraper avançado, reduzindo o tempo de desenvolvimento e de espera.

Aqui está um exemplo de código que irá apresentar o conteúdo de https://httpbin.org/ip diretamente em PHP, através da nossa API:

$content = 
file_get_contents("https://api.webscrapingapi.com/v1?pi_key=YOUR_API_KEY&url=". urlencode('https://httpbin.org/ip'));
echo $content;

Conclusão

Parabéns por ter chegado ao fim! Agora deve ter tudo o que precisa para criar o seu Web Scraper com PHP. Embora tenhamos explorado apenas a biblioteca simple_html_dom neste artigo, pode experimentar outras bibliotecas populares e ver por si mesmo qual se adequa melhor às suas necessidades.

Lembre-se de que os sites estão em constante mudança e os seus dados podem ser atualizados da noite para o dia. Para ajudar com isso, pode usar seletores mais específicos. É claro que não há garantia de que o seu scraper funcionará para sempre, mas é um começo. É por isso que os web scrapers exigem atualizações contínuas e demoradas.

Se não te apetece gastar todo esse tempo a pesquisar e a adaptar o teu código, podes sempre experimentar a versão de avaliação gratuita da WebScrapingAPI!

Sobre o autor
Sorin-Gabriel Marica, Desenvolvedor Full-Stack @ WebScrapingAPI
Sorin-Gabriel MaricaDesenvolvedor Full-Stack

Sorin Marica é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.