Determinadas aplicações necessitam efetuar login em sites da Web para obter dados ou interagir com o site. Podemos listar uma série de utilidades:

  • extração de dados;
  • robôs;
  • web semântica;
  • automação.

Veremos nesse artigo como efetuar essa tarefa em Java, a partir do uso do HttpClient.

Baixando o Http Components da Apache

O download do Http Components é feito a partir do site: Apache.org.

A versão utilizada nesse exemplo é o 4.2.3.

Exemplo de Uso: site da DevMedia

Efetuaremos o login automático no próprio site da devmedia:

Área de Login do site
Figura 2. Área de Login do site

No site da DevMedia temos os campos de login e senha, além do botão ok que irá submeter os dados ao servidor, que por sua vez, irá validar ou não o acesso.

Este plugin monitora e analisa toda a comunicação HTTP feita entre o browser e as aplicações servidoras que ele acessa.

Instale o plugin e reinicie o Firefox. Ele agora poderá ser usado para ajudar a descobrir os dados que precisamos para efetuar o login automático.

Para ativar o HttpFox, acesse o Menu ToolsWeb DeveloperHttpFoxToggle HttpFox.

Ativando HttpFox
Figura 3. Ativando HttpFox

Depois de ativado, o Firefox ficará assim:

Interface do HttpFox
Figura 4. Interface do HttpFox

Ao clicar no botão Start, o HttpFox irá começar a monitorar todas as interações do browser com o servidor. Portanto, informe login e senha, pressione o botão ok. Após isso, clique no botão Stop do HttpFox.

Monitorando interações com o servidor
Figura 5. Monitorando interações com o servidor

Observe que o HttpFox gravou todas as interações que efetuamos (entre pressionar o botão Start e o botão Stop). Uma dessas ações é justamente o login, que está destacada na linha com realce em azul.

Repare que na Aba Headers, temos a informação da URL de login, /login/login.asp, e o tipo de requisição, no caso POST. Na aba POST Data, descobrimos quais são as informações que foram enviadas no POST:

  • usuario = xxx
  • senha = xxx
  • ac = 1

Na aba POST Data, vemos o nome dos parâmetros que são realmente enviados ao servidor. Portanto, para efetuar o login na DevMedia, temos que:

  • enviar o atributo usuario preenchido;
  • enviar o atributo senha preenchido;
  • enviar o atributo ac com valor “1”;
  • URL de login: www.devmedia.com.br/login/login.asp.

Tendo essas informações em mãos, podemos construir nossa aplicação Java:


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/**
 *
 * @author marcelo
 */
public class NavegadorSite {

    private final DefaultHttpClient client = new DefaultHttpClient();

    /**
     * Efetua login no site
     * @param url - URL de Login do site
     * @param user - usuario
     * @param password - senha
     * @return true - login ok | false - login fail
     * @throws UnsupportedEncodingException
     * @throws IOException 
     */
    public boolean login(final String url, final String user, final String 
    password) throws 
    UnsupportedEncodingException, IOException {

        /* Método POST */
        final HttpPost post = new HttpPost(url);
        boolean result = false;
        
        /* Configura os parâmetros do POST */
        final List<NameValuePair> nameValuePairs =
                new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("usuario", user));
        nameValuePairs.add(new BasicNameValuePair("senha", password));
        nameValuePairs.add(new BasicNameValuePair("ac", "1"));
        
        /* 
         * Codifica os parametros.
         * 
         * Antes do encoder: fulano@email.com
         * Depois do enconder: fulano%40email.com
         */        
        post.setEntity(new UrlEncodedFormEntity(nameValuePairs, Consts.UTF_8));        
           
        /* Define navegador */
        post.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 5.1; rv:18.0) 
        Gecko/20100101 Firefox/18.0");
        
        /* Efetua o POST */
        HttpResponse response = client.execute(post);
        
        /* Resposta HTTP: Sempre imprimirá “HTTP/1.1 302 Object moved” 
        (no caso da devmedia) */
        System.out.println("Login form get: " + response.getStatusLine());
        
        /* 
         * Consome o conteúdo retornado pelo servidor
         * Necessário esvaziar o response antes de usar o httpClient novamente
         */
        EntityUtils.consume(response.getEntity());

        /* 
         * Testar se o login funcionou.
         * 
         * Estratégia: acessar uma página que só está disponível quando se está logado
         * Em caso de erro, o servidor irá redirecionar para a página de login
         * A pagina de login contem uma string: "Login DevMedia"
         * Se esta String estiver presente, significa que o login não foi efetuado com sucesso
         * 
         */
        final HttpGet get = new HttpGet("//www.devmedia.com.br/include/mynotes.asp");
        response = client.execute(get);        
        
        /*
         * Verifica se a String: "Login DevMedia" está presente
         */
        if (checkSuccess(response)) {
            System.out.println("Conexao Estabelecida!");
            result = true;
        } else {
            System.out.println("Login não-efetuado!");
        }

        return result;
    }

    /**
     * Abre página
     * @param url - Página a acessar
     * @throws IOException 
     */
    public void openPage(final String url) throws IOException {
        final HttpGet get = new HttpGet(url);
        final HttpResponse response = client.execute(get);
        saveHTLM(response);
    }

    /**
     * Encerra conexão
     */
    public void close() {
        client.getConnectionManager().shutdown();
    }
    
    /**
     * Busca por String que indica se o usuário está logado ou não
     * @param response
     * @return true - Não achou String | false - Achou String
     * @throws IOException 
     */
    private boolean checkSuccess(final HttpResponse response) throws IOException {
        final BufferedReader rd = new BufferedReader(new InputStreamReader(
                response.getEntity().getContent()));
        String line;
        boolean found = false;
        /* Deixa correr todo o laco, mesmo achando a String, para consumir o content */
        while ((line = rd.readLine()) != null) {
            if(line.contains("Login DevMedia")) {
                found = true;                
            }
        }
        return !found;
    }
    
    /**
     * Salva a página
     * @param response
     * @throws IOException 
     */
    private void saveHTLM(final HttpResponse response) throws IOException {
        final BufferedReader rd = new BufferedReader(new InputStreamReader(
                response.getEntity().getContent()));
        String line;
        File arquivo = new File("c:\\arquivo.html");
        PrintWriter writer = new PrintWriter(arquivo);        
        while ((line = rd.readLine()) != null) {
            System.out.println(line);
            writer.println(line);            
        }        
        writer.flush();
        writer.close();
    }

    /**
     * Roda aplicação
     * @param args 
     */
    public static void main(String[] args) {

        NavegadorSite navegador = new NavegadorSite();

        try {
            // Tenta efetuar login
            boolean ok = navegador.login("//www.devmedia.com.br/login/login.asp"
            , "<login>", "<senha>");
            if (ok) {
                // Acessa página restrita
                navegador.openPage("//www.devmedia.com.br/include/mynotes.asp");
            }
            navegador.close();
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
Listagem 1. Navegador de linha de comando

Devemos adicionar as seguintes dependências ao projeto:

  • httpclient-4.2.3.jar;
  • httpcore-4.2.2.jar;
  • commons-codec-1.6.jar;
  • commons-logging-1.1.1.jar.

Observe que tivemos que configurar o header do POST, no caso, setando o User-Agent. Todas as informações de Header podem ser obtidas no HttpFox.

Através do método saveHTML, podemos ver se determinada página acessada está realmente correta. Para um melhor uso, o método openPage poderia receber um segundo argumento, indicando onde salvar a página.

Conclusão

Efetuar login em sites usando HttpClient é relativamente simples. O exemplo acima foi adaptado para funcionar particularmente com o site da DevMedia, porém, com algumas alterações, é possível utilizar o código para outros sites também (o código foi testado com outros sites, usando o HttpFox para descobrir os parâmetros a serem enviados).

O HttpClient também está disponível para a plataforma Android, o que permite usar a mesma estratégia.