2013-03-11 84 views
10

我正在尋找一種方法來分析用戶代理字符串以確定它們是否由移動設備生成。這需要基於java,並且可用於hadoop生成統計信息的大批量日誌文件分析(即Web服務不合適)。從用戶代理字符串中檢測移動設備

我看過WURFL,但考慮到我只需要一個二進制移動/不移動響應,許可費似乎是令人望而卻步的。

到目前爲止,我一直在使用UADetector,這幾乎就是我所需要的。但是,我遇到了一些限制。在我的測試中,我發現許多用戶代理字符串提供了足夠的信息來確定用戶代理來自移動設備,但被UADetector報告爲未知。

例如,標準較差的Android應用可以發送UA字符串「Android」。這足以知道它來自移動設備,但UADetector將此UserAgentType報告爲UNKNOWN而不是MOBILE_BROWSER。

Apache Mobile FilterLite Device Detection是正確的,但我需要一些我可以從Java使用的東西。

任何人都可以推薦更好的解決方案嗎?

+1

_例如,標準較差的Android應用可以發送UA字符串「Android」。_我不認爲你會得到任何適用於非標準用戶代理的庫,如定製瀏覽器所設置的。如果他們是自定義字符串,那麼可能性是無止境的嗎? – anotherdave 2013-03-11 19:33:30

+0

儘管確實沒有庫適用於所有任意字符串,但「Android」仍然是一個公認的用戶代理片段。實際上,問題中提到的庫將其識別爲操作系統片段;例如,WURFL甚至報告它指示移動設備。一些非標準的用戶代理字符串,比如「 - 」,我不希望得到任何信息,但很多隻包含*不完整的信息。 – 2013-03-11 19:56:55

+1

我想這取決於你需要/想要算作「移動」。例如,您鏈接的精簡版設備檢測網站將統計「安卓」的UA字符串爲「移動」/「觸摸」,但不是「平板電腦」,而非標準應用可能會發送此UA字符串在平板電腦版本中可以通過電話輕鬆完成。就我個人而言,我認爲如果您主要關注的是分析,我不會過分擔心非標準字符串 - 您是否真的看到足夠數量的「UNKNOWNS」影響您的統計信息? – anotherdave 2013-03-12 00:12:04

回答

2

如何閱讀JSP中的Apache Mobile Filter值(用於Tomcat)?

之前,你必須配置mod_jk的httpd.conf文件你沉思補充一點:

JkEnvVar AMF_IS_MOBILE undefined 

的Java代碼:

request.getAttribute("AMF_IS_MOBILE") 

來自:http://wiki.apachemobilefilter.org

5

我是MobileESP項目的創始人和維護者,這是一個免費的開源跨平臺庫,用於檢測移動設備。它仍然非常活躍! :-)

www.mobileesp.org

MobileESP 只有給出了二進制 「是移動」 的響應。您可以通過iOS,Android或Windows Phone等平臺或設備類別(如「iPhone Tier」智能手機與平板電腦)進行檢測。請務必快速瀏覽API頁面。

正如您所知,useragent字符串差別很大。如果設備上裝有瀏覽器,製造商可以對其進行定製。例如,HTC經常定製本機Android瀏覽器的useragent字符串。

Google提供有關OEM應如何定製useragent的建議。如果該設備應被視爲手機,則Google建議在該字符串中加入「mobile」元素。但如果設備應該被視爲平板電腦,那麼該字符串應該是而不是包含「mobile」。當然,堅持這一建議差異很大。

像Opera或Maxthon這樣的第三方瀏覽器可以把他們想要的任何東西放在useragent字符串中 - 然後做!某些「新」瀏覽器應該保持無名狀態,它們已經在爲每個平臺(例如Android和iOS版本)提供正確的信息到他們的useragent字符串方面做得非常差。除非您從這些瀏覽器獲得大量流量,並且希望投資跟蹤每個平臺和軟件版本的確切useragent值,否則沒有什麼可以做的。

無論如何,MobileESP的創建目標是在頁面投放時逐頁進行檢測。我有目的地編寫了代碼,非常容易閱讀和定製。

做批量處理,你可能會做這樣的事情:

1)在構造函數中註釋掉initDeviceScan()方法。你不需要這個批量處理。

2.)將UserAgent和一個空字符串傳遞給構造函數(UAgentInfo())。

3.)然後運行您感興趣的任何檢測方法。根據您的用戶掃描,仔細考慮您節省時間的順序。

例如,如果您的大多數用戶都對iPhone,這就是你所感興趣的檢測標準之一,那麼首先運行的檢查。如果這個例子,你肯定不會先運行黑莓方法!

我的聯繫信息位於源代碼和網站上。如果您有任何問題或遇到任何錯誤,請給我一張便條。絕對看看MobileESP.org網站的一些提示。

對您的項目Aniket致以最良好的祝願!

  • 安東尼
0

爲了檢測iPhone,機器人和其他移動設備中Javauser-agent都可以使用。如果您使用的是Spring,您可以根據需要自定義以下代碼。

@Override 
public ModelAndView redirectToAppstore(HttpServletRequest request) { 
    String userAgent = request.getHeader("user-agent").toLowerCase(); 
    String iphoneStoreUrl = "IPONE_STORE_URL"; 
    String androidStoreUrl = "ANDROID_STORE_URL"; 
    if (userAgent.contains("iphone")) 
     return new ModelAndView("redirect:" + iphoneStoreUrl); 
    else if (userAgent.contains("android")) 
     return new ModelAndView("redirect:" + androidStoreUrl); 

    return new ModelAndView("redirect:/"); 
} 
2

51Degrees有一個免費的開源Java API,允許您運行離線處理。你可以在這裏從GitHub Repository訪問它。 https://github.com/51Degrees/Java-Device-Detection

作爲API的一部分有一個脫機處理示例(代碼也如下所示)這需要用戶代理的CSV文件,並返回所需的屬性到一個輸出文件。下面的例子只是使用的數據集內的屬性3,對於一個完整的列表,你可以看一下字典這裏https://51degrees.com/resources/property-dictionary

// output file in current working directory 
public String outputFilePath = "batch-processing-example-results.csv"; 
// pattern detection matching provider 
private final Provider provider; 

/** 
* Initialises the device detection Provider with the included Lite data 
* file. For more data see: 
* <a href="https://51degrees.com/compare-data-options">compare data options 
* </a> 
* 
* @throws IOException if there was a problem reading from the data file. 
*/ 
public OfflineProcessingExample() throws IOException { 
    provider = new Provider(StreamFactory.create(
      Shared.getLitePatternV32(), false)); 
} 

/** 
* Reads a CSV file containing User-Agents and adds the IsMobile, 
* PlatformName and PlatformVersion information for the first 20 lines. 
* For a full list of properties and the files they are available in please 
* see: <a href="https://51degrees.com/resources/property-dictionary"> 
* Property Dictionary</a> 
* 
* @param inputFileName the CSV file to read from. 
* @param outputFilename where to save the file with extra entries. 
* @throws IOException if there was a problem reading from the data file. 
*/ 
public void processCsv(String inputFileName, String outputFilename) 
     throws IOException { 
    BufferedReader bufferedReader = 
      new BufferedReader(new FileReader(inputFileName)); 
    try { 
     FileWriter fileWriter = new FileWriter(outputFilename); 
     try { 
      // it's more efficient over the long haul to create a match 
      // once and reuse it in multiple matches 
      Match match = provider.createMatch(); 
      // there are 20k lines in supplied file, we'll just do a couple 
      // of them! 
      for (int i = 0; i < 20; i++) { 

       // read next line 
       String userAgentString = bufferedReader.readLine(); 

       // ask the provider to match the UA using match we created 
       provider.match(userAgentString, match); 

       // get some property values from the match 
       Values isMobile = match.getValues("IsMobile"); 
       Values platformName = match.getValues("PlatformName"); 
       Values platformVersion = match.getValues("PlatformVersion"); 

       // write result to file 
       fileWriter.append("\"") 
         .append(userAgentString) 
         .append("\", ") 
         .append(getValueForDisplay(isMobile)) 
         .append(", ") 
         .append(getValueForDisplay(platformName)) 
         .append(", ") 
         .append(getValueForDisplay(platformVersion)) 
         .append('\n') 
         .flush(); 
      } 
     } finally { 
      fileWriter.close(); 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
} 

/** 
* Match values may be null. A helper method to get something displayable 
* @param values a Values to render 
* @return a non-null String 
*/ 
protected String getValueForDisplay(Values values) { 
    return values == null ? "N/A": values.toString(); 
} 

/** 
* Closes the {@link fiftyone.mobile.detection.Dataset} by releasing data 
* file readers and freeing the data file from locks. This method should 
* only be used when the {@code Dataset} is no longer required, i.e. when 
* device detection functionality is no longer required, or the data file 
* needs to be freed. 
* 
* @throws IOException if there was a problem accessing the data file. 
*/ 
@Override 
public void close() throws IOException { 
    provider.dataSet.close(); 
} 

/** 
* Instantiates this class and starts 
* {@link #processCsv(java.lang.String, java.lang.String)} with default 
* parameters. 
* 
* @param args command line arguments. 
* @throws IOException if there was a problem accessing the data file. 
*/ 
public static void main(String[] args) throws IOException { 
    System.out.println("Starting Offline Processing Example"); 
    OfflineProcessingExample offlineProcessingExample = 
      new OfflineProcessingExample(); 
    try { 
     offlineProcessingExample.processCsv(Shared.getGoodUserAgentsFile(), 
       offlineProcessingExample.outputFilePath); 
     System.out.println("Output written to " + 
       offlineProcessingExample.outputFilePath); 
    } finally { 
     offlineProcessingExample.close(); 
    } 
} 

希望這有助於。

披露:我在51Degrees工作。