2009-07-17 7 views
7

Me gustaría crear un programa que ingrese una cadena en el cuadro de texto de un sitio como Google (sin usar su API pública) y luego envíe el formulario y obtenga los resultados. es posible? Agarrar los resultados requerirá el uso de raspado de HTML, supongo, pero ¿cómo ingresaría datos en el campo de texto y enviaría el formulario? ¿Seré forzado a usar una API pública? ¿Algo como esto simplemente no es factible? ¿Tendría que averiguar cadenas/parámetros de consulta?¿Cómo puedo realizar una búsqueda mediante programación sin usar una API?

Gracias

Respuesta

4

Teoría

Lo que me gustaría hacer es crear un pequeño programa que puede enviar automáticamente los datos del formulario a cualquier lugar y volver con los resultados. Esto es fácil de hacer en Java con HTTPUnit. La tarea es la siguiente:

  • Conéctese al servidor web.
  • Analizar la página.
  • Obtenga el primer formulario en la página.
  • Rellene los datos del formulario.
  • Envíe el formulario.
  • Lea (y analice) los resultados.

La solución que elija dependerá de una variedad de factores, incluyendo:

  • Ya sea que necesite para emular JavaScript
  • Lo que hay que hacer con los datos después
  • qué idiomas con cuál es competente
  • Velocidad de la aplicación (¿es esto para una consulta o 100,000?)
  • ¿Qué tan pronto la aplicación debe estar trabajando
  • ¿Es una sola o tendrá que ser mantenida?

Por ejemplo, usted podría tratar de las siguientes aplicaciones para enviar los datos para usted:

Entonces grep (awk o sed) la (s) página (s) web resultante (s).

Otro truco cuando raspa la pantalla es descargar un archivo HTML de muestra y analizarlo manualmente en vi (o VIM). Guarde las pulsaciones de teclas en un archivo y luego, cada vez que ejecute la consulta, aplique esas teclas a la (s) página (s) web resultante (s) para extraer los datos. Esta solución no es fácil de mantener, ni es 100% confiable (pero rara vez lo es rastrear la pantalla de un sitio web). Funciona y es rápido.

Ejemplo

Una clase Java semi-genérica para enviar formularios de la web (que trata específicamente con el registro en un sitio web) está por debajo, con la esperanza de que podría ser útil. No lo uses para el mal

import java.io.FileInputStream; 

import java.util.Enumeration; 
import java.util.Hashtable; 
import java.util.Properties; 

import com.meterware.httpunit.GetMethodWebRequest; 
import com.meterware.httpunit.SubmitButton;  
import com.meterware.httpunit.WebClient;   
import com.meterware.httpunit.WebConversation;  
import com.meterware.httpunit.WebForm;    
import com.meterware.httpunit.WebLink;    
import com.meterware.httpunit.WebRequest;   
import com.meterware.httpunit.WebResponse;   

public class FormElements extends Properties 
{           
    private static final String FORM_URL = "form.url"; 
    private static final String FORM_ACTION = "form.action"; 

    /** These are properly provided property parameters. */ 
    private static final String FORM_PARAM = "form.param."; 

    /** These are property parameters that are required; must have values. */ 
    private static final String FORM_REQUIRED = "form.required.";    

    private Hashtable fields = new Hashtable(10); 

    private WebConversation webConversation; 

    public FormElements() 
    {      
    }      

    /** 
    * Retrieves the HTML page, populates the form data, then sends the 
    * information to the server.          
    */                 
    public void run()             
    throws Exception             
    {                 
    WebResponse response = receive();         
    WebForm form = getWebForm(response);       

    populate(form); 

    form.submit(); 
    }    

    protected WebResponse receive() 
    throws Exception    
    {        
    WebConversation webConversation = getWebConversation(); 
    GetMethodWebRequest request = getGetMethodWebRequest(); 

    // Fake the User-Agent so the site thinks that encryption is supported. 
    //                  
    request.setHeaderField("User-Agent",         
     "Mozilla/5.0 (X11; U; Linux i686; en-US; rv\\:1.7.3) Gecko/20040913"); 

    return webConversation.getResponse(request); 
    }            

    protected void populate(WebForm form) 
    throws Exception      
    {          
    // First set all the .param variables. 
    //          
    setParamVariables(form);    

    // Next, set the required variables. 
    //         
    setRequiredVariables(form);  
    }          

    protected void setParamVariables(WebForm form) 
    throws Exception        
    {            
    for(Enumeration e = propertyNames(); e.hasMoreElements();) 
    {               
     String property = (String)(e.nextElement());    

     if(property.startsWith(FORM_PARAM)) 
     {          
     String fieldName = getProperty(property); 
     String propertyName = property.substring(FORM_PARAM.length()); 
     String fieldValue = getField(propertyName);     

     // Skip blank fields (most likely, this is a blank last name, which 
     // means the form wants a full name).        
     //                 
     if("".equals(fieldName))          
      continue;               

     // If this is the first name, and the last name parameter is blank, 
     // then append the last name field to the first name field.   
     //                 
     if("first_name".equals(propertyName) &&       
      "".equals(getProperty(FORM_PARAM + "last_name")))   
      fieldValue += " " + getField("last_name");      

     showSet(fieldName, fieldValue); 
     form.setParameter(fieldName, fieldValue); 
     }            
    }            
    }             

    protected void setRequiredVariables(WebForm form) 
    throws Exception         
    {             
    for(Enumeration e = propertyNames(); e.hasMoreElements();) 
    {               
     String property = (String)(e.nextElement());    

     if(property.startsWith(FORM_REQUIRED)) 
     {           
     String fieldValue = getProperty(property); 
     String fieldName = property.substring(FORM_REQUIRED.length()); 

     // If the field starts with a ~, then copy the field. 
     //             
     if(fieldValue.startsWith("~"))     
     {              
      String copyProp = fieldValue.substring(1, fieldValue.length()); 
      copyProp = getProperty(copyProp);        

      // Since the parameters have been copied into the form, we can 
      // eke out the duplicate values.         
      //                
      fieldValue = form.getParameterValue(copyProp);     
     }                 

     showSet(fieldName, fieldValue); 
     form.setParameter(fieldName, fieldValue); 
     }            
    }            
    }             

    private void showSet(String fieldName, String fieldValue) 
    {               
    System.out.print("<p class='setting'>");    
    System.out.print(fieldName);       
    System.out.print(" = ");        
    System.out.print(fieldValue);       
    System.out.println("</p>");        
    }               

    private WebForm getWebForm(WebResponse response) 
    throws Exception         
    {             
    WebForm[] forms = response.getForms();   
    String action = getProperty(FORM_ACTION);  

    // Not supposed to break out of a for-loop, but it makes the code easy ... 
    //                   
    for(int i = forms.length - 1; i >= 0; i--)        
     if(forms[ i ].getAction().equalsIgnoreCase(action))     
     return forms[ i ];              

    // Sadly, no form was found. 
    //       
    throw new Exception();  
    }        

    private GetMethodWebRequest getGetMethodWebRequest() 
    { 
    return new GetMethodWebRequest(getProperty(FORM_URL)); 
    } 

    private WebConversation getWebConversation() 
    { 
    if(this.webConversation == null) 
     this.webConversation = new WebConversation(); 

    return this.webConversation; 
    } 

    public void setField(String field, String value) 
    { 
    Hashtable fields = getFields(); 
    fields.put(field, value); 
    } 

    private String getField(String field) 
    { 
    Hashtable<String, String> fields = getFields(); 
    String result = fields.get(field); 

    return result == null ? "" : result; 
    } 

    private Hashtable getFields() 
    { 
    return this.fields; 
    } 

    public static void main(String args[]) 
    throws Exception 
    { 
    FormElements formElements = new FormElements(); 

    formElements.setField("first_name", args[1]); 
    formElements.setField("last_name", args[2]); 
    formElements.setField("email", args[3]); 
    formElements.setField("comments", args[4]); 

    FileInputStream fis = new FileInputStream(args[0]); 
    formElements.load(fis); 
    fis.close(); 

    formElements.run(); 
    } 
} 

un archivos de propiedades de ejemplo se vería así:

$ cat com.mellon.properties 

form.url=https://www.mellon.com/contact/index.cfm 
form.action=index.cfm 
form.param.first_name=name 
form.param.last_name= 
form.param.email=emailhome 
form.param.comments=comments 

# Submit Button 
#form.submit=submit 

# Required Fields 
# 
form.required.to=zzwebmaster 
form.required.phone=555-555-1212 
form.required.besttime=5 to 7pm 

Run es similar al siguiente (sustituya la ruta a HttpUnit y la clase FormElements por $ CLASSPATH):

java -cp $CLASSPATH FormElements com.mellon.properties "John" "Doe" "[email protected]" "To whom it may concern ..." 

Legalidad

Otro answe mencionó que podría violar los términos de uso. Compruébalo primero, antes de dedicar algún tiempo a buscar una solución técnica. Extremadamente buen consejo.

+0

Wow, gracias por esto. Hora de leerlo: D – kgrad

+0

De nada; estaba sentado recogiendo polvo digital. –

2

mayoría de las veces, sólo puede enviar una solicitud HTTP POST sencilla.

Sugiero que intentes jugar con Fiddler para entender cómo funciona la web.

Casi todos los lenguajes de programación y frameworks que existen tienen métodos para enviar solicitudes sin formato.

Y siempre puede programar contra el control ActiveX de Internet Explorer. Creo que muchos lenguajes de programación lo admiten.

1

Bueno, aquí está el código HTML de la página de Google:

<form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top> 
<td width=25%>&nbsp;</td><td align=center nowrap> 
<input name=hl type=hidden value=en> 
<input type=hidden name=ie value="ISO-8859-1"> 
<input autocomplete="off" maxlength=2048 name=q size=55 title="Google Search" value=""> 
<br> 
<input name=btnG type=submit value="Google Search"> 
<input name=btnI type=submit value="I'm Feeling Lucky"> 
</td><td nowrap width=25% align=left> 
<font size=-2>&nbsp;&nbsp;<a href=/advanced_search?hl=en> 
Advanced Search</a><br>&nbsp;&nbsp; 
<a href=/preferences?hl=en>Preferences</a><br>&nbsp;&nbsp; 
<a href=/language_tools?hl=en>Language Tools</a></font></td></tr></table> 
</form> 

Si sabe cómo hacer una petición HTTP de su lenguaje de programación favorito, sólo darle una oportunidad y ver lo que hay detrás. Prueba esto, por ejemplo:

http://www.google.com/search?hl=en&q=Stack+Overflow 
2

Creo que esto pondría en violación legal de las condiciones de uso (consultar a un abogado acerca de que: los programadores no son buenos para dar consejos legales), pero, técnicamente, podría buscar para foobar simplemente visitando la URL http://www.google.com/search?q=foobar y, como dices, raspando el HTML resultante. Probablemente también necesite falsificar el encabezado HTTP User-Agent y tal vez algunos otros.

Quizás haya motores de búsqueda cuyos términos de uso no lo prohíben; usted y su abogado deberían aconsejarle que mire a su alrededor para ver si este es realmente el caso.

0

Si descarga Cygwin y agrega Cygwin \ bin a su ruta, puede usar curl para recuperar una página y grep/sed/whatever para analizar los resultados. ¿Por qué completar el formulario cuando con google puede usar los parámetros de la cadena de consulta, de todos modos? Con curl, también puede publicar información, establecer información de encabezado, etc. Lo uso para llamar a servicios web desde una línea de comando.

Cuestiones relacionadas