一、需求

最近基于 Material Design 重构了自己的新闻 App,数据来源是个问题。

有前人分析了知乎日报、凤凰新闻等 API,根据相应的 URL 可以获取新闻的 JSON 数据。为了锻炼写代码能力,笔者打算爬虫新闻页面,自己获取数据构建 API。

二、效果图

下图是原网站的页面

Java爬取中国高校的信息存到mysql中 java爬取app数据_字符串

爬虫获取了数据,展示到 APP 手机端

Java爬取中国高校的信息存到mysql中 java爬取app数据_数据_02

三、爬虫思路

Java爬取中国高校的信息存到mysql中 java爬取app数据_字符串_03

关于App 的实现过程可以参看这几篇文章,本文主要讲解一下如何爬虫数据。

Jsoup 简介

Jsoup 是一个 Java 的开源HTML解析器,可直接解析某个URL地址、HTML文本内容。

Jsoup主要有以下功能:

- 从一个URL,文件或字符串中解析HTML;

- 使用DOM或CSS选择器来查找、取出数据;

- 对HTML元素、属性、文本进行操作;

- 清除不受信任的HTML (来防止XSS攻击)

四、爬虫过程

Get 请求获取网页 HTML

新闻网页Html的DOM树如下所示:

Java爬取中国高校的信息存到mysql中 java爬取app数据_java爬app_04

下面这段代码根据指定的 url,用代码获取get 请求返回的 html 源代码。

?

InputStream in = connection.getInputStream();将得到输入流转化为字符串是个普遍需求,我们将其抽象出来,写一个工具方法。

?

五、解析 HTML 获取标题

利用 google 浏览器的审查元素,找出新闻标题对于的html 代码:

?

我们需要从上面的 HTML 中找出id="article_title"的部分,使用 getElementById(String id) 方法

?

六、获取发布日期、信息来源

同样找出对于的 HTML 代码

?

思路也和上面类似,使用 getElementById(String id) 方法找出id="article_detail"为Element,再利用getElementsByTag获取span 部分。因为一共有3个 ... ,所以返回的是Elements而不是Element。

?

七、解析浏览次数

如果打印出上面的details.get(2).text(),只会得到

浏览次数:

没有浏览次数?为什么呢?

因为浏览次数是JavaScript 渲染出来的, Jsoup爬虫可能仅仅提取HTML内容,得不到动态渲染出的数据。

解决方法有两种

在爬虫的时候,内置一个浏览器内核,执行js渲染页面后,再抓取。这方面对应的工具有Selenium、HtmlUnit或者PhantomJs。

所以分析JS请求,找到对应数据的请求url

如果你访问上面的 urlhttp://see.xidian.edu.cn/index.php/news/click/id/7428,会得到下面的结果

?

这个478就是我们需要的浏览次数,我们对上面的url做get 请求,得到返回的字符串,利用正则找出其中的数字。

?

八、解析新闻内容

本来是获取新闻内容纯文字的形式,但后来发现 Android 端也可以显示 CSS 格式,所以后来内容保留了 HTML 格式。

?

九、解析图片 Url

注意一个网页上大大小小的图片很多,为了只获取新闻正文中的内容,我们最好首先定位到新闻内容的Element,然后再利用getElementsByTag(“img”)筛选出图片。

?

十、新闻实体类 JavaBean

上面获取了新闻的标题、发布日期、阅读次数、新闻内容等等,我们自然需要构造一个 javabean,把获取的内容封装进实体类中。

publicclassArticleItem {
privateintindex;
privateString[] imageUrls;
privateString title;
privateString publishDate;
privateString source;
privateintreadTimes;
privateString body;
publicArticleItem(intindex, String[] imageUrls, String title, String publishDate, String source,intreadTimes,
String body) {
this.index = index;
this.imageUrls = imageUrls;
this.title = title;
this.publishDate = publishDate;
this.source = source;
this.readTimes = readTimes;
this.body = body;
}
@Override
publicString toString() {
return"ArticleItem [index="+ index +", imageUrls="+ Arrays.toString(imageUrls) +", title="+ title
+ ", publishDate="+ publishDate +", source="+ source +", readTimes="+ readTimes +", body="+ body
+ "]";
}
}

测试

?

输出信息