Todos os posts de Tomás Vásquez

SuperDicas – Usando as Fórmulas Matriciais

Originalmente publicado neste endereço: http://www.superdicas.com.br/excel/excel21.asp

Explico o motivo da replicação no fim do artigo.

O Que é uma Fórmula Matricial

No Excel uma fórmula matricial executa cálculos múltiplos e, em seguida, produz um resultado único, ou resultados múltiplos. Fórmulas matriciais agem sobre um ou mais conjuntos de valores, que são conhecidos como argumentos de matriz. Cada argumento de matriz deve ser retangular e cada argumento precisa ter o mesmo número de linhas e/ou o mesmo número de colunas que os outros argumentos.

Para produzir resultados múltiplos, a fórmula deve ser inserida em células múltiplas.

No Excel para se inserir uma fórmula matricial, deve-se pressionar as teclas [CTRL]+[SHIFT]+[ENTER] simultaneamente. O Excel coloca fórmulas matriciais entre chaves { e }.
Atentar para que essas chaves NUNCA sejam digitadas, pois assim não funcionará.

Recurso Pouco Utilizado

Além de pouco utilizado, por parecer muito complexo, é um recurso que quase ninguém conhece. Para facilitar a compreensão daremos abaixo dois exemplos de sua utilização prática. O primeiro exemplo ilustra a utilização da fórmula matricial como auxiliar na contagem de repetições de números. O segundo exemplo ilustra a utilização da mesma na elaboração de uma lista de repetições de nomes. Para facilitar, ainda mais, disponibilizamos uma planilha com estes exemplos, completos, e que você pode baixar para checar e adaptar às suas necessidades. O link para o download está no final desta página.

Exemplo 1: Contando o Número de Repetições numa Faixa de Células

Imaginemos que exista uma faixa de células onde são guardados diversos números, números esses que podem, ou não, se repetir dentro da faixa de entrada dos dados. Queremos ter a condição de saber quantas vezes um determinado número aparece dentro da faixa de entrada.

Cenário:

Nas células de A3 até A15 são colocados os números, que podem ter, ou não, repetições. Na célula B3 se digita um número – aquele que se quer conhecer o número de vezes que aparece na faixa de dados. Finalmente o resultado – o número de vezes que um dado valor aparece na faixa de entrada dos dados – deve aparecer na célula C3.

Aplicando a Fórmula Matricial:

Com o cursor na célula C3, digita-se a seguinte fórmula:
=SOMA(SE(A3:A15=B3;1;0)) – só que ao invés de pressionar a tecla [ENTER], como se faz em todas as demais situações, para inserir uma fórmula matricial se pressionam, simultaneamente, as teclas [CTRL]+[SHIFT]+[ENTER].

O Excel irá representar a fórmula entre chaves, como mostrado abaixo:

{=SOMA(SE(A3:A15=B3;1;0))}

A B C
1

Demonstração de Fórmula Matriz # 1

2 Entradas Checa este Número No. De Repetições
3 10

10

3

4 12  Na célula acima digita-se o número que se deseja pesquisar as repetições Na célula acima aparece o número de repetições do valor digitado
5 10
6 15
7 16
8 15
9 15
10 12
11 10
12 19
13 18
14 18
15 17

Como Funciona:

O Excel, percebendo se tratar de uma fórmula matricial, passa por todas as células da faixa demarcada, comparando-as com o valor digitado na célula B3 – SE(A3:A15=B3). Quando uma das células contiver um número idêntico a fórmula retorna o valor 1, senão retorna o valor 0. Ao final da faixa ser totalmente checada o Excel totaliza os zeros e uns (através da função =SOMA) encontrados em cada comparação. Essa soma é exatamente igual ao número de vezes que tal número aparece na faixa de entrada.

Exemplo 2: Mostrando Nomes Repetidos Apenas Uma Única Vez

Imaginemos que exista uma faixa de células onde são guardados diversos nomes de visitantes de nosso estante de arte, por exemplo. Esses visitantes podem, ou não, retornar e assim podem se repetir dentro da faixa de entrada dos dados. Queremos ter condição de destacar, por exemplo na coluna ao lado apenas a primeira vez em que algum nome aparece dentro da faixa de entrada.

Cenário:

Nas células de A3 até A15 são colocados os nomes, que podem ter, ou não, repetições. Finalmente o resultado – uma coluna onde cada nome só apareça uma única vez – deve aparecer na célula C3.

Aplicando a Fórmula Matricial:

Com o cursor na célula B3, digita-se a seguinte fórmula:
=SE(SOMA(A3=$B$2:B2)*1)=0;A3;””) – só que ao invés de pressionar a tecla [ENTER], como se faz em todas as demais situações, para inserir uma fórmula matricial se pressionam, simultaneamente, as teclas [CTRL]+[SHIFT]+[ENTER].
O Excel irá representar a fórmula entre chaves, como mostrado abaixo:

{=SE(SOMA(A3=$B$2:B2)*1)=0;A3;””)}

Em seguida deve-se copiar a fórmula em B3 para o restante da faixa, no caso entre B4 e B15.

A B
1

Demonstração de
Fórmula Matriz # 2

2 Visitantes Visitantes Únicos
3 André André
4 Colombina Colombina
5 Matilde Matilde
6 Alfredo Alfredo
7 Antonio Antonio
8 Matilde
9 Colombina
10 André
11 Sérgio Sérgio
12 Matilde
13 André
14 Célia Célia
15 Antonio

Como Funciona:

O Excel, percebendo se tratar de uma fórmula matricial, passa por todas as células da faixa demarcada, comparando o valor em A3 com todos os valores já definidos pela fórmula desde a posição B2 até a célula da coluna B na linha atual (B2 está vazia naturalmente, ou contém apenas um título, que não representa um nome). Quando uma das células  da coluna A contiver um novo nome a fórmula retorna o valor 1, ou 2 ou de quantas vezes se repetiu essa nome até esse momento, se ele não apareceu nenhuma vez (o valor é 0) a fórmula SE dá resultado verdadeiro e o Excel coloca o nome encontrado na mesma linha na coluna A, senão (o resultado de SE é falso) o Excel apenas coloca um valor vazio (“”) na célula.

Experimente um pouco mais com este recurso pouco explorado, mas muito útil em diversos momentos de nosso trabalho com números e/ou nomes.

Declaração

Este post é uma homenagem.

Além de ser um recurso acima do média, fórmulas matriciais são um mistério para a maioria dos usuários de Excel, mesmo depois de anos de seu lançamento. No momento da publicação deste artigo, blogs, mídias sociais, canais de vídeos de todo tipo e até cursos são dados aos montes.

No entanto, anos atrás quando a internet eram blogs e geocities, raros eram os bons conteúdos publicados. Este em específico, era minha salva guarda, já que era um dos poucos que conseguiu explicar de maneira sucinta algo que level anos para entender, e gostaria de dividí-lo aqui, com vocês.

Repito, esta é uma homenagem, já que o site que hospedava a página não está mais no ar no link original ou em outro que pareça ser de mesma autoria. Se o autor do artigo se sentir de alguma forma lesado com a publicação deste, por favor, entre em contato para a devida remoção.

Selenium – Como esperar até um elemento estar presente na página

AVISO: Este artigo é um bonus para a comunidade, já que é parte de um curso que está em desenvolvimento (com algumas adaptações). Fiquem ligados para mais novidades sobre.

Se você faz parte do time que brinca com Selenium a algum tempo, já se deparou com a situação acima. Existem algumas formas de fazê-lo utilizando as próprias funções. Abaixo demonstro a maneira que melhor me serviu para tal propósito.

A Função IsElementPresent

Ela é parte do objeto WebDriver. O uso chega a ser ridiculamente simples. Se o elemento está presente, retorna True, do contrário, False. O problema é que o parâmetro que ele pede é um objeto do tipo By:

Ok, vamos precisar então saber quem é esse carinha.

O Objeto By

Se você teve a chance de olhar o código fonte do SeleniumBasic (e você deveria), verá que o By está em todo lugar. Como o fonte é em C#, seu uso é mais natural, mas em VBA, é um pouco mais chato, mas não impossível.

Nada melhor do que ver funcionando, certo?

Considere os códigos abaixos:

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>
      Selenium - Como esperar até um elemento estar presente na página
    </title>
    <script>
      function disparaContador() {
        setTimeout(function() {
          var novaDiv = document.createElement("div");
          novaDiv.style.display = "block";
          novaDiv.id = "escondido";
          novaDiv.innerHTML = "<h2>Ta dá!</h2>";
          document.body.appendChild(novaDiv);
        }, 3000);
      }
    </script>
  </head>
  <body>
    <h1>Selenium - Como esperar até um elemento estar presente na página</h1>
    <p>
      O elemento abaixo aparecerá após 3 segundos do botão abaixo ter sido
      clicado
    </p>
    <button id="disparaContador" onclick="disparaContador()">Vai</button>
  </body>
</html>

VBA:

'@Folder("VBAProject")
Dim driver As WebDriver
 
Sub EsperaPorElemento()
    Dim por As New By
 
    Set driver = New IEDriver
    Call driver.SetCapability("ignoreZoomSetting", True)
    driver.Get Replace(ThisWorkbook.FullName, ThisWorkbook.Name, "") & "index.html"
    driver.FindElementById("disparaContador").Click
 
    While driver.IsElementPresent(por.ID("escondido"))
        'espera por um segundo
        'o uso do Application.Wait serve para não congelar a execução do VBA
        Application.Wait Now + TimeValue("00:00:01")
    Wend
    'neste ponto, o elemento já deve estar presente
    MsgBox driver.FindElementById("escondido").Text
End Sub

Em resumo, a página HTML tem um código que cria dinamicamente uma div 3 segundos após clicar no botão. Ou seja, o elemento não está lá quando a página é carregada, o que valida o código.

O código faz uso do IsElementePresent e do By para “esperar” o elemento estar presente na página.

Os mais atentos devem ter percebido que o By vai muito além do ID, tendo as opções de identificar o elemento através do TagName, ClassName, XPath, etc.

Baixe o código e execute.

ALERTA:
Não nomeia a variável do tipo By como by ou By. O VBA se perde todo e fica difícil entender o que está acontecendo. Por isso nomeiei como “por”, que seria uma tradução direta para o português.

Todo o código fonte está disponível aqui:

https://github.com/Tomamais/SeleniumCom … toNaPagina

Web Scraping, WhatsApp, CAPTCHA e Ética

Web Scraping, e reduto da extração de dados na internet. Essa prática é tão antiga que data dos bots dos robôs de busca que já a aplicavam mesmo antes de muitos de vocês leitores terem nascido.

Sim, meu caro padawan, se você achava que estava inovando escrevendo um script em Python ou VBA para extrair dados de uma página web, pense de novo! Há uma quantidade insana de bots e spiders fazendo isso desde os tempos remotos da World Wide Web.

Pra variar, a tecnologia não perdoou e tornou cada vez mais fácil fazer esse tipo de extração de dados, mesmo para profissionais cuja rotina nada tem de relacionada com programação. Nisso entra o VBA, provavelmente a opção de automação de mais fácil alcance e didática presente no mercado.

Até aqui, tudo bem, o web scraping está aí, é fácil de fazer, ferramentas tem aos montes, sites-alvo mais ainda. Mas (sempre tem um mas) enquanto muitos passam tempo tentando descobrir o como, poucos se perguntam se realmente deveriam estar fazendo isso. 

Web Scraping e Ética?

Para o quê e quando fazer web scraping é uma pergunta que, para ser respondida, deveria sempre ter um contexto ético. Não vou entrar no mérito filosófico da questão, já que em tempos atuais o que mais tem é filósofo discutindo ética na internet. Vou basear a crença deste texto na seguinte definição:

Ética: tudo aquilo que você faz mesmo quando ninguém está olhando.

Ou seja, quando você faz web scraping de um website, você deveria sim se perguntar se você deveria estar fazendo-o. Um site quando é publicado tem a intenção primária de fornecer conteúdo legível para humanos. Quando um script entra em jogo, isso cai por terra. Ao invés de um ser humano limitado a um certo número de cliques e com uma capacidade regular de ler e interpretar textos, um bot consegue repetir a operação de clicar, baixar e salvar diversas páginas numa fração desse tempo.

Dentre vários problemas que isso pode causar, posso pensar em:

  1. O site não foi feito para aguentar tal carga de acessos
  2. Os termos e condições não permite a cópia dos dados
  3. E mais importante, o autor do site tem o direito exigir interação humana no site

Sim, Termos e Condições, aquela coisa que, assim como contratos, pouquíssimos lêem.

Termos de Condições

Vou ser claro, não sou advogado, mas já tive a oportunidade de conversar muito com vários para ter uma noção honesta do que pode acontecer se você não andar na linha. Posto isto, vamos em frente.

Quando um site exibe um texto detalhando Termos e Condições, as chances de haver uma séria limitação de acesso ao uso seu conteúdo é quase certa. 

Essas limitações atingem principalmente robôs, que nada mais são que aplicativos criados para acessar o conteúdo de um website. Sabe aquele script em VBA que você criou para extrair dados de uma página web? Pois é, ele entra nessa categoria.

No geral, não é preciso se preocupar na maior parte dos casos já que o problema está em como você usa a informação e não como ela é extraída. Mas (outro mas aqui), toda vez que você pensar em fazer qualquer tipo de extração automatizada, você deveria ler os Termos e Condições.

E sim, você deveria estar se perguntando se alguma vez você já fez isso.

Por que isso é tão importante? Porque ter acesso a um dado é diferente do uso que se faz dele, e isso comumente está claro nos Termos e Condições, que normalmente detalha não só as regras e limitações como as penalidades aplicadas.

Quando você deveria fazer web scraping

Existe um cenário ideal para quando você deveria fazer web scraping sem se preocupar muito. A maneira mais fácil de identificar tal cenário é quando você já está fazendo alguma operação manual, como por exemplo extrair dados de venda para construir um relatório específico que não está disponível num sistema interno da empresa. Ao invés de copiar e colar uma centena de dados, o que não só levaria um tempo considerável como também estaria sujeito a erros, você pode automatizar isso.

Esta é uma situação perfeita para aplicar web scraping. Os dados são da empresa, serão utilizados pela empresa e o usuário que precisa deles não tem acesso a eles de outra forma que não pelo próprio.

Qualquer coisa que vá além disso (resumindo, tudo o que não é seu) cai no filtro dos Termos e Condições.

Quando você NÃO deveria fazer web scraping

Existem diversos sinais que deixarão claro que um web scraping não é bem vindo. Não vou entrar em detalhes sobre robots.txt e outras minúscias. Isto é algo que ficará para um curso de Web Scraping que lançarei num futuro próximo.

Então, quando não é aconselhável fazer web scraping? Os exemplos abaixo são os mais comuns:

  • O site expõe um CAPTCHA
  • O site protege a informação através de login e senha
  • O site ou o detentor dele expõe formas mais adequadas de extrair a informação, como através de web services (SOAP/REST)
  • O site bloqueia seu acesso caso ele for muito frequente
  • O site não permite extração de dados de forma automatizada (Termos e Condições, lembra?)

Vale a pena detalhar um pouco mais o primeiro item citado.

CAPTCHA

Isso mesmo, aquela coisa horrorosa que temos que decifrar
Isso mesmo, aquela coisa horrorosa que temos que decifrar

O CAPTCHA é um Teste de Turing aplicado em uma página web. Para leigos, é basicamente uma maneira moderna de impedir que uma máquina se passe por um ser humano real. A razão para isso é simples: sites são conteúdos visuais, feitos para humanos consumirem. Se uma máquina/robô/script vem atazanar aquele lindo website que você construiu com tanto esforço e paga com o suor do seu trabalho para ficar hospedado, você vai querer saber o que está acontecendo.

Para evitar que seu conteúdo seja lido ao léu por robôs que querem mais é tirar proveito de informação alheia, a internet bolou formas de bloquear o acesso, sendo a mais conhecida e utilizada o CAPTCHA.

Como mencionado acima, seu script VBA entra na categoria de robôs da internet, por isso, o CAPTCHA está lá para atrapalhar a vida dele.

Por isso, toda vez que você der de cara um com desses ao escrever seu lindo web scrapper, saiba existe um motivo muito bom para ele estar lá.

E o WhatsApp?

O WhatsApp entra de vítima nessa história por alguns motivos específicos:

  • Há uma versão web/desktop que pode ser usada
  • Como todo site/app, ele também funciona sob determinados termos de condições, algo que já discutimos aqui
  • O WhatsApp é de longe o aplicativo de mensagens mais utilizado no Brasil, o que o torna alvo de todo tipo de ação que foca em atingir massas (leia-se spam)
  • O WhatsApp é do Facebook, uma gigante da indústria da internet com muito $$$ para gastar e ela não poupará em revidar se um mau uso for feito do seu aplicativo, já que este pode ser usado de graça

Recentemente a publicação deste texto, o jornal The Economic Times publicou uma matéria detalhando que o WhatsApp vai processar qualquer um que fizer uso do aplicativo para envio de mensagens em massa. Link aqui (em inglês): https://economictimes.indiatimes.com/tech/internet/whatsapp-will-take-you-to-court-if-you-send-bulk-messages-misuse-app/articleshow/69783647.cms?from=mdr

Ou seja querido scripteiro, se você estiver fazendo uso do WhatsApp desktop para fazer envio de mensagens em massa, você está infringindo o regulamento do aplicativo e sujeito a penalização.

Se você se perguntava porque até agora eu não tinha publicado um tutorial de Selenium e WhatsApp, bem, aí está sua resposta.

Fazendo Mock da Classe HttpClient

O problema?

Ainda que você não viva no mundo dos micro-serviços, uma hora você vai precisar chamar um serviço REST em outra ponta via HTTP/S, e no caso do AspNetCore, o jeito mais natural de fazê-lo é via a classe HttpClient.

Até aqui, tudo tranquilo, os métodos Get, Post, Put, Patch e Delete (talvez até outros) estão lá para serem usados. O problema é, caso sua implementação precise passar por testes unitários, a classe HttpClient pode lhe trazer problemas, já que não há interface disponível para mock e os métodos acima citados não são virtual.

Note que citei que ela “pode” lhe trazer problemas. Como fazer então para que a classe HttpClient não seja um para seus testes unitários?

Tudo se resume ao SendAsync

Se há algo que é mágico no AspNetCore é que ele é código aberto. Isso mesmo, você ir lá no github e ter acesso ao código fonte de praticamente 100% das classes que você usa no seu projeto. E, felizmente, esse é a caso do HttpClient. Vou deixar o link do fonte no fim do artigo.

Dando uma lida na classe, que é bem escrita por sinal, percebe-se que todos os métodos REST com exceção do Get, chamam um método chamado SendAsync, que recebe como parâmetro um objeto HttpRequestMessage e opcionalmente um CancellationToken.

O HttpRequestMessage precisa basicamente do corpo que você enviaria via Post, Put, Patch e Delete. O ponto de atenção é que somente a versão com o CancellationToken é virtual/override. Se você sabe o que o CancellationToken é, você deveria estar usando-o. Caso não, use CancellationToken.None por agora.

O código de exemplo abaixo faz um Post usando HttpClient:

public class MeuController : ControllerBase
{
	private readonly HttpClient client;

    public MeuController(HttpClient client)
    {
        this.client = client;
    }

	public async Task AlgumPost(Criterios criterios)
	{    
	    // estou ignorando quaisquer configurações de header
	    // também estou assumindo que a classe HttpClient é injetada via construto
		var stringContent = new StringContent(JsonConvert.SerializeObject(criterios), Encoding.UTF8, "application/json");
		var result = await this.client.PostAsync($"url", stringContent, CancellationToken.None);
		return Ok(result);
	}
}

O código é até simples. Agora, o teste unitário que permite você fazer o “mockar” a chamada PostAsync seria o seguinte:

public async Task DeveriaExecutarOSendAsyncAoMenosUmaVez()
{
	// assumindo o uso do Moq e xUnit
	var httpClient = new Mock();
	httpClient
	    .Setup(x => x.SendAsync(It.IsAny(), CancellationToken.None))
	    .ReturnsAsync(new HttpResponseMessage()
	    {
	        StatusCode = HttpStatusCode.OK,
	        Content = new StringContent("{}"),
	    }).Verifiable();

	var controller = new MeuController(
	    httpClient.Object
	);

	var criterios = new Criterios() { };

	var result = await controller.AlgumPost(criterios);

	httpClient.Verify(x => x.SendAsync(It.IsAny(), CancellationToken.None), Times.Exactly(1));
}

O teste acima passa com sucesso! Note que não estamos fazendo Mock do PostAsync, mas do SendAsync já que o primeiro não pode ser “mockado”, mas ele chama o segundo. Caso queira checar que a chamada tenha sido correta, basta usar o CallBack oferecido pelo Moq.

Mas e o Get/GetString/GetStringAsync?

O que fazer então com os Gets? Simples! Não os use! Digo isso com certeza pois há uma alternativa muito mais limpa para ele. O próprio Send/SendAsync!

O problema dos Gets é que não há um meio apropriado de tratar erros. Se o request falhar, uma Exception pode ser disparada ou não.

O substituto ideal seria o seguinte:

// ao invés disso
public async Task ObterConteudo()
{
	var resultado = await this.client.GetStringAsync("https://alguma.api.por.ai");
	return Ok(resultado);
}

// faça isso
public async Task ObterConteudo()
{
	var requestMessage = new HttpRequestMessage(HttpMethod.Get, "https://alguma.api.por.ai");
	var response = await this.client.SendAsync(requestMessage);

	if (response.IsSuccessStatusCode)
	{
	    var resultado = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
	    return Ok(resultado);
	}
	else
	{
	    return StatusCode((int)response.StatusCode, response.Content.ReadAsStringAsync().Result);
	}
}

Desta forma, o retorno dado ao cliente é muito mais “honesto” e de quebra, você ganha a oportunidade de testá-lo apropriadamente.
Bom proveito!

Código fonte da classe HttpClient:

https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs

Aqui uma implementação de código funcionando:

https://github.com/Tomamais/dotnet_mocking_httpclient