Android HTML Jsoup解析速度

标签 android performance web-scraping jsoup

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

  1. 在Jsoup中通过POST方式登录页面;
  2. 获取 cookie;
  3. 通过重复使用 cookie,我浏览了 6 页(POST 和 GET)并抓取它们(主要是表格和很多行。我的意思是很多......所以,真的有很多 foreach 循环);
  4. 将所有需要的数据写入 SQLiteDatabase;

现在的问题是速度太慢了。我的意思是,在按下登录按钮后的应用程序登录屏幕中,用户必须在 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 秒。

最佳答案

由于您的问题含糊不清,并且您没有提供代码,也没有提供您正在解析的 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 行需要 2.6 秒:这没办法。你必须忍受这一点,因为它是延迟满足你的请求的服务器。毕竟你只拿了一次 cookies 然后重复使用它们。

但是这部分获取页面可以在一定程度上进行优化。如果您使用我发布的代码,您仍然会有再次发出 http 请求的开销(这是无法避免的,它与 cookie 一样是服务器延迟),但您只会解析您需要的部分,而不是整个响应。这会给你带来一些改善,但我认为不会很大。也许这甚至不值得。但是你可以尝试只改变这部分,如果你看到任何改进,请告诉我。

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

此外,如果您确实需要速度,则必须使用某种形式的并发(多线程)。 像这样的东西会产生真正的不同:

  1. 在父线程中检索 cookie(仅在开始时一次)。
  2. 为每个页面创建一个新线程并传递 cookie 和 url 作为论点。
  3. 每个线程都会解析分配给它的页面。
  4. 所有数据都在父线程中收集。

Check this关于如何使您的 http 请求并发的选择答案

关于Android HTML Jsoup解析速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25537595/

相关文章:

java - 无法获取 Google map fragment 中的当前位置

performance - DRAM 及其对现实世界性能的影响

python - 登录销售导航器 python selenium

r - 使用 R rvest 库在 iframe 中抓取表

java - 模式优化

python - BeautifulSoup 文本挖掘 - 变量字符串

android - 缺少 sync_val_compare_and_swap_1

java - 你能在 Android Studio 的 SQLite 中创建你自己的 Enum 类型吗?

java - 如何调用另一个类的方法?

performance - 对于具有 N 个线程的并行算法,性能增益是否可以超过 N?