Android 使用 jsoup 解析 html

一、什么是jsoup

jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。——摘自百度百科

1、官方文档:

jsoup Cookbook(中文版)jsoup cookbook(英文版),总有一个版本适合你。

2、能做什么:

由于工作或自己的需要,我们可能要获得某些特定网页的数据,如果没有后台提供也没有开放的Api接口,这时就可以用jsoup自己抓取数据以解决没有数据的问题。

二、使用

1、导入

如果你使用Android Studio的话,首先在Gradle中引入jsoup,这是目前最新的版本

compile 'org.jsoup:jsoup:1.10.3'

其它引入方式见官方文档https://jsoup.org/download

2、选择你需要抓取数据的目标网站,分析目标数据

百度彩票目前已经停止运营了,可以使用 http://tubiao.17mcp.com/Ssq/Haoma.aspx?page=1 来学习

这里我以抓取百度彩票的双色球历史开奖结果为例,用Chrome打开目标网页,进入开发者工具(快捷键 Ctrl + Shift + I),找到要抓取的数据在网页源码的大概位置:

图1

可以看到双色球的开奖结果在一个class="historyOpt"table中。注意观察table中包含了theadtbody,如果你了解HTML中table元素的用法,可能已经猜到了开奖结果数据就在tbody中:
图2

展开tbody标签后,其中的tr就是表格中的一行数据,td代表一个单元格。开奖日期、开奖期数、开奖结果都包含在一个td,其中的开奖结果又嵌套在了另一个table中。

3、解析数据

分析完了数据的基本结构,接下来主角jsoup就该登场解析html了。这里我们使用jsoup的使用选择器语法来查找元素功能,如果了解选择器相关概念的话做起来会容易些。关于jsoup选择器语法可以看这里:http://www.open-open.com/jsoup/selector-syntax.htm
解析数据前,总要先拿到网页源码数据吧,这个jsoup可以轻松帮我实现,并且可以直接得到Document对象:

Document doc = Jsoup.connect(URL).get();

ps:当然你也可以使用okhttp,或者retrofit等其它网络框架。

由于改操作设计网络请求,所以需要在子线程进行哦,有了Document,就可以进行解析工作了:

private List<LotteryData> parseHtml(Document document) {
        Elements elements = document.select("table[class=historylist] > tbody > tr");
        List<LotteryData> list = new ArrayList<>();
        LotteryData data;
        for (Element element : elements) {
            data = new LotteryData();
            data.setNum(element.select("td > a").text());//开奖期数
            data.setDate(element.select("td").get(1).text());//开奖日期
            Elements ems = element.select("td[class=balls] em");//开奖结果
            StringBuilder sb = new StringBuilder();
            for (Element em : ems) {
                sb.append(em.text());
            }
            data.setBalls(sb.toString());
            list.add(data);
        }

        return list;
    }

首先通过Elements elements = document.select("table[class=historylist] > tbody > tr");使用组合选择器,得到了当前页面classhistorylisttable的直接子元素tbody的所有直接子元素tr,也就是当前页面table中的所有行数据,elements是一个ArrayList<Element>类型的集合。

接下来遍历elements,解析每一行数据,我们知道一个element对象对应tr,可以代表一行数据,我们先拿开奖期数,注意观察图2,开奖期数包含在tr行的第一个td单元格中的a标签,所以我们可以这样写:

element.select("td > a").text()

这样就拿到了开奖期数,如图中的2017069。
同样开奖时间是在tr行的第二个td单元格中,获取方式如下:

element.select("td").get(1).text()

至于开奖结果,在tr行中的classballstd单元格中,并用一个子table存储,所以只要得到子table中所有em元素就可以了:

  Elements ems = element.select("td[class=balls] em");

然后再遍历ems,就可以拿到开奖结果了

 for (Element em : ems) {
                sb.append(em.text());
            }

到这里html就解析完成了。在parseHtml()返回了一个List,可以方便列表显示。

4、展示数据

原网站可以按照开始、结束日期的方式来查询开奖结果,所以我们在demo中采用了分页的形式来加载数据,每一页显示30天的开奖数据,所以就要根据页码计算每一页数据对应的开始日期和结束日期,例如第一页[2017-05-18,2017-06-17]、第二页[2017-04-17,2017-05-17] ......,然后拼接到URL后面,一个完整的请求URL是这样的:http://baidu.lecai.com/lottery/draw/list/50?type=range_date&start=2017-05-18&end=2017-06-17
至于如何根据页码计算日期,还是很简单的,可以参考源码。

到这里我们的流程就分析完了,大致从请求到解析再到展示的代码如下:

private void fetchData() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Document doc = null;
                try {
                    String[] date = getDate(PAGE_NUM);
                    //拼接URL
                    URL = URL + "&start=" + date[0] + "&end=" + date[1];
                    //请求
                    doc = Jsoup.connect(URL).get();
                    //解析
                    final List<LotteryData> datas = parseHtml(doc);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //更新列表
                            parseDataFinish(datas);
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

说了这么多,总要有个效果图吧:

图3

三、小结

用jsoup解析html还是比较简单的,虽然只是它的一小部分功能,用处还是蛮大的,对于不同的网页最大的差别就在分析出如何根据选择器查找元素。但是如果原网页修改了相关代码,可能就会影响数据抓取了,你就需要及时修改你的解析代码了。文中表达有误的地方还请指正,最后希望对你有所帮助吧!

有需要可以下载 源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容