Jsoup抓取网页数据完成一个简易的Android新闻APP
前言:作为一个篮球迷,每天必刷NBA新闻。用了那么多新闻APP,就想自己能不能也做个简易的新闻APP。于是便使用Jsoup抓取了虎扑NBA新闻的数据,完成了一个简易的新闻APP。虽然没什么技术含量,但还是写一下过程,满足一下菜鸟小小的成就感。
关于Jsoup
分析与思路
虎扑NBA新闻网页的新闻列表如图所示:
我们所要做的便是获取图中每条新闻的新闻标题、新闻概要、新闻时间与来源以及新闻的链接地址这四个信息,而后用一个实体类News封装上述四个数据,再布局到ListView上。点击ListView的每个子项,便将该子项所显示的新闻的链接地址用一个WebView显示出来,便大功告成。效果如图:
具体实现过程
1.在AndroidStudio新建工程JsoupTest,而后将Jsoup的jar包【下载地址】拷到项目的libs下,然后右键Add As Library...
2.修改activity_main.xml的布局,简单加入一个ListView,并设置一下Listview的每两个子项间的间隔的距离和颜色
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/news_lv"
android:dividerHeight="7dp"
android:divider="#dcdcdc">
</ListView>
</LinearLayout>
3.建立一个实体类News来封装我们等会要从网页中获取的新闻的标题、概要、时间与来源、链接地址这四个数据。很简单,用四个变量分别代表上述四个数据,并建立相应的构造方法以及四个变量的get与set方法。
public class News {
private String newsTitle; //新闻标题
private String newsUrl; //新闻链接地址
private String desc; //新闻概要
private String newsTime; //新闻时间与来源
public News(String newsTitle, String newsUrl, String desc, String newsTime) {
this.newsTitle = newsTitle;
this.newsUrl = newsUrl;
this.desc = desc;
this.newsTime = newsTime;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getNewsTime() {
return newsTime;
}
public void setNewsTime(String newsTime) {
this.newsTime = newsTime;
}
public String getNewsTitle() {
return newsTitle;
}
public void setNewsTitle(String newsTitle) {
this.newsTitle = newsTitle;
}
public String getNewsUrl() {
return newsUrl;
}
public void setNewsUrl(String newsUrl) {
this.newsUrl = newsUrl;
}
}
4.最重要的一步:利用Jsoup获取虎扑NBA新闻网页的数据,并封装到News实体类中。就简单概述下实现方法
查看虎扑NBA新闻的网页源代码。谷歌浏览器,右键-查看网页源代码。其他浏览器应该都差不多。
我们直接查看显示新闻列表的这部分代码,我们截图下两条新闻的代码来进行分析- 新闻1源代码:
- 新闻2源代码:
- 新闻1源代码:
分析上图两条新闻的源代码,找到我们所打算要获取的新闻的标题、概要、时间与来源、链接地址这四个数据。我们可以发现在每条新闻的[div class="list-hd"][/div]这个标签下,存在新闻的链接地址与新闻的标题这两个数据。而我们所要做的便是利用Jsoup将这两个数据解析出来:
首先用Jsoup.connect(“所要抓取数据的网址”).get()获取到一个Document对象
Document doc = Jsoup.connect("https://voice.hupu.com/nba/").get();
用doc.select("div.list-hd")这个方法,返回一个Elements对象,封装了每条新闻[div class="list-hd"][/div]标签中的内容,数据格式为:[{新闻1},{新闻2},{新闻3},{新闻4}......]
用for循环遍历titleLinks,对于每个Element对象:
用e.select("a").text()便获取到[a][/a]间的内容,即新闻标题;
用e.select("a").attr("href")便获取到每个标签中的href的值,即新闻的链接地址
Elements titleLinks = doc.select("div.list-hd");
for(Element e:titleLinks){
String title = e.select("a").text();
String uri = e.select("a").attr("href");
}
- 同理对于另外两个数据:新闻简介和新闻时间及来源,我们分析源代码并进行解析
- 新闻简介源代码
用如下代码获得新闻简介
Elements descLinks = doc.select("div.list-content");
for(Element e:titleLinks){
String desc = e.select("span").text();
}
- 新闻时间及来源源代码
![这里写图片描述](http://img.blog.csdn.net/20170122221602676?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU0NQcm9ncmFtbWVy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
用如下代码获得新闻时间与来源
```
Elements timeLinks = doc.select("div.otherInfo");
for(Element e:timeLinks){
String time = e.select("span.other-left").select("a").text();
}
```
- 综上,我们就获取到了我们所需要的数据了,为此我们在MainActivity中声明一个getNews()方法,在方法中,我们开启一个线程来进行数据的获取。完整代码如下:
private void getNews(){
new Thread(new Runnable() {
@Override
public void run() {
try{
//获取虎扑新闻20页的数据,网址格式为:https://voice.hupu.com/nba/第几页
for(int i = 1;i<=20;i++) {
Document doc = Jsoup.connect("https://voice.hupu.com/nba/" + Integer.toString(i)).get();
Elements titleLinks = doc.select("div.list-hd"); //解析来获取每条新闻的标题与链接地址
Elements descLinks = doc.select("div.list-content");//解析来获取每条新闻的简介
Elements timeLinks = doc.select("div.otherInfo"); //解析来获取每条新闻的时间与来源
//for循环遍历获取到每条新闻的四个数据并封装到News实体类中
for(int j = 0;j < titleLinks.size();j++){
String title = titleLinks.get(j).select("a").text();
String uri = titleLinks.get(j).select("a").attr("href");
String desc = descLinks.get(j).select("span").text();
String time = timeLinks.get(j).select("span.other-left").select("a").text();
News news = new News(title,uri,desc,time);
newsList.add(news);
}
}
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}catch (Exception e){
e.printStackTrace();
}
}
}).start(); }
上一段代码相信通过备注就可以理解了,通过解析虎扑NBA新闻20页的每一页的网址,获取到每条新闻所需的数据,封装到实体类News中,再加入到MainActivity中声明的泛型为News的List即newsList中。等全部20页数据都获取到之后,用Message.what=1来作为数据加载完成的标志,并用Handler.sendMessage()将子线程的消息发送到主线程,通知主线程数据已加载完成,可以将数据加载到ListView上显示出来。
5.剩下的就简单了 ,为ListView做相关的配置
- news_item.xml:为ListView的item指定布局。放置三个TextView用来显示新闻标题,新闻概要,新闻时间及来源;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:id="@+id/news_title"
android:gravity="center_horizontal"
android:textColor="#000"
android:textSize="18sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:id="@+id/news_desc"
android:layout_marginBottom="6dp"
android:layout_marginLeft="10dp"
android:gravity="center_horizontal" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/news_time"
android:layout_marginBottom="6dp"
android:textSize="10sp"
android:textColor="#708090"
android:gravity="center_horizontal"
android:layout_marginRight="30dp" />
</LinearLayout>
- NewsAdapter.java:为ListView加载数据
public class NewsAdapter extends BaseAdapter {
private List<News> newsList;
private View view;
private Context mContext;
private ViewHolder viewHolder;
public NewsAdapter(Context mContext, List<News> newsList) {
this.newsList = newsList;
this.mContext= mContext;
}
@Override
public int getCount() {
return newsList.size();
}
@Override
public Object getItem(int position) {
return newsList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.news_item,
null);
viewHolder = new ViewHolder();
viewHolder.newsTitle = (TextView) view
.findViewById(R.id.news_title);
viewHolder.newsDesc = (TextView)view.findViewById(R.id.news_desc);
viewHolder.newsTime = (TextView)view.findViewById(R.id.news_time);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.newsTitle.setText(newsList.get(position).getNewsTitle());
viewHolder.newsDesc.setText(newsList.get(position).getDesc());
viewHolder.newsTime.setText("来自 : "+newsList.get(position).getNewsTime());
return view;
}
class ViewHolder{
TextView newsTitle;
TextView newsDesc;
TextView newsTime;
}
}
6.建立NewsDisplayActivity用于显示新闻的具体内容。
布局activity_display_news.xml:简单放入一个WebView,用于显示新闻
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/web_view"></WebView>
</LinearLayout>
NewsDisplayActivity.java
public class NewsDisplayActvivity extends AppCompatActivity {
private String newsUrl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_display);
newsUrl = getIntent().getStringExtra("news_url");
WebView webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl(newsUrl);
}
}
7.MainActivity用getNews()获取到数据后,在handlerMessage()方法里接受到子线程获取完数据的消息后,开始为ListView加载数据。并为ListView的item设置点击事件,当点击item时,将该item所对应的新闻的网址传递给NewsDisplayActivity,NewsDisplayActivity得到网址后用WebView加载该网址,便可看到新闻
public class MainActivity extends AppCompatActivity {
private List<News> newsList;
private NewsAdapter adapter;
private Handler handler;
private ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
newsList = new ArrayList<>();
lv = (ListView) findViewById(R.id.news_lv);
getNews();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 1){
adapter = new NewsAdapter(MainActivity.this,newsList);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
News news = newsList.get(position);
Intent intent = new Intent(MainActivity.this,NewsDisplayActvivity.class);
intent.putExtra("news_url",news.getNewsUrl());
startActivity(intent);
}
});
}
}
};
}
private void getNews(){
new Thread(new Runnable() {
@Override
public void run() {
try{
//获取虎扑新闻20页的数据,网址格式为:https://voice.hupu.com/nba/第几页
for(int i = 1;i<=20;i++) {
Document doc = Jsoup.connect("https://voice.hupu.com/nba/" + Integer.toString(i)).get();
Elements titleLinks = doc.select("div.list-hd"); //解析来获取每条新闻的标题与链接地址
Elements descLinks = doc.select("div.list-content");//解析来获取每条新闻的简介
Elements timeLinks = doc.select("div.otherInfo"); //解析来获取每条新闻的时间与来源
for(int j = 0;j < titleLinks.size();j++){
String title = titleLinks.get(j).select("a").text();
String uri = titleLinks.get(j).select("a").attr("href");
String desc = descLinks.get(j).select("span").text();
String time = timeLinks.get(j).select("span.other-left").select("a").text();
News news = new News(title,uri,desc,time);
newsList.add(news);
}
}
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
}
最后记得在AndroidManifest中添加网络请求的权限
2017.05.19更新(Github同步更新)
由于虎扑新闻网页做了调整,去除了新闻简介,所以这部分内容就获取不到了,所以相应的要修改代码,只需要getNews()方法中做三个修改
如下图,获取新闻简介的两句代码注释掉,News构造对象时,新闻简介参数传入null。这样改动较小,界面会丑点,自行调整便可。
源码下载地址:请戳这里##
总结:虽然只是一个简单的应用,但还是有所收获。有什么错误的地方,欢迎指出。菜鸟的点滴积累,希望能早日有所成长
Jsoup抓取网页数据完成一个简易的Android新闻APP的更多相关文章
- java抓取网页数据,登录之后抓取数据。
最近做了一个从网络上抓取数据的一个小程序.主要关于信贷方面,收集的一些黑名单网站,从该网站上抓取到自己系统中. 也找了一些资料,觉得没有一个很好的,全面的例子.因此在这里做个笔记提醒自己. 首先需要一 ...
- jsoup抓取网页+具体解说
jsoup抓取网页+具体解说 Java 程序在解析 HTML 文档时,相信大家都接触过 htmlparser 这个开源项目.我以前在 IBM DW 上发表过两篇关于 htmlparser 的文章.各自 ...
- web scraper 抓取网页数据的几个常见问题
如果你想抓取数据,又懒得写代码了,可以试试 web scraper 抓取数据. 相关文章: 最简单的数据抓取教程,人人都用得上 web scraper 进阶教程,人人都用得上 如果你在使用 web s ...
- c#抓取网页数据
写了一个简单的抓取网页数据的小例子,代码如下: //根据Url地址得到网页的html源码 private string GetWebContent(string Url) { string strRe ...
- 【iOS】正則表達式抓取网页数据制作小词典
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/xn4545945/article/details/37684127 应用程序不一定要自己去提供数据. ...
- 01 UIPath抓取网页数据并导出Excel(非Table表单)
上次转载了一篇<UIPath抓取网页数据并导出Excel>的文章,因为那个导出的是table标签中的数据,所以相对比较简单.现实的网页中,有许多不是通过table标签展示的,那又该如何处理 ...
- Asp.net 使用正则和网络编程抓取网页数据(有用)
Asp.net 使用正则和网络编程抓取网页数据(有用) Asp.net 使用正则和网络编程抓取网页数据(有用) /// <summary> /// 抓取网页对应内容 /// </su ...
- 使用HtmlAgilityPack批量抓取网页数据
原文:使用HtmlAgilityPack批量抓取网页数据 相关软件点击下载登录的处理.因为有些网页数据需要登陆后才能提取.这里要使用ieHTTPHeaders来提取登录时的提交信息.抓取网页 Htm ...
- 使用JAVA抓取网页数据
一.使用 HttpClient 抓取网页数据 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 ...
随机推荐
- 关于Oracle报表
1.存储过程中的WHEN OTHERS THEN是什么意思. 异常分很多种类,如NO_FOUND.OTHERS处本应该写异常名称,如果不想把异常分得那么细,可以笼统一点用OTHERS来捕获,即所有异常 ...
- python - jpype模块,python调用java的接口
转载自: http://www.cnblogs.com/junrong624/p/5278457.html https://www.cnblogs.com/fanghao/p/7745356.html ...
- 算法 - DNA搜索 - Ako Corasick
场景:从很长的字符串(输入字符串.DNA)中搜索大量固定字符串(字典.基因) 题目:Determining DNA Health | HackerRank 算法:Aho–Corasick algori ...
- c#端口扫描器wpf+socket
布局如下 <Window x:Class="PortTest.MainWindow" xmlns="http://schemas.microsoft.com/win ...
- nodejs 之简单web服务器
1.service.js var http=require('http');//引入http模块 var fs=require('fs');//fs模块 var path=require('path' ...
- Screen Painter 程序设计
一.Screen 的创建及维护, TCode:SE51 输入程序名称,单击[建立], 程序1000为SAP预留屏幕号,屏幕号必须定义1000外的其他数字,且最多不超过四位, 本例定义屏幕为SAP预留屏 ...
- JWT的实现原理
前言最近在做一个python项目的改造,将python项目重构为java项目,过程中遇到了这个知识点,觉得这个蛮实用的,所以下班后回来趁热打铁写下这篇总结,希望后面的人能够有所借鉴,少走弯路. 一.优 ...
- 【VS开发】【智能语音处理】Windows下麦克风语音采集
简介 这是我很早以前的大学毕业设计,忽然间找到贴出来以纪念自己的纯真年代...但是因为CSDN不给面子所以导致短短的一篇文章贴了足足7次..他老提时说文章超过了64K,老大,拜托,那是算上了里面的图片 ...
- 学习Linux第一周记
2019/11/25 服务器硬件详述1) CPU 作用:运算/控制 关注信息 :路数 服务器中CPU的颗数 一般有 (单路 双路 ...
- 干货 | 深入分析 string.intern() 方法
首先我们来看一段代码: public class InternTest { public static void main(String[] args) { String str1 ...