【问题标题】:Android HTML Jsoup parsing speedAndroid HTML Jsoup解析速度
【发布时间】:2014-08-27 21:55:40
【问题描述】:

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

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

现在的问题是速度太慢了。我的意思是,在按下登录按钮后,在应用程序的登录屏幕中,用户必须在 3G 中等待长达 10 秒,在 WiFi 中等待约 8-10 秒(取决于 WiFi 速度)。当他尝试检查数据更新时,它会执行相同的算法 + 比较 SQLiteDatabase 表数据。

那么,有没有其他方法可以在 android 中进行这种 HTML 解析 - 抓取事情以使其更快?附言遗憾的是,我无权访问数据库。

编辑:

由于您询问了我正在抓取的内容,因此这里有几个您无需登录即可访问的页面的示例(与其他页面相比,它并不是一张真正的大表):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 秒。

【问题讨论】:

  • Writing all required data to SQLiteDatabase I do NOT have access to the database ????
  • 我正在将下载的数据写入我自己的 SQLiteDatabase。无权访问是指我无权访问该网站的数据库,因此我必须抓取该网站。非常清楚,我正在抓取大学信息系统网站,他们尚未授予访问其数据库的权限。
  • 如果您的代码速度较慢,那么您应该在此处发布您的代码并在互联网上的某个地方放置一个页面,这样我们就不必登录但可以进行一些测试。

标签: android performance web-scraping jsoup


【解决方案1】:

由于您的问题模棱两可,并且您没有提供代码,也没有提供您正在解析的 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. 所有数据都收集在父线程中。

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

【讨论】:

  • 为了提高解析DOM的效率:有什么方法可以只解析表吗?因为 Jsoup.connect().get() 解析整个 HTML 页面,然后它开始抓取它。我只需要桌子。
  • 是的,但是你看,当我登录时,我必须立即重定向到另一个页面,并且我正在通过发送 GET 方法来做,所以无论如何都要使用 .get()。检查 EDIT 2 以获取我的登录代码。我认为这个 .body() 代码仅适用于我的情况下的非登录页面。
  • 在 EDIT2 中你做了两件事。首先你得到cookies,然后你得到页面(modules_url)。他们都需要2.5秒?还是只是接收 cookie 的部分?
  • Connection.Response 行需要 2.6 秒,resopnse.cookie() 需要 1 毫秒。并获得我重定向 1.5 秒的页面。所以我需要 4.1 秒才能获得页面内容。
  • 感谢您的帮助,如果有改进,我会在几天内通知您。其次,并发线程是否适用于 loader ?最后一个问题是只要用户使用应用程序,我可以保持会话吗?因为在网站上,如果用户在 10 分钟内不活动,则会自动断开连接(我的意思是我可以使用 jsoup 重复使用 cookie,否则 10 分钟不活动后它将“过期”?)。跨度>
猜你喜欢
  • 1970-01-01
  • 2013-09-21
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多