Leer datos de internet (servicios REST, APIs, páginas web) desde java
Existen muchos ejemplos en la red de como llevar esto a cabo, pero muchos están en inglés y algunos desfasados, así que voy a exponer como llevar a cabo esta tarea usando la librería de apache HttpComponents a través de unos ejemplos en java.
El primer ejemplo obtendrá un fichero XML correspondiente al RSS de la página web barrapunto:
public static void main (String[] args){
// Creación del objeto cliente que realizará las peticiones
HttpClient httpclient = new DefaultHttpClient();
// Creación del objeto petición
HttpGet httpget = new HttpGet("http://barrapunto.com/index.rss");
// Creación del objeto respuesta
HttpResponse response;
try {
// Ejecución de la petición y guardado de respuesta
response = httpclient.execute(httpget);
// Mostramos el resultado de la petición
System.out.println("Estado: "+response.getStatusLine().toString());
// Leemos los datos de la respuesta
HttpEntity entity = response.getEntity();
// Si hay datos la petición se hizo correctamente y procedemos a mostrarlos
if (entity != null) {
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
System.out.println("Datos: "+result);
instream.close();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
El segundo ejemplo obtendrá datos de la página moneytrackin.com a través de su API haciendo uso de autentificación:
public static void main (String[] args){
HttpClient httpclient = new DefaultHttpClient();
// Creamos un objeto que nos permita autentificarnos al acceder a una página restringida
// La contraseña está codificada en MD5 de acuerdo a los requerimientos de la API
((AbstractHttpClient) httpclient).getCredentialsProvider().setCredentials(
new AuthScope("www.moneytrackin.com", 80),
new UsernamePasswordCredentials("usuario", "abf44982818cc242f222e0c367ab1c55"));
HttpGet httpget = new HttpGet("http://www.moneytrackin.com/api/rest/getBalance");
HttpResponse response;
try {
response = httpclient.execute(httpget);
System.out.println("Estado: "+response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
System.out.println("Datos: "+result);
instream.close();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
El tercer ejemplo obtiene los mismos datos que el anterior, pero lo hace a través de una conexión segura SSL (que la API permite) también haciendo uso de autentificación:
public static void main (String[] args){
HttpClient httpclient = new DefaultHttpClient();
// Notar la el puerto especificado es el 443 correspondiente al servicio SSL
((AbstractHttpClient) httpclient).getCredentialsProvider().setCredentials(
new AuthScope("www.moneytrackin.com", 443),
new UsernamePasswordCredentials("usuario", "abf44982818cc242f222e0c367ab1c55"));
// También se cambia la URL por la segura, que comienza por 'https'
HttpGet httpget = new HttpGet("https://www.moneytrackin.com/api/rest/getBalance");
HttpResponse response;
try {
response = httpclient.execute(httpget);
System.out.println("Estado: "+response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
System.out.println("Datos: "+result);
instream.close();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Y el cuarto ejemplo muestra como autenticarse en una página a través de un formulario y poder hacer luego peticiones de otras páginas accesibles solo para usuarios registrados (ideal para webs que no tienen API disponible y la autentificación se hace con cookies, pero trabajoso por la cantidad de parseo del html a realizar). Utilizaré la web spritmonitor (que no tiene API de acceso) para ilustrarlo:
public static void main (String[] args){
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
// Esta página guarda la autentificación en una cookie, por ello lo primero es
// acceder a la web donde está el formulario de registro
HttpGet httpget = new HttpGet("http://www.spritmonitor.de/en/");
try {
response = httpclient.execute(httpget);
System.out.println("Estado: " + response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
entity = response.getEntity();
if (entity != null) {
// Consumimos los datos de la respuesta para liberar al cliente y poder hacer más peticiones
entity.consumeContent();
// Especificamos la url donde irán los datos al ejecutarse la acción SUBMIT junto con los datos de autentificación
// loginname y password se corresponden con el nombre de los fields en el formulario
HttpPost httppost = new HttpPost("http://www.spritmonitor.de/en/login.html?action=login&loginname=name&password=password");
response = httpclient.execute(httppost);
System.out.println("Estado: " + response.getStatusLine());
entity = response.getEntity();
if (entity != null) {
// Ya deberíamos estar autentificados, ahora podríamos acceder a cualquier parte del sitio web
// al que solo pueden acceder usuarios registrados
// Podríamos liberar el cliente...
entity.consumeContent();
// y acceder por ejemplo a la página de preferencias del usuario
HttpGet httpget2 = new HttpGet("http://www.spritmonitor.de/en/my_data.html");
response = httpclient.execute(httpget2);
System.out.println("Estado " + response.getStatusLine());
entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
System.out.println("Datos: "+result);
instream.close();
}
}
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Para el que se pregunte que hace la función convertStreamToString aquí va el código:
public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
Actualización 20/08/2009: si es necesario acceder a internet a través de un proxy, habría que añadir las siguientes líneas:
...
HttpClient httpclient = new DefaultHttpClient();
String proxy_ip="139.96.100.1";
int proxy_port = 80;
// La siguiente línea solo es necesario si el proxy requiere autentificación
((AbstractHttpClient) httpclient).getCredentialsProvider().setCredentials(new AuthScope(proxy_ip, proxy_port), new UsernamePasswordCredentials("username", "password"));
// Creamos el objeto proxy
HttpHost proxy = new HttpHost(proxy_ip, proxy_port);
// Establemecemos la propiedad correspondiente
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
...
Fuentes: romefort, httpclient tutorial y Praeda & Co
Posted on: Thursday, June 18, 2009 at 19:17 pm
programación. Puedes seguir las respuestas de esta entrada a traves de l feed RSS 2.0.
Puedes dejar una respuesta, o trackback desde tu propio sitio.










como investigo la forma en que se envian los parametro de login?
en tu caso utilizaste estos:
http://www.spritmonitor.de/en/login.html?action=login&;amp;amp;loginname=usuario&password=password.
[Responder]
sucotronic Reply:
March 11th, 2010 at 18:00 pm
@eltonyjefe, te recomiendo que uses la extensión Firebug de Firefox para poder verlos de manera clara y sencilla.
[Responder]
hola de nuevo, ok, mira eso lo estube analizando con el Opera, trae integrado una herramienta =, pero no logro dar con ese metodo.
lo analizare quiza este venga algo mejor que el de opera, aunque se ven =.
recuerdo que habia un add-on para firefox, que permitia modificar los datos enviados por post, justo antes de enviarlos, solo que no recuerdo cual es, kisa ese sirva, o no se. gracias, si no encuentro la soulucion, espero puedas ayudarme un poco mas, gracias
[Responder]
sucotronic Reply:
March 11th, 2010 at 19:27 pm
@eltonyjefe, tienes dos extensiones para hacer eso que indicas: UrlParams y Tamper Data.
[Responder]
se, el temData, xD.
ese era, ahora ya se como mandarlo, gracias. aunque aun no sirve jeje, con mas calma lo hare, gracias
[Responder]
March 11th, 2010 at 19:37 pmoye man, sere muy enfadoso, ps no me resulta, no logro entrar a una pagina de este modo que me intersa mucho.
me pregunto si es que me pudieras ayudar un poco?
si me podrias agregar al msn?? listoa@hotmail.com
[Responder]
sucotronic Reply:
March 12th, 2010 at 22:11 pm
@eltonyjefe, no pasa nada, a nadie muerden por preguntar
De todos modos hay algunas páginas que por temas de cookies y similares a veces no admiten este tipo de métodos para acceder a su contenido.
[Responder]
asdasd Reply:
April 6th, 2010 at 18:42 pm
@sucotronic, No funciona el código de “spritmonitor”. En la ultima llamada, la de acceso a los datos personales, no funciona, devuelve el código de acceso denegado.
¿cómo lo solucionarías?
[Responder]
sucotronic Reply:
April 6th, 2010 at 23:12 pm
@asdasd, arreglado, era un problema con los carácteres especials ‘&’. Ahora si te copias el código no debería darte problemas.
no logro hacer lo mismo con filmaffinity.com y no sé por qué es. Hago exactamente lo mismo y nada. ¿Puedes probarlo?
Muchas gracias
[Responder]
April 7th, 2010 at 9:50 amHola,
Muy buen artículo! una vez que tenemos la respuesta html de una web que no tiene API, ¿Cúal es el mejor método para parsear el HTML y extraer los elementos deseados? ¿Expresiones regulares, almacenarlo en algún objeto que disponga de métodos para ello, o alguna otra alternativa? ¿Qué diferencia tendriamos entre el HttpEntity y el HttpResponse?
Muchas gracias.
Saludos!
[Responder]
sucotronic Reply:
November 9th, 2010 at 15:34 pm
@Jose A., la elección de un parseador java de HTML da material para hacer otro artículo. Yo no los he usado mucho, pero aquí puedes encontrar una relación de los existentes:
http://java-source.net/open-source/html-parsers
La diferencia entre un Entity y un Response es que una clase define el tipo de objeto que devuelve la otra. Puedes mirar la documentación oficial de apache httcomponents acerca de HttpEntity.
[Responder]
Jose A. Reply:
November 9th, 2010 at 16:23 pm
@sucotronic, muchas gracias por la rápida respuesta. Concretamente deseaba parsear el HTML en Android, así que seguiré investigando a ver qué es mejor usar.
Entre las diferencias que creo haber entendido;
HttpResponse almacena toda la respuesta que manda el servidor (headers del navegador + contenido de la web html/xml/javascript/…)
Con HttpResponse.getEntity() obtenemos solo el contenido de la web, que resulta ser del tipo HttpEntity
¿Acierto o me equivoco?
¿Qué pasa si no se realiza HttpEntity.consumeContent()?
[Responder]
sucotronic Reply:
November 9th, 2010 at 17:05 pm
@Jose A., has acertado
Respecto al consumeContent puedes ver en la página del API que es importante hacerlo sobretodo para poder reutilizar las conexiones, porque sino se crearía una nueva con cada petición que se hiciese (vamos para gestionar los recursos de forma eficiente).
Ok! Muchas gracias por la info.
Por si a alguien le es de utilidad, para parsear HTML en Android, quizás le sirva esto http://thinkandroid.wordpress.com/2010/01/05/using-xpath-and-html-cleaner-to-parse-html-xml/
Saludos!
[Responder]
November 9th, 2010 at 17:24 pm