O uso de arquivos texto (TXT) foi, ou provavelmente ainda é, uma das formas mais conhecidas e utilizadas para comunicar diferentes tipos de aplicação. Imagine um cenário, por exemplo uma empresa A usando um sistema em .NET, que precisa enviar informações sobre parcelas geradas para um sistema B legado, escrito em Clipper ou Cobol. O uso de TXT é inevitável.

Mas um personagem estava para surgir e mudar esse cenário. Se o leitor já está pensando no termo XML, acertou. Podemos dizer que o XML estende o formato TXT, já que também é expresso em forma textual, porém tem duas grandes diferenças: 1) Expõe seus dados em um formato mais lógico e hierárquico; 2) Existem inúmeros parsers prontos para processar arquivos XML.

A tendência é que a comunicação entre sistemas heterogêneos seja feita através de XML, já que esse é um formato amplamente aceito e padronizado. E quando se fala em comunicar aplicativos via XML de forma on-line, então entra outra nova (e nem tão nova assim) e importante tecnologia: Web Services (chamado a partir daqui simplesmente de WS).

Por exemplo, imagine um cenário onde construímos um sistema para uma agência de turismo. Poderíamos integrar em nosso WebSite uma consulta on-line via WS aos sites das companhias áreas que oferecem as passagens mais baratas para o horário desejado pelo cliente.

Em vez de entrarmos site por site de cada companhia, nosso sistema faz isso automaticamente via WS (ou usando a técnica que veremos neste artigo). E poderia integrar com outro WS para já disponibilizar ao cliente um hotel próximo ao local de chegada que tenha disponibilidade para um horário X. Tudo automático!

Seria uma maravilha se tudo o que precisássemos integrar em nosso sistema pudesse ser obtido através da comunicação via WS. É bem mais simples receber dados em XML e processá-los com um parser (através das classes do .NET).

Mas a realidade mostra um cenário totalmente diferente. Quase tudo o que vemos é baseado em HTML (browser) e não XML, o que significa que para usar determinado serviço de outra empresa, você precisa abrir um browser, preencher informações e consultar. Isso dá um fim ao processo que precisaria ser feito de forma automática. Ou, pelo menos, deveria até você ler este artigo.

Quando usamos um browser para utilizar um serviço de uma empresa, estamos usando o que chamamos de intercâmbio B2C. O usuário final é responsável por obter a informação de um browser que recebe HTML.

Quando a comunicação é feita de forma automática por um sistema via WS e XML, e o usuário final acessa o serviço via nossa aplicação e não diretamente o serviço, dizemos que a comunicação é feita através de B2B.

Por exemplo, se você acessa o site da DevMedia para comprar edições de revistas anteriores que por ventura não tenha em sua coleção, está usando o B2C. Se está, por exemplo, usando o WS dos Correios (veja edição 36) para exibir dados de endereço do cliente em seu sistema, está usando B2B.

Mas onde quero chegar com toda essa introdução? O fato é que precisamos cada vez mais construir aplicações B2B para agregar funcionalidades as nossas aplicações, porém, infelizmente, a maioria das coisas que encontramos hoje na Web não são disponibilizadas na forma de WS (B2B), mas somente para usuários finais através de um browser HTML (B2C). O que nos resta é criar um mecanismo para usar serviços B2C como se fossem B2B.

Criando solicitações HTTP

A solução apresentada neste artigo consiste em fazer via código o que um usuário faria normalmente via Web Browser. Ou seja, podemos usar em nossas aplicações serviços disponibilizados não como WS, mas em forma de Web Sites. Como os dados trafegam sobre o HTTP em formato HTML, e não XML, é preciso realizar um trabalho extra e “braçal”.

Imagine um usuário preenchendo um cadastro em um Web Site, onde ele informa os campos em um formulário e clica em um botão Gravar. Considere que você precisa transferir todos os registros da sua base de clientes para esse Web Site.

O que fazemos é, para cada registro, preencher os dados do formulário programaticamente e emitir um comando ao Web Site para clicar no botão Gravar. Ou seja, estamos fazendo tudo via código.

Estamos simulando o papel de um browser, criando uma requisição HTTP no braço (através da classe WebRequest do .NET, do namespace System.Net) e obtendo o valor de retorno. Aplicações desse tipo também são conhecidas como robots.

Como o valor de retorno é HTML, e não XML, normalmente o tráfego de dados será bem mais intenso, visto que em HTML trafegam não somente dados, mas informações de layout, banners, figuras, que normalmente não são necessárias em uma aplicação B2B. Além disso, é preciso fazer o parse manual do arquivo HTML de retorno, procurando linha a linha (ou tag a tag) por um valor desejado.

Os exemplos demonstrados neste artigo são bastante interessantes e vão deixar mais clara a ideia aqui proposta, que se usada com sabedoria, poderá agregar um valor muito grande as suas aplicações Web ou mesmo Desktop.

As aplicações aqui construídas serão do tipo Windows Forms, mas podem facilmente serem feitas utilizando-se ASP.NET Web Forms, caso queira.

Nota: Não é o objetivo deste artigo demonstrar exemplos para uso ilícito da tecnologia, como fazer mau uso de serviços oferecidos por empresas, sobrecarregar servidores - D.O.S, preencher cadastros com dados falsos, burlar votações on-line, fazer spam automático etc.

O objetivo único e principal aqui é mostrar como você pode integrar suas aplicações com Web Sites que forneçam serviços úteis.

Nota: Como aplicações Web são totalmente dinâmicas, e pelo fato dos exemplos fazerem parse manual do código HTML, é possível que deixem de funcionar caso o fornecedor do serviço modifique por algum motivo o seu layout ou simplesmente o endereço da página.

No entanto, no endereço para download deste artigo, você sempre encontrará versões atualizadas e funcionais para os exemplos aqui apresentados.

Obtendo dados da Web via código

Neste primeiro exemplo, veremos como obter (GET) os dados vindos de uma página. Esse é um aplicativo mais simples, pois não será necessário passar nenhum parâmetro em forma de campo para o servidor. Como exemplo, vamos obter a cotação on-line do dólar.

Em uma nova aplicação Windows Forms, desenhe o formulário mostrado na Figura 1. Nele temos um Button, um TextBox chamado tbResponse e um Label (lbResultado).

Formulário para exibir o valor do dólar
Figura 1. Formulário para exibir o valor do dólar

O lbResultado vai exibir a cotação atual do dólar obtida a partir do site. O TextBox não tem funcionalidade para o usuário final, ele apenas ajudará a visualizar o conteúdo de retorno ( Response) retornado do servidor Web. No Click do botão apenas chamamos o método DoRequest (Listagem 1).

using System.Net;
 using System.IO;
 ...
 private void DoRequest()
 {
  //cria uma requisição para a URL
  WebRequest rq = WebRequest.Create(
  "http://br.invertia.com/mercados/divisas");
  //obtém a resposta
  HttpWebResponse rp = 
  (HttpWebResponse)rq.GetResponse();
  //obtém um stream contendo a resposta
  //retornada pelo servidor
  Stream ds = rp.GetResponseStream();
  //cria um StreamReader para leitura
  StreamReader rd = new StreamReader(ds);
  //lê o conteúdo
  string ct = rd.ReadToEnd();
  //atribui o resultado ao textBox
  tbResponse.Text = ct;
  //fecha os objetos
  rd.Close();
  ds.Close();
  rp.Close();
  //exibe o resultado
  lbResultado.Text = "R$ " + ExtractDolar(ct);
 }
Listagem 1. Criando uma requisição HTTP no braço

Os códigos estão todos comentados para um melhor entendimento. Veja que estamos criando uma requisição HTTP no braço, como se fosse o usuário acessando a página. Isso é feito através da classe WebRequest.

Note que, contrariando o padrão do .NET, criamos um objeto WebRequest com o método Create e não com o operador new do C#. A seguir, fazemos um GET para obter o valor de retorno para a página passada como parâmetro no Create do WebRequest.

O valor do Response (variável rp), que é a resposta / retorno, nada mais é que a própria página HTML que seria enviada a um browser. Para fazer a leitura desse Response, precisamos de um StreamReader, que obterá o conteúdo do Response e guardará na variável ct (o Content). A seguir fechamos os objetos utilizados.

Após a requisição, exibimos o valor do conteúdo retornado no TextBox, que é o código HTML. O próximo passo é buscar no HTML puro o que estamos procurando, um processo bastante braçal já que estamos trabalhando com HTML e não XML.

O código da função ExtractDolar obtém o valor do dólar a partir do HTML de retorno. A técnica é simples, procuramos por algo fixo no HTML e a posição relativa do que buscamos comparado a esse valor fixo. Esse é um procedimento que você deve fazer examinando o HTML retornado.

Nesse caso, o valor do dólar está 16 posições após o elemento DOLCM e tem tamanho 6. Não fique apavorado com o nível do “hard-coded”, essa é uma das formas mais utilizadas para fazer o parse em um HTML (ou o DOM, dependendo do formato HTML). A função é mostrada na Listagem 2.

private string ExtractDolar(string text)
 { 
  //procura por indexador fixo
  int i = text.LastIndexOf("DOLCM");
  //incrementa deslocamento
  i += 16;
  //captura o texto
  return text.Substring(i, 6);
 }
Listagem 2. Extraindo o dólar do Response

Executando a aplicação (não esqueça de colocar a chamada a DoRequest no botão), já podemos ver a cotação on-line do dólar (Figura 2).

Cotação do dólar obtida on-line
Figura 2. Cotação do dólar obtida on-line
Nota: Mesmo que exista na Web um site que disponibilize os serviços aqui demonstrados via WS, não é o objetivo deste artigo usar esse mecanismo.

Preenchendo formulários automaticamente

Uma variação deste primeiro exemplo é obter dados da Web onde há a necessidade de primeiramente se preencher um formulário. O valor de retorno é variável, e depende do que o usuário informou no formulário.

Como exemplo, vamos usar o serviço de tradução disponibilizado pelo site Google, o Google Translate. Novamente, não importa aqui se existe um WS para obter o mesmo resultado, o que quero mostrar é como preencher forms automaticamente e fazer o parse do valor de retorno.

Em uma nova aplicação Windows Forms, desenhe o formulário mostrado na Figura 3. Nele temos um Button, dois TextBoxes chamados tbTexto e tbResponse, um Label (lbResultado) e um ComboBox (cmbTraduzir), além dos Labels apenas para indicarem a função de cada controle.

Formulário para tradução on-line
Figura 3. Formulário para tradução on-line

O usuário vai digitar no primeiro TextBox o valor que deseja traduzir, no ComboBox ele escolhe se deseja traduzir de Português > Inglês ou Inglês > Português(coloque esses valores na sua propriedade Items) e no Label de resultado mostramos o valor da tradução, após o clique no botão.

Não vamos neste exemplo exibir o HTML, caso queira, faça como no primeiro exemplo. O botão chama o DoRequest (Listagem 3).

using System.Net;
 using System.IO;
 ...
 private void DoRequest()
 {
  //cria uma requisição para a URL
  WebRequest rq = WebRequest.Create(
  "http://translate.google.com/translate_t");
  //verifica a seleção do usuário para a tradução
  string Conversao;
  if (cmbTraduzir.SelectedIndex == 0)
  Conversao = "pt|en";
  else
  Conversao = "en|pt";
  //preenche os campos do post
  string fields = "text=" + tbTexto.Text + 
  "&langpair=" + Conversao;
  //vamos dar um POST ao invés de GET
  rq.Method = "POST";
  //coloca os campos em um array de bytes
  byte[] bytes = Encoding.ASCII.GetBytes(fields);
  //configura o tamanho do content do request
  rq.ContentLength = bytes.Length;
  //obtém um stream usado para o request
  Stream st = rq.GetRequestStream();
  //escreve no stream os campos e fecha
  st.Write(bytes, 0, bytes.Length);
  st.Close();
  //obtém o response a partir do request
  HttpWebResponse rp = 
  (HttpWebResponse)rq.GetResponse();
  //obtém um stream contendo a resposta
  //retornada pelo servidor
  Stream ds = rp.GetResponseStream();
  //cria um StreamReader para leitura
  StreamReader rd = new StreamReader(ds);
  //Faz a leitura
  string responseFromServer = rd.ReadToEnd();
  //fecha os objetos
  rd.Close();
  ds.Close();
  rp.Close();
  //exibe o resultado
  lbResultado.Text = 
  ExtractTranslation(responseFromServer);
 }
Listagem 3. Processando a requisição de tradução

O final do código é o mesmo do primeiro exemplo, de forma que vou me deter na explicação da primeira parte da listagem. Tudo está comentado, para um fácil entendimento.

Após configurar o Request, testamos o valor escolhido para tradução no ComboBox. A seguir, no objeto WebRequest, configuramos seu método (Method) para POST, pois vamos postar dados em um formulário.

Ainda no WebRequest, precisamos enviar os respectivos Fields, que nada mais são que os campos do formulário. No caso da tradução do Google, é o campo que indica o tipo de tradução a ser feita e o texto a ser traduzido. Note que para isso usamos um array de bytes e passamos como parâmetro para o Write do objeto Stream.

O método ExtractTranslation extrai o conteúdo da tradução a partir da string de retorno, e é mostrado na Listagem 4. O resultado da aplicação em execução é mostrado na Figura 4.

private string ExtractTranslation(string text)
 {
 // procura por indexador fixo
  int i = text.LastIndexOf("id=result_box");
  // incrementa deslocamento
  i += 22;
  // captura o texto
  int j = text.LastIndexOf("");
  return text.Substring(i, j-i);
 }
Listagem 4. Código do ExtractTranslation
Google dando uma mão na tradução
Figura 4. Google dando uma mão na tradução

Você pode facilmente adaptar este exemplo para outros tipos de formulários que tenham campos diferentes. Nesse caso, precisará apenas identificar, além da URL de postagem, que campos o form precisa receber como parâmetro.

Isso pode ser obtido verificando-se o código-fonte da página HTML, veja, por exemplo, na Figura 5 como obtivemos acesso aos campos do formulário de tradução.

Detalhes do formulário
Figura 5. Detalhes do formulário

Observe pela Figura 5 que podemos obter os detalhes do form, como a URL onde precisamos dar o POST. Note também que os campos ficam dentro do elemente form, uma boa dica para você procurar no extenso HTML quais os campos precisa fornecer, que nesse caso são dois, chamados de text e langpair.

Temperatura

Que tal exibir ao usuário as informações atualizadas sobre o tempo, na cidade onde ele mora. É o que vamos fazer neste último exemplo, um pouco semelhante ao anterior. Dos diversos sites que disponibilizam informações sobre o tempo em cidades brasileiras, o que escolhi para esta aplicação foi o https://weather.com/pt-BR (Figura 6).

Site Weather
Figura 6. Site Weather

O primeiro passo para obtermos os serviços do site é preenchermos seu form e examinarmos os códigos HTML de envio e de retorno. O que nos interessa obter está circulado na Figura 6. As informações que precisamos passar ao servidor estão no outro círculo, nesse caso, um único campo que é o nome da cidade que você deseja obter informações sobre o tempo.

Examinando o código HTML da página, o primeiro passo é procurar pela tag form, é ela que indica os campos que devem ser postados. Nesse caso, encontramos os campos da Figura 7, um chamado Text e outro oculto (hidden). É importante também detectar em que local devemos postar os dados, nesse caso consultamos o atributo Action do elemento form.

Estudando o comportamento da página
Figura 7. Estudando o comportamento da página
Nota: Se a página possuir múltiplos elementos forms, tenha o cuidado de escolher aquele que posta os dados que realmente deseja enviar, claro.

Estudado o comportamento da página, passamos para aplicação. Ela é semelhante as demais que criamos, de forma que não vou entrar em todos os detalhes do design do form. Você pode facilmente construí-lo baseando-se na Figura 8.

Form para obter informações sobre o tempo
Figura 8. Form para obter informações sobre o tempo

Os componentes que vão ser referenciados no código tiveram seus nomes padrão modificados, como mostra a figura. Além disso, bem abaixo do form, temos um PictureBox. O botão chama o método DoRequest, que pode ser visto na Listagem 5.

using System.Net;
 using System.IO;
 ...
 private void DoRequest()
 {
  //cria uma requisição para a URL
  WebRequest rq = WebRequest.Create( 
  "http://br.weather.com/search/search/");
  //preenche os campos do post
  string fields = "where=" + tbTexto.Text + "&what=";
  //configura o ContentType
  rq.ContentType = 
  "application/x-www-form-urlencoded";
  //vamos dar um POST ao invés de GET
  rq.Method = "POST";
  //coloca os campos em um array de bytes
  byte[] bytes = Encoding.ASCII.GetBytes(fields);
  //configura o tamanho do content do request
  rq.ContentLength = bytes.Length;
  //obtém um stream usado para o request
  Stream st = rq.GetRequestStream();
  //escreve no stream os campos e fecha
  st.Write(bytes, 0, bytes.Length);
  st.Close();
  //obtém o response a partir do request
  HttpWebResponse rp = 
  (HttpWebResponse)rq.GetResponse();
  //obtém um stream contendo a resposta
  //retornada pelo servidor
  Stream ds = rp.GetResponseStream();
  //cria um StreamReader para leitura
  StreamReader rd = new StreamReader(ds);
  //lê os dados
  string responseFromServer = rd.ReadToEnd();
  //fecha os objetos
  rd.Close();
  ds.Close();
  rp.Close();
  //exibe os resultados
  lblTemperatura.Text = 
  ExtractTemperatura(responseFromServer);
  lblStatus.Text = 
  ExtractStatus(responseFromServer);
  string URLImagem = 
  ExtractImage(responseFromServer);
  ConfigPictureBox(URLImagem);
 }
Listagem 5. Consultando o tempo

O código é praticamente igual ao do exemplo anterior, mudando somente o nome dos campos que precisamos enviar ao servidor. No final, exibimos as informações nos Labels, sendo elas a temperatura e uma descrição do tempo.

Os métodos usados no final do código, que fazem o parse do HTML de retorno e obtêm as informações desejadas, podem ser vistos na Listagem 6.

private string ExtractTemperatura(string text)
 {
  //procura por indexador fixo
  int i = text.IndexOf("obsTempText");
  //incrementa deslocamento
  i += 32;
  //captura o texto
  return text.Substring(i,2) + "ºC";
 }
 
 private string ExtractStatus(string text)
 {
  //procura por indexador fixo
  int i = text.IndexOf("obsText");
  //incrementa deslocamento
  i += 9;
  //captura o texto
  string Status = string.Empty;
  while (!(text[i].ToString() == "<"))
  {
  Status += text[i];
  i += 1;
  }
  return Status;
 }
 
 private string ExtractImage(string text)
 {
  //procura por indexador fixo
  string URL = 
  "http://image.weather.com/web/common/intlwxicons/52/";
  int i = text.IndexOf(URL) + URL.Length;
  //captura a URL
  while (!(text[i].ToString() == "."))
  {
  URL += text[i];
  i += 1;
  }
  return URL + ".gif"; 
 }
Listagem 6. Métodos para o parse das informações

Um método aqui merece especial atenção, o ExtractImage. O site em questão devolve um pequeno ícone indicando as condições do tempo na cidade pesquisada (tempo bom, nublado, chuva etc.).

O que obtemos como retorno é a URL para a imagem. Se estivéssemos usando ASP.NET para criar nossa aplicação, e quiséssemos exibir essa imagem, bastaria passar essa URL para um Image.

Porém estamos usando Windows Forms, e precisamos fazer uma nova requisição somente para pegar a imagem (o HTML não permite embutir imagens no código), então precisamos de um novo método.

É o que faz o ConfigPictureBox (Listagem 7). Basicamente criamos um Request e guardamos o retorno em um Response, que é a imagem. Usando um FileStream, salvamos a imagem no disco.

private void ConfigPictureBox(string URL)
 {
  //cria uma requisição para a imagem
  WebRequest rq = WebRequest.Create(URL);
  //cria um response
  HttpWebResponse rp =
  (HttpWebResponse)rq.GetResponse();
  //cria um stream a partir do response (imagem)
  Stream ds = rp.GetResponseStream();
  //cria um filestream para gravar a imagem no disco
  FileStream fs = new FileStream("Img.gif",
  FileMode.Create);
  //aloca um buffer
  byte[] buffer = new byte[512];
  int byteCount;
  do
  {
  //escreve no buffer e salva 
  byteCount = ds.Read(buffer, 0, 512);
  fs.Write(buffer, 0, byteCount);
  } 
  while (byteCount > 0);
  //fecha objetos
  fs.Close();
  ds.Close();
  rp.Close();
  //carrega a figura
  pictureBox1.Load("Img.gif");
 }
Listagem 7. Método ConfigPictureBox

A aplicação final em execução é mostrada na Figura 9.

Frio e tempo bom em Porto Alegre
Figura 9. Frio e tempo bom em Porto Alegre

Conclusão

Agora você já pode integrar sua aplicação com os mais variados tipos de Web Sites, basta usar a imaginação. Por exemplo, por aqui já criamos um aplicativo que se comunica com o Twitter, enviando scraps e obtendo informações sobre contatos.

Também uma aplicação que a partir dos dados do cliente, exibe um mapa com a localização exata da quadra, rua e número. Colocamos esse último disponível para download. Tudo usando preenchimento programático de formulários.

É bem provável que alguns dos serviços aqui demonstrados estejam disponíveis via WebServices, mas conforme comentei, o objetivo e propósito deste artigo foi considerar esses sites como modelos, como objetivo de estudo, para que agora você possa criar seus próprios aplicativos que consomem serviços baseados em Web Sites. Quem sabe até mesmo a ideia exposta na introdução deste artigo.

Bom, eu não tenho dúvida que precisaria de um outro artigo – ou talvez a revista inteira, sem exagerar – só para listar a imensidão de possibilidades do que pode ser feito com o que foi demonstrado nestes exemplos. Toda a Web está nas mãos do seu código.

Agora use a imaginação, expresse-a no código e veja os resultados. Bom proveito e até a próxima!

Confira também