首页 文章

Android HTML Jsoup解析速度

提问于
浏览
2

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

  • 通过Jsoup中的POST方法登录页面;

  • 获取cookie;

  • 通过重用cookie,我将浏览6页(POST和GET)并抓取它们(主要是表格和大量行 . 我的意思是很多......所以,真的很多foreach循环);

  • 将所有必需的数据写入SQLiteDatabase;

现在的问题是它的速度很快 . 我的意思是,在按下登录按钮后,在应用程序的登录界面中,用户必须在3G中等待10秒,在WiFi中等待8-10秒(取决于WiFi速度) . 当他试图检查数据更新时,它会使用相同的算法来比较SQLiteDatabase表数据 .

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

EDIT:

由于您询问了我正在抓取的内容,以下是您可以在不登录的情况下访问的几个页面的一个示例(与其他人相比,它实际上不是一个大表):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()方法中完成的 .

EDIT 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 回答

  • 5

    由于你的问题含糊不清,你没有提供你的代码,也没有你要解析的DOM的一些样本,我将提供一般答案 .

    • 优化您的jsoup查询 . 由于存在大量数据(大型DOM),请尝试尽可能高效地解析它们 .

    • 最小化循环 . 您确定在处理数据期间没有做任何不必要的循环吗?

    • 如果您连接大块字符串,请尝试使用 StringBuilder 而不是 String .

    • 尝试使用多个线程 .

    Update

    您可以接收服务器的响应,操纵消息正文,然后使用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();
    }
    

    Update 2

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

    但是,这部分 getting the page 可以在某种程度上进行优化 . 如果你使用我发布的代码,你仍然会有再次发出http请求的开销(这是无法避免的,它会相信它会很多 . 也许它甚至不值得 . 但你可以尝试改变这部分只是,告诉我你是否看到任何进步 .

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

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

    • 在父线程中检索cookie(开头只有一次) .

    • 为每个页面创建一个新线程并将cookie和url作为参数传递 .

    • 每个线程都会解析分配给它的页面 .

    • 所有数据都在父线程中收集 .

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

相关问题