DevWebPHP
Image
22/06/2020

Web Scraping com PHP: alerta de dividendos com Symfony

# Introdução

Eu sigo um perfil no Instagram @fiisinvest que mostra os investimentos que o autor vem fazendo, e nesse perfil ele posta as notificações de dividendos que ele recebe.

Essas notificações ele recebe de um aplicativo chamado Kinvo.

Eu acho muito legal a idéia de abrir a tela do celular e lá está a notificação que você recebeu dinheiro vindo dos seus investimentos 🤑!

Só que essa funcionalidade do aplicativo é paga 😕

Mas... a informação está disponível para cada investidor no portal CEI. Então nada que um scraping não dê jeito 😎

Eu comecei a fazer esse script com node.js, mas acabei perdendo bastante tempo com o problema do certificado, quase desisti, e dai decidi fazer em PHP... Muuuuuuuito mais fácil!

Acabei descobrindo um pacote que usava os componentes do Symfony para fazer scraper mas no final nem usei o pacote, só os componentes do Symfony mesmo.

E o resultado ficou menor e mais simples que o script feito em Node.js 🤣

# Iniciando

O objetivo é criar um script que vai extrair as informações e enviar um e-mail para mim mesmo com os dividendos a receber no dia.

Não é necessário um front-end, então vou só usar a linha de comando.

Crie uma pasta para o projeto chamada alerta-dividendos.

Abra o terminal na pasta e instale as dependências necessárias:

composer require symfony/browser-kit symfony/http-client \
  symfony/css-selector symfony/mailer symfony/google-mailer symfony/mime
1
2

Crie um arquivo chamado index.php e inclua o autoload:

<?php
require __DIR__ . '/vendor/autoload.php';
1
2

# Fazendo login

Fazer a request para a tela de login do CEI:

<?php
require __DIR__ . '/vendor/autoload.php';
$browser = new Symfony\Component\BrowserKit\HttpBrowser();

try {
    $loginScreen = $browser->request('GET', 'https://cei.b3.com.br/CEI_Responsivo/login.aspx');
    var_dump($loginScreen->html());
} catch (\Exception $e) {
    echo $e->getMessage();
}
1
2
3
4
5
6
7
8
9
10

Para testar, no terminal execute:

php index.php
1

Provavelmente, vai dar um erro de certificado como esse:

Peer certificate cannot be authenticated with given CA certificates for "https://cei.b3.com.br/CEI_Responsivo/login.aspx
1

Vamos ignorar essa validação instruindo o HttpClient com:

$client = Symfony\Component\HttpClient\HttpClient::create(['verify_peer' => false]);
$browser = new Symfony\Component\BrowserKit\HttpBrowser($client);
1
2

Vamos testar novamente:

php index.php
1

Se deu certo, o código-fonte da página de login vai ser exibido na tela do terminal.

Para fazer o login vamos selecionar o formulário pela label do botão. Com o inspetor de elementos vamos pegar o name dos campos CPF e senha:

Input name

Agora temos o necessário para fazer o login:

try {
    $loginScreen = $browser->request('GET', URL_LOGIN);
    $loginForm = $loginScreen->selectButton('Entrar')->form([
        'ctl00$ContentPlaceHolder1$txtLogin' => 'seucpf',
        'ctl00$ContentPlaceHolder1$txtSenha' => 'suasenha'
    ]);
    $loginResult = $browser->submit($loginForm);
} catch (\Exception $e) {
    echo $e->getMessage();
}
1
2
3
4
5
6
7
8
9
10

Pronto! Estamos logados!

# Consultando os dividendos

Agora vamos recuperar os dividendos acessando a tela e enviando o formulário de pesquisa:

Proventos

$dividendsResult;
try {
    $url = 'https://cei.b3.com.br/CEI_Responsivo/ConsultarProventos.aspx';
    $dividendsScreen = $browser->request('GET', $url);
    $dividendsForm = $dividendsScreen->selectButton('Consultar')->form();
    $dividendsResult = $browser->submit($dividendsForm);
    var_dump($dividendsResult->html());
} catch (\Exception $e) {
    echo $e->getMessage();
    die;
}
1
2
3
4
5
6
7
8
9
10
11

Se tudo deu certo, veremos o código-fonte da tela de proventos no terminal. Simples assim!

# Extraindo as informações

Agora vamos extrair as informações para poder manipular:

Dividendos

As informações relevantes para nós nesse caso é somente as colunas "Ativo" que é a primeira (0), "Prev. Pagamento" é a quarta (3) e "Valor Líquido" a última (7).

$dividends = $dividendsResult->filter('tbody tr')->each(function ($tr) {
    return [
        'payer' => $tr->filter('td')->eq(0)->text(),
        'date' => $tr->filter('td')->eq(3)->text(),
        'ammount' => $tr->filter('td')->eq(7)->text(),
    ];
});
1
2
3
4
5
6
7

O valor e a data estão formatados, vamos por em um formato que fique mais fácil de filtrar, pois não queremos todos os dividendos somente os do dia.

$dividends = $dividendsResult->filter('tbody tr')->each(function ($tr) {
    return [
        'payer' => $tr->filter('td')->eq(0)->text(),
        'date' => preg_replace('/(\d{2})\/(\d{2})\/(\d{4})/', '$3-$2-$1', $tr->filter('td')->eq(3)->text()),
        'ammount' => floatval(preg_replace('/,/', '.', $tr->filter('td')->eq(7)->text())),
    ];
});
1
2
3
4
5
6
7

# Manipulando as informações

Agora podemos usar a data para comparar com a data atual e somar os valores:

$now = date('Y-m-d');
$payers = [];
$total = 0;
foreach ($dividends as $dividend) {
    if (date('Y-m-d', strtotime($dividend['date'])) == $now) {
        $total += $dividend['ammount'];
        $payers[] = $dividend['payer'];
    }
}
$totalBrl = number_format($total, 2, ',', '.');
$subject = 'R$ ' . $totalBrl . ' a mais na conta!';
$body = 'Vou receber no total R$ ' . $totalBrl . ' dos ativo(s): ' . implode(', ', $payers);
echo $body;
1
2
3
4
5
6
7
8
9
10
11
12
13

# Enviando e-mail

Por fim enviamos o e-mail:

$email = (new Symfony\Component\Mime\Email())
    ->from('seuemail@gmail.com')
    ->to('seuemail@gmail.com')
    ->subject($subject)
    ->text($body);

$transport = new Symfony\Component\Mailer\Bridge\Google\Transport\GmailSmtpTransport('seuemail@gmail.com', 'suasenha');
$mailer = new Symfony\Component\Mailer\Mailer($transport);
$mailer->send($email);
1
2
3
4
5
6
7
8
9

# Conclusão

Agora é só registrar um crontab para executar o script todo dia e receber os alertas quando os dividendos vão cair na conta 🏖️🍹🕶️:

0 9 * * * /usr/bin/php /path/absoluto/index.php
1

O código completo você pode ver no GitHub.

Copyright © DevWebPHP 2020