java - Jsoup在Java中解析动态加载网页

标签 java parsing jsoup

import java.io.IOException;
import java.util.ArrayList;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;


public class listGrabber {
    public static void main(String[]args) {
        try {
            Document doc = Jsoup.connect("https://play.google.com/store/apps/category/GAME_ACTION/collection/topselling_free").get();
            int count = 0;
            Elements elements;
            String url;
            ArrayList<String> list = new ArrayList<>();
            do{
                elements = doc.select("a[class^=title]").get(count).select("a[class^=title]");

                url = "";
                url = elements.attr("abs:title").replaceAll("https://play.google.com/store/apps/category/GAME_ACTION/collection/","");
                url = url.replaceAll("®|™","");
                url = url.replaceAll("[(](.*)[)]","");
                list.add(url);
                System.out.println(url);
                count++;
            }while (url!="" &&url!=null);
            // String divContents =
            // doc.select(".id-app-orig-desc").first().text();
            // elements.remove("div");
        } catch (IOException e) {

        }
    }
}

正如您在上面看到的,我正在尝试从 https://play.google.com/store/apps/category/GAME_ACTION/collection/topselling_free 中获取单词列表。

每次滚动到页面底部时,Google Play 商店页面都会加载更多元素。

我的程序将抓取显示的前 40 个元素,但由于 jsoup 不加载动态加载的网页的其余部分,我无法抓取前 40 个以外的任何元素。

此外,如果您在页面上滚动到游戏 #300,则会出现显示更多按钮,我还想解析显示更多按钮之外的元素。

有没有办法让 Jsoup 解析所有动态加载到页面上的元素?

最佳答案

编辑 - 在 OP 的几条评论之后,我完全理解他想要实现的目标。我改变了一些我原来的解决方案并测试了它。

您可以使用 JSOUP 来完成。在第一页之后,要获取下一页,您需要发送带有一些 header 的 post 请求。 header 包含(除其他外)起始编号和要获取的记录数。如果您发送一个非法号码(即您询问包含游戏编号 700 的页面但结果仅包含 600 个游戏),您将再次获得第一页。您可以遍历页面,直到获得已有的结果。
有时服务器返回 600 个结果,有时只返回 540 个,我不明白为什么。
代码是 -

import java.util.regex.Pattern;
import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class HelloWorld {

public static void main(String[] args) {

    Connection.Response res = null;
    Document doc = null;
    Boolean OK = true;
    int start = 0;
    String query;
    ArrayList<String> tempList = new ArrayList<>();
    ArrayList<String> games = new ArrayList<>();
    Pattern r = Pattern.compile("title=\"(.*)\" a");

    try {   //first connection with GET request
        res = Jsoup.connect("https://play.google.com/store/apps/category/GAME_ACTION/collection/topselling_free")
                .method(Method.GET)
                .execute(); 
        doc = res.parse();
    } catch (Exception ex) {
        //Do some exception handling here
    }
    for (int i=1; i <= 60; i++) {    //parse the result and add it to the list
        query = "div.card:nth-child(" + i + ") > div:nth-child(1) > div:nth-child(3) > h2:nth-child(2) > a:nth-child(1)";
        tempList.add(doc.select(query).toString());
    }

    while (OK) {    //loop until you get the same results again
        start += 60;    
        System.out.println("now at number " + start);
        try {      //send post request for each new page
            doc = Jsoup.connect("https://play.google.com/store/apps/category/GAME_ACTION/collection/topselling_free?authuser=0")
                    .cookies(res.cookies())
                    .data("start", String.valueOf(start))
                    .data("num", "60")
                    .data("numChildren", "0") 
                    .data("ipf", "1")
                    .data("xhr", "1")
                    .post();
        } catch (Exception ex) {
            //Do some exception handling here
        }
        for (int i=1; i <= 60; i++) {    //parse the result and add it to the list
            query = "div.card:nth-child(" + i + ") > div:nth-child(1) > div:nth-child(3) > h2:nth-child(2) > a:nth-child(1)";
            if (!tempList.contains(doc.select(query).toString())) {
                tempList.add(doc.select(query).toString());
            } else {    //we've seen these games before, time to quit
                OK = false;
                break;
            }               
        }   
    }
    for (int i = 0; i < tempList.size(); i++) {    //remove all redundent info.
        Matcher m = r.matcher(tempList.get(i));
        if (m.find()) {
            games.add(m.group(1));
            System.out.println((i + 1) + " " + games.get(i));
        }           
    }
}
}

代码可以进一步改进(比如在一个单独的方法中处理所有列表),所以这取决于你。
我希望这对你有用。

关于java - Jsoup在Java中解析动态加载网页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31661962/

相关文章:

java - 使用 IntDef 的类型安全

java - 鼠标单击 JLabel 数组 (Java)

java - 通过 Java API 使用 Liquibase 生成数据导出 SQL 文件

c# - 从 C# 中的字符串解析化学式?

java - 无法使用 JSoup 解析 HTML

java - 无法使用 JSoup 登录到 IIS 登录提示

Java-使用 JSoup 抓取动态网站

java - 将文件从一个 ftp 服务器复制或移动到另一个

c++ - 带有 OpenGL 的 OBJ 文件解析器

javascript - 寻找 html 字符串 jquery 解析器(解析 <a> 链接和 <img> 图像)