Java实现爬虫给App提供数据(Jsoup 网络爬虫)

一、需求

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

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

二、效果图

下图是原网站的页面

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

三、爬虫思路

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

Android下录制App操作生成Gif动态图的全过程 :http://www.jb51.net/article/78236.htm
学习Android Material Design(RecyclerView代替ListView):http://www.jb51.net/article/78232.htm
Android项目实战之仿网易新闻的页面(RecyclerView ):http://www.jb51.net/article/78230.htm

Jsoup 简介

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

Jsoup主要有以下功能:

  • - 从一个URL,文件或字符串中解析HTML;
  • - 使用DOM或CSS选择器来查找、取出数据;
  • - 对HTML元素、属性、文本进行操作;
  • - 清除不受信任的HTML (来防止XSS攻击)

四、爬虫过程

Get 请求获取网页 HTML

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

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

public static String doGet(String urlStr) throws CommonException {
 URL url;
 String html = "";
 try {
 url = new URL(urlStr);
 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 connection.setRequestMethod("GET");
 connection.setConnectTimeout(5000);
 connection.setDoInput(true);
 connection.setDoOutput(true);
 if (connection.getResponseCode() == 200) {
 InputStream in = connection.getInputStream();
 html = StreamTool.inToStringByByte(in);
 } else {
 throw new CommonException("新闻服务器返回值不为200");
 }
 } catch (Exception e) {
 e.printStackTrace();
 throw new CommonException("get请求失败");
 }
 return html;
}

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

public class StreamTool {
 public static String inToStringByByte(InputStream in) throws Exception {
 ByteArrayOutputStream outStr = new ByteArrayOutputStream();
 byte[] buffer = new byte[1024];
 int len = 0;
 StringBuilder content = new StringBuilder();
 while ((len = in.read(buffer)) != -1) {
 content.append(new String(buffer, 0, len, "UTF-8"));
 }
 outStr.close();
 return content.toString();
 }
}

五、解析 HTML 获取标题

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

<div id="article_title">
 <h1>
 <a href="http://see.xidian.edu.cn/html/news/7428.html">
 关于举办《经典音乐作品欣赏与人文审美》讲座的通知
 </a>
 </h1>
</div>

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

String htmlStr = HttpTool.doGet(urlStr);

// 将获取的网页 HTML 源代码转化为 Document
Document doc = Jsoup.parse(htmlStr);

Element articleEle = doc.getElementById("article");
// 标题
Element titleEle = articleEle.getElementById("article_title");
String titleStr = titleEle.text();

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

同样找出对于的 HTML 代码

<html>
 <head></head>
 <body>
 <div id="article_detail">
 <span> 2015-05-28 </span>
 <span> 来源: </span>
 <span> 浏览次数: <script language="JavaScript" src="http://see.xidian.edu.cn/index.php/news/click/id/7428">
 </script> 477 </span>
 </div>
 </body>
</html>

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

// article_detail包括了 2016-01-15 来源: 浏览次数:177
Element detailEle = articleEle.getElementById("article_detail");
Elements details = detailEle.getElementsByTag("span");

// 发布时间
String dateStr = details.get(0).text();

// 新闻来源
String sourceStr = details.get(1).text();

七、解析浏览次数

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

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

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

  • 在爬虫的时候,内置一个浏览器内核,执行js渲染页面后,再抓取。这方面对应的工具有Selenium、HtmlUnit或者PhantomJs。
  • 所以分析JS请求,找到对应数据的请求url

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

document.write(478)

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

// 访问这个新闻页面,浏览次数会+1,次数是 JS 渲染的
String jsStr = HttpTool.doGet(COUNT_BASE_URL + currentPage);
int readTimes = Integer.parseInt(jsStr.replaceAll("\\D+", ""));
// 或者使用下面这个正则方法
// String readTimesStr = jsStr.replaceAll("[^0-9]", "");

八、解析新闻内容

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

Element contentEle = articleEle.getElementById("article_content");
// 新闻主体内容
String contentStr = contentEle.toString();
// 如果用 text()方法,新闻主体内容的 html 标签会丢失
// 为了在 Android 上用 WebView 显示 html,用toString()
// String contentStr = contentEle.text();

九、解析图片 Url

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

Element contentEle = articleEle.getElementById("article_content");
// 新闻主体内容
String contentStr = contentEle.toString();
// 如果用 text()方法,新闻主体内容的 html 标签会丢失
// 为了在 Android 上用 WebView 显示 html,用toString()
// String contentStr = contentEle.text();

Elements images = contentEle.getElementsByTag("img");
String[] imageUrls = new String[images.size()];
for (int i = 0; i < imageUrls.length; i++) {
 imageUrls[i] = images.get(i).attr("src");
}

十、新闻实体类 JavaBean

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

public class ArticleItem {

 private int index;
 private String[] imageUrls;
 private String title;
 private String publishDate;
 private String source;
 private int readTimes;
 private String body;

 public ArticleItem(int index, String[] imageUrls, String title, String publishDate, String source, int readTimes,
 String body) {
 this.index = index;
 this.imageUrls = imageUrls;
 this.title = title;
 this.publishDate = publishDate;
 this.source = source;
 this.readTimes = readTimes;
 this.body = body;
 }

 @Override
 public String toString() {
 return "ArticleItem [index=" + index + ",\n imageUrls=" + Arrays.toString(imageUrls) + ",\n title=" + title
 + ",\n publishDate=" + publishDate + ",\n source=" + source + ",\n readTimes=" + readTimes + ",\n body=" + body
 + "]";
 }

}

测试

public static ArticleItem getNewsItem(int currentPage) throws CommonException {
 // 根据后缀的数字,拼接新闻 url
 String urlStr = ARTICLE_BASE_URL + currentPage + ".html";

 String htmlStr = HttpTool.doGet(urlStr);

 Document doc = Jsoup.parse(htmlStr);

 Element articleEle = doc.getElementById("article");
 // 标题
 Element titleEle = articleEle.getElementById("article_title");
 String titleStr = titleEle.text();

 // article_detail包括了 2016-01-15 来源: 浏览次数:177
 Element detailEle = articleEle.getElementById("article_detail");
 Elements details = detailEle.getElementsByTag("span");

 // 发布时间
 String dateStr = details.get(0).text();

 // 新闻来源
 String sourceStr = details.get(1).text();

 // 访问这个新闻页面,浏览次数会+1,次数是 JS 渲染的
 String jsStr = HttpTool.doGet(COUNT_BASE_URL + currentPage);
 int readTimes = Integer.parseInt(jsStr.replaceAll("\\D+", ""));
 // 或者使用下面这个正则方法
 // String readTimesStr = jsStr.replaceAll("[^0-9]", "");

 Element contentEle = articleEle.getElementById("article_content");
 // 新闻主体内容
 String contentStr = contentEle.toString();
 // 如果用 text()方法,新闻主体内容的 html 标签会丢失
 // 为了在 Android 上用 WebView 显示 html,用toString()
 // String contentStr = contentEle.text();

 Elements images = contentEle.getElementsByTag("img");
 String[] imageUrls = new String[images.size()];
 for (int i = 0; i < imageUrls.length; i++) {
 imageUrls[i] = images.get(i).attr("src");
 }

 return new ArticleItem(currentPage, imageUrls, titleStr, dateStr, sourceStr, readTimes, contentStr);

}

public static void main(String[] args) throws CommonException {
 System.out.println(getNewsItem(7928));
}

输出信息

ArticleItem [index=7928,
 imageUrls=[/uploads/image/20160114/20160114225911_34428.png],
 title=电院2014级开展“让诚信之花开遍冬日校园”教育活动,
 publishDate=2016-01-14,
 source=来源: 电影新闻网,
 readTimes=200,
 body=<div id="article_content">
 <p style="text-indent:2em;" align="justify"> <strong><span style="font-size:16px;line-height:1.5;">西电新闻网讯</span></strong><span style="font-size:16px;line-height:1.5;"> (通讯员</span><strong><span style="font-size:16px;line-height:1.5;"> 丁彤 王朱丹</span></strong><span style="font-size:16px;line-height:1.5;">...)

本文讲解了如何实现Jsoup 网络爬虫,如果文章对您有帮助,那就给个赞吧。

(0)

相关推荐

  • Java爬虫Jsoup+httpclient获取动态生成的数据

    Java爬虫Jsoup+httpclient获取动态生成的数据 前面我们详细讲了一下Jsoup发现这玩意其实也就那样,只要是可以访问到的静态资源页面都可以直接用他来获取你所需要的数据,详情情跳转-Jsoup爬虫详解,但是很多时候网站为了防止数据被恶意爬取做了很多遮掩,比如说加密啊动态加载啊,这无形中给我们写的爬虫程序造成了很大的困扰,那么我们如何来突破这个梗获取我们急需的数据呢, 下面我们来详细讲解一下如何获取 String startPage="https://item.jd.com/1147

  • Java 爬虫工具Jsoup详解

    Java 爬虫工具Jsoup详解 Jsoup是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址.HTML 文本内容.它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据. jsoup 的主要功能如下: 1. 从一个 URL,文件或字符串中解析 HTML: 2. 使用 DOM 或 CSS 选择器来查找.取出数据: 3. 可操作 HTML 元素.属性.文本: jsoup 是基于 MIT 协议发布的,可放心使用于商业项目. js

  • Java实现爬虫给App提供数据(Jsoup 网络爬虫)

    一.需求 最近基于 Material Design 重构了自己的新闻 App,数据来源是个问题. 有前人分析了知乎日报.凤凰新闻等 API,根据相应的 URL 可以获取新闻的 JSON 数据.为了锻炼写代码能力,笔者打算爬虫新闻页面,自己获取数据构建 API. 二.效果图 下图是原网站的页面 爬虫获取了数据,展示到 APP 手机端 三.爬虫思路 关于App 的实现过程可以参看这几篇文章,本文主要讲解一下如何爬虫数据. Android下录制App操作生成Gif动态图的全过程 :http://www

  • Nginx限制搜索引擎爬虫频率、禁止屏蔽网络爬虫配置示例

    复制代码 代码如下: #全局配置 limit_req_zone $anti_spider zone=anti_spider:10m rate=15r/m; #某个server中  limit_req zone=anti_spider burst=30 nodelay;  if ($http_user_agent ~* "xxspider|xxbot") {  set $anti_spider $http_user_agent; } 超过设置的限定频率,就会给spider一个503. 上

  • python教程网络爬虫及数据可视化原理解析

    目录 1 项目背景 1.1Python的优势 1.2网络爬虫 1.3数据可视化 1.4Python环境介绍 1.4.1简介 1.4.2特点 1.5扩展库介绍 1.5.1安装模块 1.5.2主要模块介绍 2需求分析 2.1 网络爬虫需求 2.2 数据可视化需求 3总体设计 3.1 网页分析 3.2 数据可视化设计 4方案实施 4.1网络爬虫代码 4.2 数据可视化代码 5 效果展示 5.1 网络爬虫 5.1.1 爬取近五年主要城市数据 5.1.2 爬取2019年各省GDP 5.1.3 爬取豆瓣电影

  • Python网络爬虫中的同步与异步示例详解

    一.同步与异步 #同步编程(同一时间只能做一件事,做完了才能做下一件事情) <-a_url-><-b_url-><-c_url-> #异步编程 (可以近似的理解成同一时间有多个事情在做,但有先后) <-a_url-> <-b_url-> <-c_url-> <-d_url-> <-e_url-> <-f_url-> <-g_url-> <-h_url-> <--i_ur

  • python网络爬虫学习笔记(1)

    本文实例为大家分享了python网络爬虫的笔记,供大家参考,具体内容如下 (一)   三种网页抓取方法 1. 正则表达式: 模块使用C语言编写,速度快,但是很脆弱,可能网页更新后就不能用了. 2.Beautiful Soup 模块使用Python编写,速度慢. 安装: pip install beautifulsoup4 3. Lxml 模块使用C语言编写,即快速又健壮,通常应该是最好的选择. (二) Lxml安装 pip install lxml 如果使用lxml的css选择器,还要安装下面的

  • hadoop中实现java网络爬虫(示例讲解)

    这一篇网络爬虫的实现就要联系上大数据了.在前两篇java实现网络爬虫和heritrix实现网络爬虫的基础上,这一次是要完整的做一次数据的收集.数据上传.数据分析.数据结果读取.数据可视化. 需要用到 Cygwin:一个在windows平台上运行的类UNIX模拟环境,直接网上搜索下载,并且安装: Hadoop:配置Hadoop环境,实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS,用来将收集的数据直接上传保存到HDFS,然后用MapReduce

  • java实现一个简单的网络爬虫代码示例

    目前市面上流行的爬虫以python居多,简单了解之后,觉得简单的一些页面的爬虫,主要就是去解析目标页面(html).那么就在想,java有没有用户方便解析html页面呢?找到了一个jsoup包,一个非常方便解析html的工具呢. 使用方式也非常简单,引入jar包: <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.8.

  • java网络爬虫连接超时解决实例代码

    本文研究的主要是java网络爬虫连接超时的问题,具体如下. 在网络爬虫中,经常会遇到如下报错.即连接超时.针对此问题,一般解决思路为:将连接时间.请求时间设置长一下.如果出现连接超时的情况,则在重新请求[设置重新请求次数]. Exception in thread "main" java.net.ConnectException: Connection timed out: connect 下面的代码便是使用httpclient解决连接超时的样例程序.直接上程序. package da

  • Java 网络爬虫新手入门详解

    这是 Java 网络爬虫系列文章的第一篇,如果你还不知道 Java 网络爬虫系列文章,请参看Java 网络爬虫基础知识入门解析.第一篇是关于 Java 网络爬虫入门内容,在该篇中我们以采集虎扑列表新闻的新闻标题和详情页为例,需要提取的内容如下图所示: 我们需要提取图中圈出来的文字及其对应的链接,在提取的过程中,我们会使用两种方式来提取,一种是 Jsoup 的方式,另一种是 httpclient + 正则表达式的方式,这也是 Java 网络爬虫常用的两种方式,你不了解这两种方式没关系,后面会有相应

  • Java 网络爬虫基础知识入门解析

    前言 说起网络爬虫,大家想起的估计都是 Python ,诚然爬虫已经是 Python 的代名词之一,相比 Java 来说就要逊色不少.有不少人都不知道 Java 可以做网络爬虫,其实 Java 也能做网络爬虫而且还能做的非常好,在开源社区中有不少优秀的 Java 网络爬虫框架,例如 webmagic .我的第一份正式工作就是使用 webmagic 编写数据采集程序,当时参与了一个舆情分析系统的开发,这里面涉及到了大量网站的新闻采集,我们就使用了 webmagic 进行采集程序的编写,由于当时不知

随机推荐