2009-07-17 13 views
7

Vorrei creare un programma che inserisca una stringa nella casella di testo in un sito come Google (senza utilizzare la loro API pubblica) e quindi inviare il modulo e acquisire i risultati. È possibile? Afferrando i risultati sarà necessario utilizzare lo scraping HTML, ma come inserirò i dati nel campo di testo e invierò il modulo? Sarei obbligato a utilizzare una API pubblica? Una cosa del genere non è fattibile? Dovrei capire stringhe/parametri di query?Come è possibile eseguire una ricerca a livello di codice senza utilizzare un'API?

Grazie

risposta

4

Teoria

Quello che vorrei fare è creare un piccolo programma che può inviare automaticamente i dati del modulo in qualsiasi luogo e tornare con i risultati. Questo è facile da fare in Java con HTTPUnit. L'attività è simile a questa:

  • Connessione al server web.
  • Analizza la pagina.
  • Ottieni il primo modulo sulla pagina.
  • Compila i dati del modulo.
  • Invia il modulo.
  • Leggere (e analizzare) i risultati.

La soluzione si sceglie dipenderà da una varietà di fattori, tra cui:

  • Se avete bisogno di emulare JavaScript
  • Quello che dovete fare con i dati in seguito
  • quali lingue con di cui sei esperto
  • Velocità applicazione (è questa per una query o 100.000?)
  • Quanto tempo l'applicazione deve funzionare
  • E 'una tantum, o dovrà essere mantenuta?

Ad esempio, si potrebbe provare le seguenti applicazioni per inviare i dati per voi:

Poi grep (awk, o sed) le pagine Web risultanti.

Un altro trucco quando lo screen scraping è scaricare un file HTML di esempio e analizzarlo manualmente in vi (o VIM). Salvare le sequenze di tasti in un file e quindi ogni volta che si esegue la query, applicare tali sequenze di tasti alle pagine Web risultanti per estrarre i dati. Questa soluzione non è gestibile, né affidabile al 100% (ma lo scraping dello schermo da un sito Web è raramente). Funziona ed è veloce.

Esempio

una classe Java semi-generici di presentare forme di siti web (in particolare si occupano di registrazione in un sito web) è al di sotto, nella speranza che possa essere utile. Non usarlo per il male.

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 file di esempio proprietà sarà simile:

$ 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 è simile al seguente (sostituire il percorso HttpUnit e la classe FormElements a $ CLASSPATH):

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

Legalità

Un'altra risposta ho detto che potrebbe violare le condizioni d'uso. Controlla prima di tutto, prima di passare il tempo a cercare una soluzione tecnica. Consiglio estremamente buono.

+0

Wow, grazie per questo. È ora di leggerlo: D – kgrad

+0

Prego; era seduto in giro a raccogliere polvere digitale. –

2

maggior parte del tempo, si può semplicemente inviare una semplice richiesta HTTP POST.

Ti suggerisco di provare a giocare con Fiddler per capire come funziona il web.

Quasi tutti i linguaggi di programmazione e i framework disponibili hanno metodi per inviare richieste non elaborate.

E si può sempre programmare contro il controllo ActiveX di Internet Explorer. Credo che molti linguaggi di programmazione lo supportino.

1

Bene, ecco il codice HTML della pagina di 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> 

Se sai come fare una richiesta HTTP dal vostro linguaggio di programmazione preferito, basta fare un tentativo e vedere quello che si ottiene indietro. Prova questo per esempio:

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

Credo che questo avrebbe messo in violazione giuridica dei termini di utilizzo (consultare un avvocato a tale proposito: i programmatori non sono bravo a dare consulenza legale), ma, tecnicamente, è possibile cercare per foobar semplicemente visitando l'URL http://www.google.com/search?q=foobar e, come dici tu, raschiando l'HTML risultante. Probabilmente avrai anche bisogno di simulare l'intestazione HTTP User-Agent e forse alcuni altri.

Forse ci sono motori di ricerca le cui condizioni d'uso non vietano questo; voi e il vostro avvocato potreste essere ben informati di guardarvi intorno per vedere se è davvero così.

0

Se si scarica Cygwin e si aggiunge Cygwin \ bin al percorso, è possibile utilizzare curl per recuperare una pagina e grep/sed/qualunque per analizzare i risultati. Perché compila il modulo quando con google puoi usare i parametri di querystring, comunque? Con arricciatura, puoi anche postare informazioni, impostare le informazioni di intestazione, ecc. Lo uso per chiamare i servizi web da una riga di comando.

Problemi correlati