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:
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 Tools – Web Developer – HttpFox – Toggle HttpFox.
Depois de ativado, o Firefox ficará assim:
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.
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();
}
}
}
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.