Carregar dados de tabelas HTML - Delphi


 

 

Olá amigos do The Club, este mês traremos a vocês uma dica que pode ser de grande utilidade. Atualmente é cada vez mais necessário que nossos sistemas realizem leituras de outras fontes de dados como, por exemplo, planilhas do Excel, arquivos XML, arquivos de texto e outros formatos. Este recurso evita que os usuários tenham que alimentar manualmente as informações de cadastro (em alguns casos é claro), por exemplo, além de garantir a integridade dos dados, pois se tratando de um processo realizado pelo sistema pode-se tratar algumas regras de validações para que sejam inseridas apenas as informações pertinentes ao sistema.

Como o próprio título já diz, iremos construir nesta dica uma aplicação que irá realizar a leitura de um arquivo HTML, carregar os dados de uma tabela e armazená-los em uma tabela temporária.

Para exemplificar este recurso vamos criar primeiramente um arquivo HTML com algumas informações organizadas em uma tabela. Na listagem 1 temos um exemplo de um arquivo HTML, nesta dica estaremos utilizando este arquivo. Para salvar como HTML, basta abrir um editor de textos e salvar com a extensão HTM ou HTML.

 

 

<HTML>

<HEAD>
  <TITLE>The Club - Exemplo</TITLE>
</HEAD>

<BODY>
  <CENTER><FONT COLOR=BLUE SIZE=6>Produtos mais vendidos da marca Tal</FONT></CENTER>
  <BR />

  <TABLE ALIGN=CENTER BORDER=1 WIDTH=50%>
    <TR>       
      <TH>Cod. Barra</TH>     
      <TH>Nome</TH>     
      <TH>Quantidade</TH>     
      <TH>Valor R$</TH>     
    </TR>        
    <TR>       
      <TD ALIGN=CENTER>1234567891023</TD>
      <TD ALIGN=CENTER>Produto 1</TD>
      <TD ALIGN=CENTER>250</TD>
      <TD ALIGN=CENTER>5,25</TD>
    </TR>     
    <TR>       
      <TD ALIGN=CENTER>1234567891033</TD>
      <TD ALIGN=CENTER>Produto 2</TD>
      <TD ALIGN=CENTER>12</TD>
      <TD ALIGN=CENTER>125,41</TD>
    </TR>     
    <TR>       
      <TD ALIGN=CENTER>1234567891028</TD>
      <TD ALIGN=CENTER>Produto 3</TD>
      <TD ALIGN=CENTER>441</TD>
      <TD ALIGN=CENTER>11,23</TD>
    </TR>     
    <TR>       
      <TD ALIGN=CENTER>1234567891015</TD>
      <TD ALIGN=CENTER>Produto 4</TD>
      <TD ALIGN=CENTER>332</TD>
      <TD ALIGN=CENTER>2,99</TD>
    </TR>     
    <TR>       
      <TD ALIGN=CENTER>1234567891056</TD>
      <TD ALIGN=CENTER>Produto 5</TD>
      <TD ALIGN=CENTER>125</TD>
      <TD ALIGN=CENTER>7,85</TD>
    </TR>     
  </TABLE>
</BODY>

</HTML>

Listagem 1 – Arquivo HTML de exemplo

 

Neste exemplo temos uma tabela HTML simples com quatro colunas, listando informações sobre os produtos mais vendidos de determinada marca. É apenas um exemplo, pois podemos encontrar na internet alguns sites que disponibilizam variadas informações em tabelas HTML. Um exemplo é o site da Caixa, que disponibiliza downloads dos resultados de várias loterias em um arquivo HTML, organizado em uma tabela.

 

 

Mãos a obra

 

Abra o seu Delphi e crie um novo projeto. Salve-o com a nomenclatura que for mais apropriada. Para este exemplo estamos utilizando o Delphi 7, mas esta dica servirá também para as demais versões do Delphi, talvez precisando apenas de algumas adaptações, mas o contexto será o mesmo.

Temos que ter em mente que nossa aplicação irá fazer a leitura de um arquivo de texto escrito no padrão da linguagem HTML, e que neste caso específico temos uma tabela com precisamente quatro colunas, para outra situação o código terá que ser adaptado. Portanto iremos criar uma variável pública do tipo TextFile, para que possamos instanciar o arquivo em nosso sistema. Esta variável deve ser pública por que será acessada de métodos diferentes dentro da nossa unidade de trabalho. Irei utilizar neste exemplo a nomenclatura “ArqHTML” para esta variável.

Adicione ao formulário os seguintes componentes com seus respectivos nomes: três TPannel (pnTopo, pnLista, pnInfo), um TButton (btnImportarHTML), um TDBGrid (dbgLista), um TClientDataSet (cdsTemp) e um TDataSource (dsTemp). Disponibilize os componentes seguindo o exemplo da figura 1.

 

 

Exemplo tela
Figura 1 – Exemplo da tela do sistema

 

 

Tabela temporária

 

Podemos ver na figura 1 que os campos da tabela temporária já estão criados e de acordo com a ordem das colunas da tabela no arquivo HTML. Para criar uma tabela temporária clique com o direito do mouse no cdsTemp e acesse a opção “Fields Editor...”. Na janela que abrir clique com o direito do mouse e acesse a opção “New Field” ou pelas teclas de atalho “Ctrl + N” para inserir um novo campo ao cdsTemp. Será mostrada a janela “New Field” para preencher as propriedades do novo campo. Siga as informações da tabela 1 para inserir os quatro campos da tabela temporária.

 

Tabela 1
Tabela 1 – Propriedade dos campos temporários

 

Após criar os quatro campos verifique a ordem que eles estão dispostos, pois deve estar na mesma ordem que se encontram na tabela 1. Após, verificar a ordem dos campos, feche a tela “Fields Editor” e clique novamente com o direito do mouse no componente cdsTemp, acesse agora a opção “Create Dataset”. Pronto a nossa tabela temporária está criada e pronta para o uso. Vale lembrar que após a aplicação ser finalizada os dados contidos nesta tabela serão perdidos, portanto caso seja interessante persistir estas informações deve-se criar um método para inseri-las numa base de dados, ou apenas vincular o DataSet a algum componente de acesso a dados, mas este é outro assunto.

 

 

Leitura e importação dos dados

 

Para fazer o processo de leitura e importação dos dados iremos dividir as tarefas nos seguintes métodos:

  • GetNomeArquivoSelecionado – uma função que irá chamar uma janela do Windows para o usuário informar qual o arquivo a ser lido pelo sistema. O retorno desta função é uma string com o nome completo do arquivo;

  • CarregarArquivo – este método também é uma função. Ela se encarregará de instanciar o arquivo HTML em memória. Seu retorno será verdadeiro caso o sistema consiga carregar corretamente o arquivo, e falso caso o arquivo seja inválido;

  • LerArquivo – este método tem a função de varrer as linhas do arquivo, extrair o conteúdo das células e fazer as chamadas dos métodos InserirConteudo, GravarRegistro e VerificarRegistroInserido;

  • InserirConteudo – este método irá inserir o conteúdo no registro temporário do cdsTemp;

  • GravarRegistro – este método irá gravar o registro inserido;

  • VerificarRegistroInserido – este método faz uma verificação na tabela temporária para evitar que sejam inseridos registros duplicados;

  • ImportarDadosHTML – Este é o método principal. Ele ficará encarregado de chamar o método CarregarArquivo, LerArquivo e irá liberar o arquivo HTML da memória depois de finalizada a sua leitura;

Bem, depois de listados os métodos, vamos então a programação dos mesmos. Segue na listagem 2 a codificação dos métodos encarregados por instanciar o arquivo em memória na variável ArqHTML. Lembrando que as declarações destes métodos foram feitas na seção Private da Classe TfrmCarregaHTML (TForm).

 

 

function TfrmCarregaHTML.GetNomeArquivoSelecionado(DirIntial: String;
  const Filter: String): String;
var
  D: TOpenDialog;
begin
  // Retorna uma String o nome completo do arquivo selecionado.

  D := TOpenDialog.Create(Nil);
  D.InitialDir := DirIntial;
  D.Filter := Filter;
  D.Execute;
  Result := D.FileName;
  D.Free;
end;

function TfrmCarregaHTML.CarregarArquivo: Boolean;
var
  NomeArquivo, DirInicial, Filtro: String;
begin
  // Retorna False caso haja falha ao carregar arquivo e True caso tenha sucesso.

  Result := True;

  DirInicial := ExtractFilePath(ParamStr(0));
  Filtro := 'Arquivos HTML|*.htm*|Todos os Arquivos|*.*';
  NomeArquivo := GetNomeArquivoSelecionado(DirInicial, Filtro);

  if not FileExists(NomeArquivo) then
  begin
    Result := False;
    ShowMessage('Arquivo inválido ou nenhum arquivo informado.');
    Exit;
  end;

  AssignFile(ArqHTML, NomeArquivo);
end;

Listagem 2 – Codificação dos métodos de carregar o arquivo

 

 

A primeira função processo possibilita que o usuário informe um arquivo HTML. A segunda irá verificar se o arquivo selecionado pelo usuário é válido e somente irá carregar o arquivo na variável caso seja verdadeiro, e obviamente irá retornar para o procedimento que fez sua chamada com sucesso ou não para a instanciação do arquivo.
Veja na listagem 3 a codificação do método de leitura do arquivo.

 

 

procedure TfrmCarregaHTML.LerArquivo;
const
  TD_Abertura = '<TD';
  TABLE_Fechamento = '</TABLE>';
  TR_Fechamento = '</TR>';
  TD_Fechamento = '</TD>';
  LimiteColunas = 4;
var
  ColunaCorrente, ContaRegistro, Ini, Fim: Integer;
  Linha, LinhaUpper, Conteudo: String;
  LinhaDuplicada: Boolean;
begin
  // Faz a leitura e armazenamento das informações.

  ColunaCorrente := 0;
  ContaRegistro := 0;

  Reset(ArqHTML);
  while not Eof(ArqHTML) do
  begin
    Readln(ArqHTML, Linha);
    LinhaUpper := UpperCase(Linha);

    // Verifica a Tag TD (início e fim da célula) para extrair o conteúdo.
    if Pos(TD_Abertura, LinhaUpper) > 0 then
      if ColunaCorrente <= (LimiteColunas - 1) then
      begin
        Ini := Pos('>', LinhaUpper) + 1;
        Fim := Pos(TD_Fechamento, LinhaUpper);
        Conteudo := Copy(Linha, Ini, Fim - Ini);
             
        // A cada nova linha verifica se o Cod. Barra já existe.
        if (ColunaCorrente = 0) then
          LinhaDuplicada := VerificarRegistroInserido(ColunaCorrente, Conteudo);

        // Insere o registro apenas se não existe ainda na tabela.
        if not (LinhaDuplicada) then
          InserirConteudo(ColunaCorrente, Conteudo);

        Inc(ColunaCorrente);
      end;

    // Verifica a Tag TR (fim da linha) para gravar o registro.
    if Pos(TR_Fechamento, LinhaUpper) > 0 then
    begin
      if GravarRegistro then
        Inc(ContaRegistro);
      ColunaCorrente := 0;
    end;

    // Verifica a Tag TABLE (fim da tabela) para finalizar a leitura.
    if Pos(TABLE_Fechamento, LinhaUpper) > 0 then
      Break;
  end;

  ShowMessage(Format('Foram inseridos [ %d ] novos registros.', [ContaRegistro]));
end;

Listagem 3 – Codificação do método de leitura.

 

Este é um dos principais métodos. Ele ficou com a responsabilidade de ler o arquivo e extrair o conteúdo das células da tabela para fazer a chamada dos métodos de verificação, inserção e gravação dos registros. Repare que temos cinco constantes neste método. As quatro primeiras representam a abertura ou o fechamento de algumas Tags HTML, serão utilizadas para sabermos de quais linhas extrair as informações que precisamos, a última indica quantas colunas iremos ler da tabela, neste caso informamos 4.

Apesar de parecer complexo este método é bem simples. Logo de início inicializamos nos variáveis e já colocamos o ArqHTML em modo de leitura com o comando Reset. Após isso criamos um laço para varrer linha a linha o arquivo com a rotina “while not Eof(ArqHTML) do”. Dentro deste laço faremos três verificações, a primeira, se a linha atual trata-se de uma célula (TD); a segunda, se a linha atual trata-se de um fim de linha (TR); a terceira, se a linha indica o fim da tabela HTML (TABLE). São para estas verificações que utilizamos nossas contastes.

Para cada verificação temos uma ação a ser realizada. Se a linha for uma célula, iremos primeiramente verificar se a coluna está entre o intervalo indicado para a leitura, para isso utilizamos nossa contaste, logo depois iremos extrair o seu conteúdo para em seguida chamarmos o método VerificarRegistroInserido, que vai retornar para uma variável booleana, LinhaDuplicada, se é ou não duplicado. Com a informação desta variável, verificaremos se deve ou não ser inserido o conteúdo, ou seja, apenas se a variável for igual a falso, iremos chamar o método InserirConteudo, por fim iremos incrementar o contador de colunas. Se a linha atual indicar o fim de uma linha da tabela, iremos chamar o método GravarRegistro e incrementar o contador de registros. Se a linha atual indicar o fim da tabela iremos apenas parar o laço. Ao término do laço exibe-se uma mensagem ao usuário indicando a quantidade de novos registros inseridos na tabela temporária.
Veja na listagem 4 as codificações dos métodos de inserção, verificação e gravação dos conteúdos.

 

 

procedure TfrmCarregaHTML.InserirConteudo(IndiceColuna: Integer;
  Conteudo: String);
begin
  // Insere os dados na tabela temporária.
  // Lembrando que a ordem dos campos deve ser a mesma das colunas no HTML.

  if cdsTemp.State <> dsInsert then
    cdsTemp.Append;

  cdsTemp.Fields[IndiceColuna].AsString := Conteudo;
end;

function TfrmCarregaHTML.VerificarRegistroInserido(IndiceColuna: Integer;
  Conteudo: String): Boolean;
var
  NomeCampo: String;
begin
  // Retorna True caso o registro já tenha sido inserido.

  NomeCampo := cdsTemp.Fields[IndiceColuna].FieldName;
  Result := cdsTemp.Locate(NomeCampo, Conteudo, [loCaseInsensitive]);
end;

function TfrmCarregaHTML.GravarRegistro: Boolean;
begin
  // Grava as informações inseridas.

  Result := cdsTemp.State = dsInsert;
  if cdsTemp.State = dsInsert then
    cdsTemp.Post;
end;

Listagem 4 – Codificações dos métodos de inserção, verificação e gravação dos conteúdos

 

No método de inserção, verificamos o estado do cdsTemp, caso não seja de inserção, alteramos para o mesmo. Através dos dois parâmetros passados, IndiceColuna e Conteudo, fazemos a atribuição ao campo do cdsTemp. É justamente pelo fato de atribuirmos o conteúdo utilizando o índice da coluna que é importante a ordem dos campos seguirem a ordem das colunas da tabela HTML.

No método VerificarRegistroInserido fazemos uma busca do conteúdo a ser inserido no campo COD_BARRA (IndiceColuna = 0) através do método Locate do cdsTemp, o retorno desta função será Verdadeiro caso encontre alguma ocorrência na busca e Falso caso contrário.

No método de gravação, apenas iremos gravar caso o cdsTemp esteja em estado de inserção, pois em momento algum estamos editando a tabela. Assim pode-se dar um retorno Verdadeiro ou Falso, para o método que fizer a chamada desta função.

Veja na listagem 5 a codificação do método ImportarDadosHTML, que é o procedimento que irá fazer a chamada dos CarregarArquivo, LerArquivo e depois se encarregar de liberar o arquivo da memória.

 

procedure TfrmCarregaHTML.ImportarDadosHTML;
begin
  // Procedimento principal, o qual agrupa todas as operações de
  // leitura e processamento e gravação dos dados da tabela HTML.

  // Carrega o Arquivo. Caso haja falha, aborta o processo.
  if not CarregarArquivo then
    Exit;

  cdsTemp.DisableControls;

  // faz a leitura e importação dos dados.
  LerArquivo;

  cdsTemp.EnableControls;
  cdsTemp.First;

  // Fecha o arquivo.
  CloseFile(ArqHTML);
end;

procedure TfrmCarregaHTML.btnImportarClick(Sender: TObject);
begin
  // Faz a chamada do método principal de importação.

  ImportarDadosHTML;
end;

Listagem 5 – Codificação e chamada do método ImportarDadosHTML

 

Com este último método agrupamos todas as tarefas para fazer a importação dos dados da tabela HTML para nossa tabela temporária. Note que no evento OnClick do btnImportarHTML apenas fazemos a chamada do método ImportarDadosHTML. Veja na figura 2 o nosso exemplo em execução, note que as informações da tabela HTML já estão carregadas na tabela temporária.

 

 

Figura 2 - Execução do exemplo

Figura 2 – Exemplo em execução

 

 

Conclusão

 

Sabe-se que fazer importação de dados, independente do formato do arquivo de origem, é mais que necessário atualmente. Portanto, vimos aqui neste artigo uma das formas de fazer esta importação utilizando como fonte de informações uma tabela HTML. Procuramos dividir bem os métodos para facilitar o entendimento do que se passa em cada etapa do processo de importação.

Esperamos que este artigo seja de utilidade a vocês leitores. Um abraço a todos e até uma próxima.

 

 

Sobre o Autor

Lucas Vieira de Oliveira Consultor The Club

E-mail: suporte@theclub.com.br

The Club - O Maior Clube de programadores do Brasil