一款漫画APP的实现(二)- 数据拉取

本篇主要分享一下之前提到的漫画APP中数据拉取的技术实现

在开始之前,我们需要明确两点:我们的漫画数据从哪来?利用什么工具获取这些数据?


对于第一点,由于我们大部分小伙伴可能都没有能直接获取漫画原稿链接的接口,所以只能从现有的一些服务站点爬去数据。这其中我们最常用、同时也是最方便的,就是从现有网站获取数据来源。而这里我们也是主要介绍这种方式(从网站获取)

不过首先要注意的是,这里我们要实现的不是把某个特定网站的数据爬取然后存储到自己本地或服务器上,而是我们什么时候需要这些数据,就什么时候实时拉取,不借助也不需要借助任何本地存储或云端服务。


首先就是找网站了。

国内比较出名动漫站点大概就是腾讯动漫这些大厂的网站了,不过如果你想在腾讯动漫这些网站上拉取数据,比起一些其它的普通漫画网站要麻烦一些,因为腾讯动漫这些网站会涉及到id验证才能读取到数据,更重要的是,如果那个网站的漫画是需要收费的,那我们暂时也是无法获取它的数据的。毕竟在这之前,你还需要先通过它的收费验证,之后它才会从服务器向前端发送漫画数据。

这里就以一个数据相对容易拉取的网站为例(其它网站大同小异,按个人需求来定)如下图:

一款漫画APP的实现(二)- 数据拉取


这里网站名字就不透露了(熟悉的应该很容易就看出来了吧...),我们可以看到,这个网站的首页,大概就分成了两部分:一个是顶部导航栏,一个是漫画简介。这两个部分都很重要,在它的源码中就隐藏着我们所需要的重要东西:漫画数据以及分类数据

这时候我们可以按下键盘的F12键(或者找到“开发者工具”),可以看到当前网页的源码:

一款漫画APP的实现(二)- 数据拉取

一款漫画APP的实现(二)- 数据拉取

从图中我们可以看到,网页中每一个漫画类别其实都对应着源码的一个Tag的内容,并且这个“分类”的目标跳转网页就是图中<a></a>标签的href值;而对于漫画数据来说,从图二可以看到,它的图片数据其实就是对应了<img>标签里的src值。

那么到这里其实我们就很容易想到了,只要我们能够事先了解到这个网页的层次结构,就可以通过获取相应标签的值,来获取到我们需要的数据。


是不是有点明白了呢?

别急。“工欲善其事,必先利其器”。我们虽然知道了大概怎么获取数据的原理,可是该怎么获取这些数据呢?或者说,要用到哪些工具or技术?

这里主要推荐一个强大的框架:Jsoup点击跳转下载

具体Jsoup怎么使用的就不啰嗦了,它的教程百度搜一下非常多,而且也十分简单。

那么接下来的篇幅是基于你已经会了Jsoup或其它类似框架的这个基础来开展的。


这里我们假设一个场景,我们的漫画应用中有一个首页推荐,推荐的应该是一些热门的漫画等等。这里偷懒一下,直接用目标网站的推荐内容来作为我们自己的首页推荐。如图:

一款漫画APP的实现(二)- 数据拉取

我们要获取的就是这个界面中的漫画内容,这里直接查看它的网页源码:

一款漫画APP的实现(二)- 数据拉取

一款漫画APP的实现(二)- 数据拉取

图中可以看到,这些漫画的所有数据都集中在了一个<div>内的<a>标签里,那么我们只需要先定位到这个<div>(图中它的属性为class="mhlist2 mhlist2_fix_top clearfix"),将所有<a>标签获取到一个Elements里,再循环读取出Elements里每一个Element的内容,就是每一部漫画的简介数据了,代码如下:

Document document = Jsoup.parse(htmlData);    // htmlData为当前网页源码数据

Elements elements = document.select("div.mhlist2.mhlist2_fix_top.clearfix>a");

for (Element element : elements) {
    // do something
    // 解析数据
}

不过这时候你可能发现:为什么我明明正确读取了所有的数据,偏偏我的漫画图片就是不显示?

别急,跟着往下看。

这时候我们在网页点击进去,可以看到该漫画的整个章节列表

一款漫画APP的实现(二)- 数据拉取

一款漫画APP的实现(二)- 数据拉取

这时候还是跟上一步(“首页”)的相关操作,定位到章节的源码Tag里,循环读取出章节数据以及该章节目标跳转的网页就行了

// 这里用的是connect, 而上一步用到的是Parse,待会儿会解释为什么这样用
Document document = Jsoup.connect(url).get();

Elements chapterElements = document.select("ul#topic1>li");

for (Element element : chapterElements) {
    // do something
}

到了漫画详情那这里,操作也是一样的,就不赘述了


到这里你可能发现了,我们上面读取到的所有数据,唯独图片无法正常显示!这是为什么呢?我们只需要单独做一个小测试就可以发现问题所在了。这里我们打印一下获取到的<img>标签的src值,我们发现获取到的竟然不是我们在网页源码里看到的一长串url链接,而是null或者另外的空白替代图(如"blank.gif"等)

Log.d("测试", "test src: " + src);

// log输出内容:
test src: null
// 或
test src: _blank.gif

这难道是我们没有获取到<img>标签下的数据吗?不,我们确实获取到了,但我们只获取到了它本来的静态数据,而没有获取到它动态生成的值。

通过源码我们可以发现,图片的src值其实是通过JS来动态获取的,而Jsoup本身却并不能动态渲染加载JS,只能加载静态网页的内容

<img src="http://image.mhxk.com/mh/25934.jpg" alt="斗破苍穹" width="145px" height="210">

或者你想到了利用htmlUnit来辅助加载JS,可是htmlUnit在安卓端是无法使用的(具体原因请自行百度,跟它的client有关)

那究竟该怎么办呢?这个问题的解决方案,我打算放到下一篇博客来讲吧