gpt4 book ai didi

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

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 27 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java实现爬虫给App提供数据(Jsoup 网络爬虫)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

1、需求 。

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

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

2、效果图 。

下图是原网站的页面 。

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

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

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

3、爬虫思路 。

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

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

Jsoup 简介 。

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

Jsoup主要有以下功能:

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

4、爬虫过程 。

Get 请求获取网页 HTML 。

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();将得到输入流转化为字符串是个普遍需求,我们将其抽象出来,写一个工具方法.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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();
  }
}

5、解析 HTML 获取标题 。

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

?
1
2
3
4
5
6
7
< 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) 方法 。

?
1
2
3
4
5
6
7
8
9
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();

6、获取发布日期、信息来源 。

同样找出对于的 HTML 代码 。

?
1
2
3
4
5
6
7
8
9
10
11
< 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.

?
1
2
3
4
5
6
7
8
9
// 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();

7、解析浏览次数 。

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

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

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

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

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

?
1
document.write( 478 )

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

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

8、解析新闻内容 。

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

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

9、解析图片 Url 。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
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" );
}

10、新闻实体类 JavaBean 。

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

  1. public class ArticleItem { 
  2.  
  3.  private int index; 
  4.  private String[] imageUrls; 
  5.  private String title; 
  6.  private String publishDate; 
  7.  private String source; 
  8.  private int readTimes; 
  9.  private String body; 
  10.  
  11.  public ArticleItem(int index, String[] imageUrls, String title, String publishDate, String source, int readTimes, 
  12.  String body) { 
  13.  this.index = index; 
  14.  this.imageUrls = imageUrls; 
  15.  this.title = title; 
  16.  this.publishDate = publishDate; 
  17.  this.source = source; 
  18.  this.readTimes = readTimes; 
  19.  this.body = body; 
  20.  } 
  21.  
  22.  @Override 
  23.  public String toString() { 
  24.  return "ArticleItem [index=" + index + ", imageUrls=" + Arrays.toString(imageUrls) + ", title=" + title 
  25.  + ", publishDate=" + publishDate + ", source=" + source + ", readTimes=" + readTimes + ", body=" + body 
  26.  + "]"
  27.  } 
  28.  
  29.  
 

测试 。

  。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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 ));
}

输出信息 。

?
1
2
3
4
5
6
7
8
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 网络爬虫,如果文章对您有帮助,那就给个赞吧.

最后此篇关于Java实现爬虫给App提供数据(Jsoup 网络爬虫)的文章就讲到这里了,如果你想了解更多关于Java实现爬虫给App提供数据(Jsoup 网络爬虫)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com