lunes, 28 de julio de 2014

Web scraping para consultar contenido en paginas web ajenas, llenar formularios y capturar respuesta usando Java.





Saludos a todos.

La siguiente entrada resolverá las siguientes incógnitas:
  • ¿Cómo capturar el contenido de una pagina web usando Java?
  • ¿Cómo llenar con datos un formulario de una web ajena y enviar los datos usando Java?
  • ¿Cómo llenar con datos un formulario de una web ajena, enviar los datos y capturar la respuesta usando Java?
La solución a las anteriores dudas nos será de mucha utilidad si por ejemplo tienes muchos datos que deseas consultar en un formulario web y deseas automatizar dicha tarea.

Empecé a practicar web scraping sin saber que lo hacia, a mi esposa le encomendaron la tarea de consultar un poco mas de 1000 cédulas (dni en otros países) para determinar, mesa de votación, lugar y dirección donde debía realizar el sufragio para elección de senado y cámara en mi país Colombia, todo esto lo debía hacer desde una desde la pagina que el gobierno habilita http://wsr.registraduria.gov.co/servicios/elec-presidente2014.htm.

Mi esposa me solicitó ayuda para realizar la descomunal tarea, para mi dicha tarea es tediosa y representa perder mi tiempo en algo que no quería hacer, pesé que debía haber una forma de automatizar dicha tarea; así que con ayuda de mi amigo Google nos pusimos en la tarea de averiguar como hacer tal cosas.

Las sugerencia que encontramos nos dirigirían a que debía integrar un web browser a una aplicación Java, después de intentar con muchas librerías de las cuales la mayoría hacían el problema más grande, me quede con htmlunit.

¿Porque integrar un web browser? Mi idea era emular un navegador web y consultar dato por dato, pero aclaro que esto no lo haría yo, lo haría mi PC el cual no se aburre y hace esta tarea mucho más rápido que yo.

Hosting

Les dejo un vistazo de la aplicación funcionando.



Es hora de ver código,  le ofrezco uno muy básico y fácil de comprender que les ayudara a hacer cosas mas complicadas después; en el código emulé una consulta al buscador de Google.

package scraping;

import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author rey salcedo
 */
public class Scraping {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //emulamos un navegador web
        final WebClient webClient = new WebClient();

        try {
            //Pagina donde se hara la consulta
            HtmlPage page1 = webClient.getPage("https://www.google.com.co/search");
            
            //nombre del formulario
            final HtmlForm form = page1.getFormByName("f");
            //el valor "f" no es arbitrario es el nombre del formulario web de google
            
            //nombre de la caja de texto
            final HtmlTextInput textField = form.getInputByName("q");
            //el valor "q" no es arbitrario es el nombre de la caja de texto del formulario web de google

            //nombre del boton del formulario
            final HtmlSubmitInput button = form.getInputByName("btnG");
            //el valor "btnG" no es arbitrario es el nombre del boton del formulario web de google
                        
            //llenamos la caja de texto
            textField.setValueAttribute("usandojava");

            //Creamos la pagina que nos devolverá el resultado
            final HtmlPage pageResultado;
            
            //hacemos clic en el boton del formulario y asignamos el resultado a la pagina pageResultado
            pageResultado = button.click();
            
            //imprimimos el resultado
            System.out.println(pageResultado.asText());
            
            //cerramos el navegador emulado, para liberar todo esto de la memoria
            webClient.closeAllWindows();
        } catch (IOException ex) {
            Logger.getLogger(Scraping.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FailingHttpStatusCodeException ex) {
            Logger.getLogger(Scraping.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}




Advierto que para el caso del formulario de google no es estrictamente necesario llenar un formulario como lo he hecho, ya que solo bastas con un simple link https://www.google.com.co/search?q=usandojava


Para la consulta de los nombre de los componentes les sugiero que descarguen la pagina web donde está el formulario y como nota importante les sugiero de no usen chrome, mejor usen FireFox ya que chrome no me daba los nombres apropiados de los componentes del formulario, para la descarga de las librerías necesarias les dejo el link de la pagina oficial http://sourceforge.net/projects/htmlunit/files/htmlunit/



Como siempre esperando serles de ayuda.

No olviden comentar.





martes, 29 de abril de 2014

Aprendiendo a programar en java usando el valor de π(pi)





Saludos a todos.

Hace muchísimo tiempo cuando curioseaba el lenguaje Pascal y antes de dormir me puse a pesar en la geometría del circulo y recordé las clases de colegio donde me decían que el valor de pi no era mas que la longitud de la circunferencia dividida entre su diámetro.





Tenia presente que midiendo la circunferencia y el diámetro de un plato redondo por ejemplo solo hallaría un valor aproximado de pi, y que dicho valor más exacto sólo lo podían hacer los matemáticos y sus demostraciones, cosa que difícilmente lograría yo.

Siempre he sido regular en matemáticas, para algunos muy bueno, la verdad no lo creo; pero sí me consideraba mejor en la geometría y dibujo técnico.

De tanto pensar en círculos, matemática y geometría llego a mi una forma de hallar el valor de pi sin hacer demostraciones, gracias a que recordé que había leído en alguna parte la teoría que mas o menos dice "Un circulo es una figura geométrica con muchos lados que equidistan de un centro o eje"

Se me prendió el bombillo, me dije, tomare un cuadrado del cual conozco su diámetro y le agregare más lados calculado de los ya existentes sin cambiar el diámetro del mismo, es decir que el diámetro sera una constante; la suma de sus lados me darían el perímetro el cual dividiría por el diámetro y me daría el valor aproximado de pi, si hago esto muchas veces me acercaré cada vez más a pi; en otras palabras le agregare más lados al cuadrado tratando de convertirlo en un circulo.

Tome lápiz, cuaderno y comencé ha calcular, para el caso de un cuadrado de diámetro 1 los lados medirían 0,707106781, ya que según Pitágoras:

h^2 = co^2 + ca^2

Como para un cuadrado sus lados son igual, es decir sus catetos, nos quedaría:

h^2 = co^2 + co^2

h^2 = 2 * co^2

Sacamos raíces a ambos términos de cada igualdad

h = √2 * co

finalmente

co = h/√2

siendo la hipotenusa nuestro diámetro y remplazando...

co = 1/√2 = 0,707106781;

Listo ya tengo los datos de mi cuadrado, como los cuadrados tienen 4 lados el perímetro sería (0,707106781 * 4) = 2,828427125

Nuestro primer valor aproximado para pi seria:

2,828427125/1 = 2,828427125

2,828427125 es un valor muy distante al verdadero valor de pi; lo que sigue ahora es usando geometría agregarle más lados a figura y calcularlos sin cambiar el diámetro (1) y recalcular el valor de pi; en la practica debía recalcular miles de veces para llegar a un valor decente de pi.

Hosting

Tome nuevamente mi cuaderno y lápiz, y escribir un programa en Pasca (en esa época no tenia computador, así que me tocaba a papel y compilar en mi cabeza) para luego esperar el sábado que tenia nuevamente contacto con un computador; para sorpresa mía el día que pase mi programa a computador funciono sin problemas dándome el valor de pi tal cual una calculadora, estaba muy excitado al llegar muy cerca al valor de pi sin ser matemático.

Como mencione al inicio, eso paso hace mucho tiempo; y hoy que empece a recordar me ha sido duro reconstruir el programa, sospecho que es por mi pereza de hacer algo dos veces, así que investigue algo que me ayudara a recordar y me tope conque ya eso lo habían hecho Arquimedes y lo llamó Método exhaustivo, aunque mi método es ligeramente distinto, así que más pereza me da reconstruirlo, pero en un futuro lo haré para ustedes.

Pero como es costumbre escribir código en cada una de mis entradas, me tope con la Fórmula de Leibniz que no es más que una sumatoria que tiende al infinito y que es fácil programar.


//Autor Rey Salcedo
class FormulaLeibniz{
 public static double formula(int repeticiones){
  double pi = 0;
  for(int n = 0;n < repeticiones;n++){
   pi += ((Math.pow(-1,n))/(2*n + 1));
  }
  return pi*4;
 }
 public static void main(String[] args){
  System.out.println(formula(100000000));
 }
} 

Espero le sirva y les sea de agrado



jueves, 10 de abril de 2014

Conversión de binario a decimal, de decimal a binario y operaciones con números binarios


Conversión de binario a decimal, de decimal a binario y operaciones con números binarios.

El sistema numérico binario es muy importante para la computación debido a que los sistemas de computo actuales en su gran mayoría sólo pueden hacer operaciones aritméticas con unos y ceros, y cuando digo sistemas de computo no solo me refiero a PC de escritorio y portátiles, sino que también smartphone, tables, incluso calculadoras electrónicas de mano, entre otros dispositivos; y la razón del uso de binarios es la facilidad al momento de realizar operaciones aritméticas y el descubrimiento de materiales que pueden trabajar entre voltajes y ausencia de los mismo de manera precisa,.

Ahora cabe la pregunta, ¿Cómo éstos dispositivos pueden hacer tantas cosas solo usando ceros y unos?, diré que en un comienzo los sistemas de computo no hacían muchas cosas, operaban con ceros y unos y solo científicos, matemáticos, físicos y programadores comprendían las respuestas de estos equipos de luces titilantes, luego las cosas se tornaron complejas y recurrieron a simplificar largas secuencias de ceros y unos en comandos, algo así como lenguajes memotécnicos; luego inventaron el ensamblador, luego lenguajes más fáciles de codificar, luego siguieron muchos más, pasaron por los orientados a objetos y siguen evolucionando; ésta evolución a dado entornos más complejos y cosas más interesantes que luces titilantes; lo anterior es una respuesta personal y resumida, te invito a investigar más.

Antes de pasar a abordar el tema de los números binarios, trataremos sobre el sistema decimal y como hacemos para combinarlos entre si y formar cifras más grandes.

La razón por la que usamos un sistema basado en diez dígitos (0,1,2,3,4,5,6,7,8,9) son meramente históricas, no hay una razón matemática para que esto sea así.



La siguiente figura representa el mecanismo o método que usamos a diario para contar y generar numero decimales.


De igual forma podemos hacer conteos en otra bases, el siguiente ejemplo aplica para el sistema binario con la única variante que, la caja no puede tener 2 o más elementos


En el siguiente gráfico confrontaré los dos conteos en sistema decimal y binario respectivamente, el resultado final está representando la misma cantidad pero en bases distintas, es decir 10 base 10 = 1010 base 2.


Listo, ahora tratemos el tema de la conversión de decimal a binario y viceversa; usando Java es muy facíl ya que prácticamente está resuelto usando la clase Integer como podemos ver en el codigo a continuación.

class Conversion{
 public static void main(String []args){
  //De binario a decimal
  String numeroBinario = "1010";
  int num=Integer.parseInt(numeroBinario,2);
  System.out.println(numeroBinario + " base 2 = " + num + " base 10");
  
  //De decimal a binario
  int numeroDecimal = 10;
  String binario = Integer.toBinaryString(numeroDecimal); 
  System.out.println(numeroDecimal + " base 10 = " + binario + " base 2");
 }
} 

Pero veamos ahora como se resuelve este tipo de conversión usando papel y lápiz.


Decimal a binario
Se divide el número del sistema decimal entre 2, cuyo resultado entero se vuelve a dividir entre 2, y así sucesivamente hasta que el dividendo sea menor que el divisor, 2. Es decir, cuando el número a dividir sea 1 finaliza la división.

A continuación se ordenan los restos empezando desde el último al primero, simplemente se colocan en orden inverso a como aparecen en la división, se les da la vuelta. Éste será el número binario que buscamos (Explicación de wikipedia).


Binario a decimal
Para realizar la conversión de binario a decimal, realice lo siguiente:

Inicie por el lado derecho del número en binario, cada cifra multiplíquela por 2 elevado a la potencia consecutiva (comenzando por la potencia 0, 20).

Después de realizar cada una de las multiplicaciones, sume todas y el número resultante será el equivalente al sistema decimal. (Explicación de wikipedia).

Ejemplos:
(Los números de arriba indican la potencia a la que hay que elevar 2)




Ya para terminar les ofrezco el código que he escrito más operaciones basica con números binarios, espero les guste.


public class Ejercicio{
 public static int dinarioADecimal(String numeroBinario){
  int longitud = numeroBinario.length();//Numero de digitos que tiene nuestro binario
  int resultado = 0;//Aqui almacenaremos nuestra respuesta final
  int potencia = longitud - 1;
  for(int i = 0;i < longitud;i++){//recorremos la cadena de numeros
   if(numeroBinario.charAt(i) == '1'){
    resultado += Math.pow(2,potencia);
   }
   potencia --;//drecremantamos la potencia
  }
  return resultado;
 }
 
 public static String decimalABinario(int numeroDecimal){
  int temp = numeroDecimal;
  String resultado = "";
  while (temp != 0){
   if(temp % 2 == 0){
    resultado = "0" + resultado;
   }else{
    resultado = "1" + resultado;
   }
   temp = temp / 2;
  }
  return resultado;
 }
 
 public static String operacionBinaria(char operador,String numero1, String numero2){
  int n1Decimal = dinarioADecimal(numero1);
  int n2Decimal = dinarioADecimal(numero2);
  if(operador == '+'){
   return (decimalABinario(n1Decimal + n2Decimal));
  }else if(operador == '-'){
   return (decimalABinario(n1Decimal - n2Decimal));
  }else if(operador == '*'){
   return (decimalABinario(n1Decimal * n2Decimal));
  }else{
   return ("null");
  }
 }
 
 public static String sumaBinaria(String numero1,String numero2){
  return (operacionBinaria('+',numero1,numero2));
 }
 
 public static String sumaBinaria(String numero1,String numero2,String numero3){
  return sumaBinaria(sumaBinaria(numero1,numero2),numero3);
 }
 
 public static String restaBinaria(String numero1,String numero2){
  return (operacionBinaria('-',numero1,numero2));
 }
 
 public static String multiplicacionBinaria(String numero1,String numero2){
  return (operacionBinaria('*',numero1,numero2));
 }
 
 public static void main(String []args){
  System.out.println("-----De binario a decimal-----");
  System.out.println(dinarioADecimal("101010"));
  
  System.out.println("-----De decimal a binario-----");
  System.out.println(decimalABinario(10));
  
  System.out.println("-----Sumando dos binarios-----");
  System.out.println(sumaBinaria("101010","111000"));
  
  System.out.println("-----Sumando tres binarios-----");
  System.out.println(sumaBinaria("101010","111000","101010"));
  
  System.out.println("-----Restando dos binarios-----");
  System.out.println(restaBinaria("101010","111000"));
  
  System.out.println("-----Multiplicando dos binarios-----");
  System.out.println(multiplicacionBinaria("101010","111000"));
 }
}

Esperando serles de ayuda.

Entrada destacada

Matriz de adyacencia para un grafo

"La matriz de adyacencia es una matriz cuadrada que se utiliza como una forma de representar relaciones binarias."; aunque pa...