Categories
programación

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

42 replies on “Leer datos de internet (servicios REST, APIs, páginas web) desde java”

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

se, el temData, xD.
ese era, ahora ya se como mandarlo, gracias. aunque aun no sirve jeje, con mas calma lo hare, gracias

oye 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

@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.

@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?

@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

Hola,

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!

@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()?

@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).

Hola!!!!

Quería pedir ayuda si me podeis decir cual sería la versión final para esta línea, o si así ya está bien porque no me funciona.

HttpPost httppost = new HttpPost(“http://www.spritmonitor.de/en/login.html?action=login&;loginname=name&password=password”);

y donde tendría que poner mi usuario y mi password.

Gracias por todo.

@pedro, no tiene mala pinta la línea. Tendrías que sustituir en donde pones ‘name’ y ‘password’ (detras del igual).

@Pedro, en firebug hay una pestaña de red que te muestra las cabeceras que se envían a una web. Primero deberías apuntar todos los parámetros que se envían cuando se hace un uso normal de la web (login, consulta de datos…) y luego intentar replicar las peticiones en java 😛

@Pedro, hola Pedro. Para poder loguearte en algunas páginas web, es necesario enviar algunos datos adicionales con al petición de la página, como puede ser una cookie, o ciertos datos que se procesan en js. Te recomiendo investigar como funciona usando firebug(en firefox) on la consola de desarrollador (en Chrome).

Hola intente probar el ejemplo #4 para poder acceder a una pagina que solo los usuarios registrados tienen derecho.. pero al obtener con el “httpget” dicha pagina, que por cierto es un formulario, me manda otra pagina diciendo que necesito loguearme o la cookie hace falta =/.. De casualidad sabes porque ?

@Luis Moreno, hay muchas páginas que para gestioar el logueo de usuarios usan cookies y/o otros elementos, por lo que es más complejo loguearse y mantenerse autentificado.

Buenas amigo, muy buen post, tengo ganas de testear ese codigo y entenderlo a la perfeccion, me gustaria saber que metodo me recomiendas para poder obtener unos datos de esta pagina web.
http://contribuyente.seniat.gob.ve/BuscaRif/BuscaRif.jsp

La verdad ando bastando agotado buscando codigos, pero al fin veo que consegui algo en español “gracias al dios google”.

Mi idea es capturar solo el nombre que se genera al realizar una busqueda del RIF de la persona juridica, ej: J299191388 al ingresar eso me muestra unos datos y quiero capturar el nombre, “es posible?”. Quiero obtener ese nombre y guardarlo en una variable para poder utilizarlo en un formulario jFrame en java netbeans. Te agradesco mucho por el codigo, ire a analizarlo.

@Jose Martinez, la página que comentas parece sencilla de consultar. Necesitarías hacer una petición POST con el parámetro p_rif llevando el valor que tu quieres, y luego analizar la respuesta en busca de los datos que te interesan (te recomiendo usar jsoup para parsear la respuesta).

@sucotronic,

ok voy a volverme loco tratando, ya que soy nuevo en esto tendre que documentarme en jsoup y ir probando como funciona ya que de html y php no se mucho, necesitare verme despues algun cursito, y si el parametro es p_rif… lo vi en el codigo fuente de la pagina, tambien me fue util firebug, aunque no lo se usar mucho. Por como vi, el que me parecio mas util fue tu cuarto ejemplo… tratare de ver que saco de alli y entenderlo, no me gusta andar haciendo puro copy paste, pero como me quedan solo 2 semanas para entregar el trabajo tengo que apresurarme antes que se me consuma el tiempo.

Jajajaja, bueno aca ando, dandole al codigo de tu ejemplo 4, aunque me gustaria que esa libreria httpcomponents viniera con su javadoc integrado 🙁 leerlo desde la internet no provoca mucho. Por cierto seria de mucha ayuda que me explicaras este paso

HttpPost httppost = new HttpPost(“http://www.spritmonitor.de/en/login.html?action=login&;loginname=name&password=password”);

Quiero entender bien este paso, lo que viene despues del “;” son datos que nosotros manejamos?, es decir los parametros no?.
ejemplo loginname=misuario y password=mipassword?.

PD: Joder ojala hubiera gente como tu aca en venezuela por que ya estoy cansado de lo mismo, quiero aprender cosas nuevas.

@Jose Martinez,

Mmm, parece que no, revise en el firebug y vi que tienen un campo llamado value = “”, es posible setear mi id y password desde el programa en la peticion POST?, me podrias enseñar como? :). Disculpa por tantas preguntas, pero me parece un tema bastante bueno y quisiera dominarlo, lastima que aun no entiendo muy bien las otras funciones como response, entity y el consumecontent, el httpget lo entendi por que lo supuse jaja y ademas por que escribiste arriba un // y el client para una nueva conexion. Ya con mas tiempo me leerle el javadoc para detallarme mas.

Hola otra ves 🙂
Parece que esto me va a llevar tiempo como tu dices, la pagina http://contribuyente.seniat.gob.ve/BuscaRif/BuscaRif.jsp tiene datos que se procesan en js, que puedo hacer en este caso?.

“”<input id="p_rif" type="text" onblur="javascript:this.value=this.value.toUpperCase();" onchange="javascript:this.value=this.value.toUpperCase();" title="Ingrese su número de Rif, según Ejm " name="p_rif" maxlength="10" style="font-family: Verdana; font-size: 10;" alt="Rif del Contribuyente" "

sin las dos primeras comillas y sin la ultima comilla
ese es el codigo en donde se coloca el rif de la persona, es bastante diferente al de la pagina spritmonitor :(.

PD: Aun no logro autentificarme como usuario en esa pagina mediante el java :(. logre que en el segundo estatus me tirara Estado: HTTP 1.1 302 Found
pero el que me da problemas es el tercer Estado que dice Not Found. Mientras que el primero dice OK. El segundo tambien decia OK, pero probe varios metodos que busque por internet para setear valores en el POST, y parece que al menos surtio algo de efecto, ahora mi pregunta estare haciendo algo mal?, ya que probe ese codigo del ejemplo 4 pero me genera Estado 1 ok, estado 2 ok y estado 3 not found.
Y otra cosa, revise por Firebug, y no dice loginname dice username, afecta en algo eso?.

ufff amigo cuando puedas me hechas una manito :(… ando ahora agotado todo el dia tratando de implementar esto pero sobre la web que tu dijiste que parece sencilla T_T. Y no lo logro :(.
Cualquier cosa yo ando conectado todo el dia tratando de averiguar cada ves algo mas, e visto que algunos usan Postmethod pero me da la impresion que es una version vieja de HttpPost. T_T. Acepto cualquier ayuda. Gracias.

@sucotronic,

Uhmm vale :)… ya estoy pidiendo tambien consejos y ayudas en tres foros distintos, de hecho tu codigo del ejemplo 4 lo modifique un poco, debido a que parece que la misma pagina modifico su parametro login por username… y la pagina de my_data ahora es
http://www.spritmonitor.de/en/my_account.html
Tambien agrege el envio de parametros para que dijera “Found” en el 2 estado, mira…

HttpPost httppost = new HttpPost(“http://www.spritmonitor.de/en/login.html?action=login&;username=username&password=password”);
// Enviando parametros por httppost a la web.
// Aca segun lo que necesito, “Leer el foro” sobre lo del seniat, el parametro es:
// @params p_rif

ArrayList params = new ArrayList(2);
params.add(new BasicNameValuePair(“username”, “warrior4000”)); // mi username // Prueben cambiando algo aca y ejecuten el codigo.
params.add(new BasicNameValuePair(“password”, “wMJHq4A”)); // mi password
httppost.setEntity(new UrlEncodedFormEntity(params));
response = httpclient.execute(httppost);
System.out.println(“Estado: ” + response.getStatusLine());
entity = response.getEntity();

Asi fue como implemente el seteo de valores en el httppost… existen formas incluso con el Json… pero no las he probado, y seguramente es mas eficiente o capaz menos codigo que este.

**el tercer estado ya genera “OK”. El error estaba en que la pagina no la encontraba, asi que puse.
http://www.spritmonitor.de/en/my_account.html y cambio su estado.
Lo otro… como hacer para obtener solo una parte del codigo html con Json… de hecho no se ni usar Json Y__Y. Y no se que otras cosas de mas necesito para enviar parametros a paginas .jsp como mencionaste arriba en una respuesta a Pedro… Bueno gracias por responder :)… yo sigo pasando por aca cualquier cosa, de todos modos tu codigo es el que me abrio el principal camino a estos temas de http, “bueno en realidad habia visto muchos otros pero este era el mas actual y mas entendible a mi parecer”.

Buenas noticias… ahora necesito aprender es Json… para parsear el codigo html…
puedes ayudarme aca?. Todo este es el codigo.

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://contribuyente.seniat.gob.ve/BuscaRif/BuscaRif.jsp”);
try {
response = httpclient.execute(httpget);
System.out.println(“Estado: ” + response.getStatusLine().toString()); // Esto solo para comprobar los estados, los mas comunes 200 / 302 / 404
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
// p_rif se corresponde con el rif del field de la web.

HttpPost httppost = new HttpPost(“http://contribuyente.seniat.gob.ve/BuscaRif/BuscaRif.jsp;p_rif=p_rif”);
// Enviando parametros por httppost a la web.
// Aca segun lo que necesito, “Leer el foro” sobre lo del seniat, el parametro es:
// @params p_rif

ArrayList params = new ArrayList(2);
params.add(new BasicNameValuePair(“p_rif”, “J299191388”)); // mi username // Prueben cambiando algo aca y ejecuten el codigo.

httppost.setEntity(new UrlEncodedFormEntity(params));
response = httpclient.execute(httppost);
System.out.println(“Estado: ” + response.getStatusLine());
entity = response.getEntity();
if (entity != null) {

// De aqui en adelante por favor leer mi pregunta en el foro.
// Yo no se trabajar con Json y muchos dicen que es util para parsear codigo html, por ello les pido su ayuda.
InputStream instream = entity.getContent(); // Todo el codigo Html de la pagina.
String result= convertStreamToString(instream); // Leer el metodo convertStream mas abajo.
System.out.println(“Datos: “+result); // Mandamos a imprimir en un sout. todo el codigo html
instream.close();
// Como hacer para obtener al menos el nombre y no todo el codigo html?, esa es una de mis necesidades –
// en lo que respecta a lo del seniat.
// 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 aca es donde comienza el problema del parseo… es decir lo que quiero obtener del codigo html.
/// Leer el foro.
/// Supongo de aqui en adelante deberia usar Json, lamentablemente no me he documentado completo sobre Json.

}
} // Disculpen las except… me da flojera hacer unos propios en ejemplos :(.
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

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();
}

@Jose Martinez, me alegra ver que has conseguido hacer las peticiones y conseguir los datos que te interesan 🙂
Para parsear la respuesta lo mejor es que uses jsoup, que está diseñado específicamente para extraer datos de html, y será capaz de tolerar fallos semánticos. Un parseador de json solo te valdrá para datos en json, en otro tipo de casos te fallará.

@sucotronic,

Perfecto mil gracias jeje, bueno no se si me puedes ayudar con algo ultimo, mas bien ya logre un paso gigantesco.

pero necesito saber algo, despues del parseo es posible obtener solo el nombre?… lo que pasa es que el parseo al principio era gigante, pero me puse a leer el codigo y el javadoc y entendí su funcionamiento, ahora es pequeñito y especifico…pero, tiene un “____________________” + ” aqui va el rif ” + ” y luego aca el nombre “… no se si me entiendes..

Yo quiero el nombre nada mas para mandarlo a imprimir, mi pregunta es como?.

Nvm…. esta listo al 200%, muchisimas gracias por dejarme utilizar tu ejemplo 4 como comienzo a estos temas de conexiones a webs desde java ” que para mi eran nuevos 🙂 “… tambien muchas gracias por lo de Json, me fue bastante facil manejarlo ya que me adapte rapido a sus funciones.
Un saludo 😀

Muy buenas estoy con un problema que talves puedan ayudarme, me dieron como tarea leer informacion que me es enviada mediante un IP y un puerto especifico la cual tiene formato XML, lo que necesito saber es si los ejemplos que tienen arriba me permitiran recuperar esos datos o si pudieran indicarme algun lugar o sitio donde pueda darme una idea de que pasos seguir para recuperar los mismos. Una vez los pueda recuperar estos datos deben ser enviados a una base de datos.

Agradeceria mucho cualquier ayuda

Leave a Reply

Your email address will not be published. Required fields are marked *