Android HTML Jsoup解析速度

时间:2014-08-27 21:55:41

标签: android performance web-scraping jsoup

这是合约。在我的Android应用程序中,我正在使用Jsoup进行一些网络抓取。现在它工作正常,但它太慢了。我在代码中所做的是:

  1. 通过Jsoup中的POST方法登录页面;
  2. 获取Cookie;
  3. 通过重复使用cookies,我将浏览6页(POST和GET)并抓取它们(主要是表格和许多行。我的意思是很多......所以,真的很多foreach循环);
  4. 将所有必需数据写入SQLiteDatabase;
  5. 现在问题是它速度很快。我的意思是,在按下登录按钮后,在应用程序的登录界面中,用户必须在3G中等待10秒,在WiFi中等待8-10秒(取决于WiFi速度)。当他试图检查数据更新时,它会执行相同的算法+比较SQLiteDatabase表数据。

    那么,有没有其他方法来做这个HTML解析 - 在android中刮掉东西以使其更快?附:我遗憾地无法访问数据库。

    修改

    由于您询问了我正在抓取的内容,以下是您可以在不登录的情况下访问的几个页面的一个示例(与其他人相比,这不是一个很大的表格):https://medeine.vgtu.lt/programos/programa.jsp?sid=F&fak=5&prog=87&rus=U&klb=en

    现在,对于代码......我真的不能给你完整的代码,但这里是我得到表的每个单元格的例子:

    document = Jsoup.connect(getContext().getString(R.string.url))
                        .cookie("JSESSIONID", cookie)
                        .get();
    
                Element table = document.select("table.duomenys").first();
                if (table != null) {
                    databaseHandler.openDatabase();
                    databaseHandler.getDatabase().beginTransaction();
                    try {
                        for (Element row : table.select("tr.n, tr.l") {
                            Elements columns = row.select("td");
                            addItem(columns, DatabaseHandler.getTableName());
                        }
                        databaseHandler.getDatabase().setTransactionSuccessful();
                    } finally {
                        databaseHandler.getDatabase().endTransaction();
                    }
                    databaseHandler.closeDatabase();
                }
    

    这是addItem()方法示例:

    private void addItem(Elements columns, String tableName) {
        databaseHandler.addItem(new Item(
                columns.get(0).text(),
                columns.get(1).text(),
                columns.get(3).text(),
                columns.get(4).text()
        ), tableName);
    }
    

    这只是一页。其中有6个,其中很少有更大。当然这是在AsyncTaskLoader的loadInBackground()方法中完成的。

    编辑2:

    Connection.Response response = Jsoup.connect("https://medeine.vgtu.lt/studentams/submit.jsp")
                    .data("studKnNr", id, "asmKodas", password)
                    .timeout(3000)
                    .method(Connection.Method.POST)
                    .execute();
    
            String cookie = response.cookie("JSESSIONID");
    
            Document document = Jsoup.connect(modules_url)
                    .cookie(cookie_id, cookie)
                    .get();
    

    当我想到它时...可能是解析不是很慢,而是登录并重定向到6页,在这种情况下我什么都不做?现在我注意到在Connection.Response中通过.execute()向服务器发送POST并获取cookie需要大约2.5秒。

1 个答案:

答案 0 :(得分:5)

由于您的问题含糊不清,并且您没有提供代码,也没有提供您正在解析的DOM的一些示例,我将提供一般答案。

  • 优化您的jsoup查询。既然有很多数据(大DOM),试试吧 尽可能高效地解析它们。
  • 最小化循环。你确定你没有做任何不必要的循环 在处理数据期间?
  • 如果您有任何机会连接大块字符串,请尝试使用 StringBuilder代替String
  • 尝试使用多个线程。

<强>更新

您可以接收服务器的响应,操纵消息正文,然后使用Jsoup的解析,这样您就可以最小化解析的时间。

try {
    Connection.Response response = Jsoup.connect("ENTER_URL")
                                   .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")  
                                   .referrer("http://www.google.com")   
                                   .method(Method.GET) //or Method.POST
                                   .execute();

    String body = response.body();

    String table = body; //Manipulate the string, remove all the data you don't want.

    Document doc = Jsoup.parse(table);

    System.out.println(doc);

} catch(Exception e) {
    e.printStackTrace();
}

更新2

Connection.Response line takes 2.6 seconds:这无济于事。你必须忍受这个,因为服务器延迟服务你的请求。毕竟你只使用一次cookie然后重复使用它们。

但是,此部分getting the page可以在某种程度上进行优化。如果你使用我发布的代码,你仍然会有再次发出http请求的开销(这是无法避免的,这是与cookie一样的服务器延迟),但你只会解析你需要的部分,而不是整个回应。这会给你一些改进,但我不相信它会有多大改进。也许它甚至不值得。但您可以尝试仅更改此部分,并告诉我您是否看到任何改进。

Document document = Jsoup.connect(modules_url)
                .cookie(cookie_id, cookie)
                .get();

此外,如果你真的需要速度,你将不得不使用某种形式的并发(多线程)。 这样的事情会产生真正的不同:

  1. 在父线程中检索cookie(开头只有一次)。
  2. 为每个页面创建一个新线程并传递cookie和URL 作为参数。
  3. 每个线程都会分析分配给它的页面。
  4. 所有数据都收集在父线程中。
  5. Check this选择了如何使您的http请求并发的答案