从用户代理字符串中检测移动设备

时间:2013-03-11 18:36:37

标签: java user-agent

我正在寻找一种分析用户代理字符串的方法,以确定它们是否是由移动设备生成的。这需要基于java,并且可以在hadoop上进行大批量日志文件分析,以生成统计信息(即,Web服务不合适)。

我见过WURFL,但鉴于我只需要二进制移动/非移动回复,许可费似乎过高。

到目前为止,我一直在使用UADetector,这几乎就是我所需要的。但是,我遇到了一些限制。在我的测试中,我发现许多用户代理字符串提供了足够的信息来确定用户代理来自移动设备,但是被UADetector报告为UNKNOWN。

例如,标准不佳的Android应用可以发送UA字符串“Android”。这足以让它知道它来自移动设备,但是UADetector将此UserAgentType报告为UNKNOWN而不是MOBILE_BROWSER。

Apache Mobile FilterLite Device Detection做了正确的事,但我需要一些可以在Java中使用的东西。

有人可以推荐更好的解决方案吗?

5 个答案:

答案 0 :(得分:5)

我是MobileESP项目的创始人和维护者,MobileESP项目是一个用于检测移动设备的免费开源跨平台库。它仍然非常活跃! :-)

www.mobileesp.org

MobileESP 给出二进制“移动”响应。您可以通过iOS,Android或Windows Phone等平台或设备类别进行检测,例如“iPhone Tier”智能手机与平板电脑。请务必快速查看API页面。

您可能知道,使用者字符串差异很大。如果设备上附带浏览器,则制造商可以对其进行自定义。例如,HTC经常自定义原生Android浏览器的useragent字符串。

Google提供有关OEM应如何自定义useragent的建议。如果设备应被视为手机,那么Google建议在字符串中加入“mobile”元素。但是,如果该设备应被视为平板电脑,那么该字符串应该包含“mobile”。当然,遵守这项建议的情况差别很大。

Opera或Maxthon等第三方浏览器可以在useragent字符串中添加他们想要的任何内容 - 并且可以!某些仍然无名的“新”浏览器在将每个平台(例如,Android与iOS版本)的有效字符串中放入正确的信息方面做得非常糟糕。除非您从这些浏览器获得大量流量并希望投资跟踪每个平台和软件版本的确切使用价值,否则您无能为力。

无论如何,MobileESP的创建目的是在提供页面时逐页进行检测。我故意编写代码,以便于阅读和自定义。

要进行批处理,您可以执行以下操作:

1。)在构造函数中,注释掉initDeviceScan()方法。您不需要将其用于批量处理。

2.。)将UserAgent和一个空字符串传递给构造函数(UAgentInfo())。

3。)然后运行您感兴趣的任何检测方法。根据您的用户扫描,考虑您执行这些操作的顺序以节省时间。

例如,如果您的大多数用户都在iPhone上并且这是您感兴趣的检测标准之一,那么请先运行该检查。如果这个例子,你肯定不会先运行BlackBerry方法!

我的联系信息位于源代码和网站上。如果您有任何疑问或遇到任何错误,请给我发一封信。一定要浏览MobileESP.org网站以获取一些提示。

对你的项目表示最良好的祝愿,Aniket!

  • 安东尼

答案 1 :(得分:4)

另一个主题建议使用以下库:

https://github.com/ahand/mobileesp/blob/master/Java/UAgentInfo.java

似乎没问题。

答案 2 :(得分: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

答案 3 :(得分:2)

51Degrees有一个免费的开源Java API,允许您运行离线处理。您可以在此处从GitHub存储库访问它。 https://github.com/51Degrees/Java-Device-Detection

作为API的一部分,有一个离线处理示例(代码也如下所示),它采用User-Agents的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工作。

答案 4 :(得分:0)

要检测iPhone,可以使用Java user-agent中的Android和其他移动设备。如果您使用的是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:/");
}