将带有 jsoup 的 HTML 表解析为 android listview

Posted

技术标签:

【中文标题】将带有 jsoup 的 HTML 表解析为 android listview【英文标题】:Parsing a HTML table with jsoup to android listview 【发布时间】:2015-12-18 17:04:26 【问题描述】:

我正在开发一个需要 html 表的应用程序。经过大量努力寻找正确的代码并解决错误。我遇到了一个错误,我不知道如何解决它。我已经发现我需要一个扩展 Async 的类。唯一的问题是我真的不知道如何使用异步。我得到的错误是 Async 的致命异常:“FATAL EXCEPTION: AsyncTask #1”。这不太清楚下一步该做什么或如何解决这个问题。所以我希望有人可以帮助我。

最后的代码是将表格放入ArrayList,最后放入列表视图。

这是我的代码:

public class Cluka2 extends AsyncTask<Void, Void, String> 

    Document document = null;
    public ArrayList<String> list = new ArrayList<>();

    @Override
    protected String doInBackground(Void... params) 

        try 
            document = Jsoup.connect("https://tennisnaarden.planmysport.com/portal/page/pmsportal30/TVNaarden/Toernooien/Clubtoernooi").get();
           // System.out.println(document);
          //  Log.e("DEBUG", document.toString());
           // Log.v("Debug", document.toString());

         catch (IOException e) 
            e.printStackTrace();
        
        Elements elements = document.select("#pcnt1383_8158836_1383_4326089_4326089 td:first-child");

        for(int i=0;i<elements.size();i++)
        

            list.add(elements.get(i).text());
            System.out.println(elements.get(i).text());

        
        System.out.println(list);
        return list.toString();
    

这是我的错误:

java.lang.RuntimeException: An error occured while executing doInBackground()
            at android.os.AsyncTask$3.done(AsyncTask.java:299)
            at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
            at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
            at java.util.concurrent.FutureTask.run(FutureTask.java:239)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.lang.NullPointerException
            at com.example.gebruiker.tvnaardentoernooien.Cluka2.doInBackground(Cluka2.java:29)
            at com.example.gebruiker.tvnaardentoernooien.Cluka2.doInBackground(Cluka2.java:12)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)

【问题讨论】:

您应该在代码中显示第 29 行在哪里。 【参考方案1】:

看起来您在尝试连接到提到的网站页面时遇到异常,然后控制转到 catch 块,之后您访问的是未初始化的变量 document ,这就是为什么你会收到NPE。

使用 throws 或只是运行时包装技巧来找到真正的原因:

 catch (IOException e) 
        throw new RuntimeException(e);

【讨论】:

【参考方案2】:

阿罗哈,

将您要求的代码放入 try catch 语句中。当您尝试在 try catch 语句之外使用它时,您的变量超出了范围。第 29 行的对象 Elements 试图引用最初声明的 Document 对象,该对象仍然为空。那应该让它为你工作。

    public class Cluka2 extends AsyncTask<Void, Void, String> 

    Document document = null;
    public ArrayList<String> list = new ArrayList<>();

    @Override
    protected String doInBackground(Void... params) 

        try 
            document = Jsoup.connect("https://tennisnaarden.planmysport.com/portal/page/pmsportal30/TVNaarden/Toernooien/Clubtoernooi").get();
           // System.out.println(document);
           //  Log.e("DEBUG", document.toString());
           // Log.v("Debug", document.toString());
           Elements elements = document.select("#pcnt1383_8158836_1383_4326089_4326089 td:first-child");

           for(int i=0;i<elements.size();i++)
           

            list.add(elements.get(i).text());
            System.out.println(elements.get(i).text());

           
           System.out.println(list);
           return list.toString();

         catch (IOException e) 
            e.printStackTrace();
        

    

您的代码应如上所示。您对文档检索到的数据所做的任何工作都应在 try catch 中处理。此外,由于您要将这些元素添加到 arraylist,它也需要在 try catch 中。这应该可以防止您的空指针异常被触发。至于您的 AsyncTask,只需记住 AsyncTask 的生命周期(onPreExecute、doInBackground、postExecute 和 onProgressUpdate)就可以了。

【讨论】:

感谢您的帮助。 NullPointerException 消失了,但现在唯一的问题是从网站检索数据。我现在有一个没有数据的空白页。 为了访问您的数据,您需要在 onPostExecute 中检索它。更多详情请查看AsyncTask methods on Android Developer【参考方案3】:

经过一番努力,这是我解决问题的方法:

这是我的类,用于连接 URL 并获取 html 数据

   public class ClubkampioenschappenOnderdelenHTMLRequest extends AsyncTask<Void, Void, String> 

    Document document = null;
    public List<String> list = new ArrayList<>();
    private ListView listView;
    private Context context = null;


    public ClubkampioenschappenOnderdelenHTMLRequest(ArrayList<String> list, Context mContext, ListView ListView) 
        this.list = list;
        context= mContext;
        this.listView = ListView;
    

    public List<String> getList() 
        return list;
    

    public void setList(List<String> list) 
        this.list = list;
    

    @Override
    protected String doInBackground(Void... params) 


        try 
            URL url = new URL("https://tennisnaarden.planmysport.com/portal/page/pmsportal30/TVNaarden/Toernooien/Clubtoernooi");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "text/html");
            conn.connect();

            InputStreamReader input = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader reader = new BufferedReader(input);
            String line;
            String html = "";

            while((line = reader.readLine()) != null) 
                html += line;
            

            document = Jsoup.parse(html);

            Elements elements = document.select("#pcnt1383_8158836_1383_4326089_4326089 td:first-child");

            for (int i = 0; i < elements.size(); i++) 
                list.add(elements.get(i).text());
            

         catch (IOException e) 
            e.printStackTrace();
        
        return list.toString();
    

    @Override
    protected void onPostExecute(String result) 
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, list);
        listView.setAdapter(arrayAdapter);
    

onCreate方法中的代码:

@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_clubkampioenschappen_singleen_dubbel);
        this.setTitle("Onderdelen");

        ConnectivityManager connMgr = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();

        if (networkInfo != null && networkInfo.isConnected()) 

            ListView Onderdelen = (ListView) findViewById(R.id.Onderdelen);
            ClubkampioenschappenOnderdelenHTMLRequest clucka = new ClubkampioenschappenOnderdelenHTMLRequest(list, ClubkampioenschappenSingleenDubbelOnderdelen.this, Onderdelen);
            clucka.execute();

【讨论】:

以上是关于将带有 jsoup 的 HTML 表解析为 android listview的主要内容,如果未能解决你的问题,请参考以下文章

JSoup 解析带有未闭合标签的无效 HTML

如何将用 Jsoup(Java html 解析器)制作的文档转换为字符串

使用 jsoup 库解析 html 元标记

如何将字符串转化为Jsoup的Document 对象

JSoup 解析垃圾 Freemarker 标签

Java爬虫利器HTML解析工具-Jsoup