search - 如何在不使用 API 的情况下以编程方式执行搜索?

标签 search screen-scraping

我想创建一个程序,将字符串输入到像谷歌这样的网站的文本框中(不使用他们的公共(public) API),然后提交表单并获取结果。这可能吗?获取结果将需要使用我假设的 HTML 抓取,但我将如何将数据输入文本字段并提交表单?我会被迫使用公共(public) API 吗?这样的事情是不可行的吗?我必须弄清楚查询字符串/参数吗?

谢谢

最佳答案

理论

我要做的是创建一个小程序,它可以自动将任何表单数据提交到任何地方并返回结果。这在 Java 中很容易做到,HTTPUnit .任务是这样的:

  • 连接到网络服务器。
  • 解析页面。
  • 获取页面上的第一个表单。
  • 填写表格数据。
  • 提交表格。
  • 读取(并解析)结果。

  • 您选择的解决方案将取决于多种因素,包括:
  • 是否需要模拟 JavaScript
  • 之后你需要对数据做什么
  • 你精通什么语言
  • 应用程序速度(这是一个查询还是 100,000 个查询?)
  • 应用程序需要多长时间才能运行
  • 它是一次性的,还是必须维护?

  • 例如,您可以尝试以下应用程序为您提交数据:
  • Lynx
  • curl
  • wget

  • 那么grep (awk 或 sed)生成的网页。

    屏幕抓取的另一个技巧是下载一个示例 HTML 文件并在 vi(或 VIM)中手动解析它。将击键保存到文件中,然后每当您运行查询时,将这些击键应用到生成的网页以提取数据。此解决方案不可维护,也不是 100% 可靠(但很少从网站抓取屏幕)。它可以工作并且速度很快。

    示例

    下面是一个用于提交网站表单(特别是处理登录网站)的半通用 Java 类,希望它可能有用。不要用来作恶。
    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();
      }
    }
    

    示例属性文件如下所示:
    $ 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
    

    运行它类似于以下内容(将 HTTPUnit 的路径和 $CLASSPATH 的 FormElements 类替换):
    java -cp $CLASSPATH FormElements com.mellon.properties "John" "Doe" "John.Doe@gmail.com" "To whom it may concern  ..."
    

    合法性

    另一个答案提到它可能违反使用条款。先检查一下,然后再花时间研究技术解决方案。非常好的建议。

    关于search - 如何在不使用 API 的情况下以编程方式执行搜索?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1141136/

    相关文章:

    javascript - 使用 javascript 链接下载 PhantomJS

    php - 修改抓取网页中包含的 JavaScript 的最佳方法是什么?

    ruby - 使用 Datamapper 和 Sinatra 进行简单搜索

    python - 如何索引CSV文件以高效搜索?

    python Mechanize : create and submit a form

    javascript - 如何以编程方式抓取网页和 "click"javascript 按钮?

    javascript - 输入值有时不适用

    search - Solr 每个字段的多个方面

    php - 在阿拉伯语单词中搜索阿拉伯语字母

    c# - 是否可以在网络浏览器或框架中自动执行按钮点击和文本输入。如果有必要,甚至可以使用桌面工具?