使用Jsoup非同步抓取新聞資料裝載listview(仿開源中國資訊列表)
最近想寫一下開源中國的客戶端,但是不想自己造資料,才發現有jsoup這麼好用的東西。使用jsoup,你在網站上能看到的任何東西都可以解析出來。jsoup是一個解析網頁原始碼的開源庫,他能按照給定的規則提取出一個網頁中的任意元素,和其他網頁解析庫不同的是,他提取網頁內容的方式和css、jquery的選擇器非常相似。
我們看一下網頁中的資訊和最終的實現效果(網頁截圖比手機截圖晚了兩個小時湊合看吧 0.0):
jsoup規則其實並不難:
開啟開源中國新聞資訊的網頁,右鍵檢視原始碼,找到資訊相關的<div>。
<div class="panel" id='RecentNewsList'> <h3 class='tabs'> <ul> <li><a href="/news/list" class='active'>全部資訊</a></li> <li><a href="/news/list?show=industry">綜合資訊</a></li> <li><a href="/news/list?show=project">軟體更新資訊</a></li> </ul> </h3> <ul class='List'> <li> <h2><a href="/news/72054/mybatis-spring-boot-1-0-2" target="_blank">Mybatis Spring Boot 1.0.2 釋出</a></h2> <p class='date'><a href="http://my.oschina.net/u/2305107">淡漠悠然</a> 釋出於 1小時前 - 3評</p> <p class='detail'>Mybatis Spring Boot 1.0.2 釋出了,Mybatis Spring Boot 是 MyBatis 和 Spring Boot 的整合。 暫無相關改進說明,檢視專案提交記錄,可點選這裡。 下載: Source code (zip) Source code (tar.gz)...</p> <p class='more'><a href="/news/72054/mybatis-spring-boot-1-0-2" target="_blank" class='more'>顯示全文</a></p> </li> <li> <a href="/news/72053/windows-10" target="_blank" class='img'><img src="/img/logo/windows.gif?t=1451964198000" border='0'/></a> <h2><a href="/news/72053/windows-10" target="_blank">Win10 年度最重大更新:程式碼、理想與愛</a></h2> <p class='date'><a href="http://my.oschina.net/osadmin">oschina</a> 釋出於 5小時前 - 29評</p> <p class='detail'>微軟 Build 2016 大會,讓圍繞 Windows 10 的軟體開發變得格外矚目。 在這次,微軟依舊在開發者大會上帶來了 Windows 10、平臺軟體開發、HoloLens、人工智慧方面的技術進展,當然最讓普通消費者關心的仍然是 Wind...</p> <p class='newsImg'><a title="Win10 年度最重大更新:程式碼、理想與愛" href="/news/72053/windows-10" target="_blank"><img alt="...." src="http://static.oschina.net/uploads/space/2016/0331/115526_bt3I_1774694.png"></a></p> <p class='more'><a href="/news/72053/windows-10" target="_blank" class='more'>顯示全文</a></p> </li><span style="font-family: 'lucida grande', 'lucida sans unicode', lucida, helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif; line-height: 23.8px;"> </span>
我們會發現所有的資訊都在id為RecentNewsList的div中,jsoup提供了getElementById()方法:
Document doc = Jsoup.connect(path).timeout(5000).get();
Element masthead = doc.getElementById("RecentNewsList");
這時masthead中就包含了d為RecentNewsList的div中所有的資訊。我們再仔細觀察發現,資訊都是在class為List的ul中,並且以<li></li>為一組,jsoup提供了select()方法,條件遞進,用空格分開:
Elements articleElements = masthead.select("ul.List li");
ul.List表示class為List的ul,articleElements中包含了所有以<li></li>為一組資訊資訊,每一組資訊如果獲取標題,詳情和發表資訊可用以下程式碼:
此時titleElement,summaryElement,timeElement分別裝著標題,詳情和發表資訊。Elements titleElement = articleElement.select("h2 a"); Elements summaryElement = articleElement.select("p.detail"); Elements timeElement = articleElement.select("p.date");
以articleElements中的資料作為資料來源的話,我們要以articleElements的長度做個迴圈,逐個取出以上三個資訊賦值給一個Article物件,並將每一個Article物件放到定義的ArrayList物件中中。此時將ArrayList物件作為資料來源設定ListView介面卡。
下面我們看怎麼一步步實現的:
1、首先新建android工程,下載jsoup的jar包匯入工程,由於ADT升級到版本20以後無法載入這個包,用builtpath的方式可能會報錯 java.lang.noclassdeffounderror:org/jsoup/Jsoup,如果報錯,先把jar包remove掉,然後直接將jsoup.jar拷到libs資料夾下,clean一下工程就好了。
2、新建Article實體類,作為ListView介面卡的適配型別
package com.example.osnews;
public class Article {
private String title="";
private String summary="";
private String postTime="";
public Article(String title,String summary,String postTime){
this.title=title;
this.summary=summary;
this.postTime=postTime;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getPostTime() {
return postTime;
}
public void setPostTime(String postTime) {
this.postTime = postTime;
}
}
3、新建ListView的介面卡ListAdapter
package com.example.osnews;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class ListAdapter extends BaseAdapter {
private ArrayList<Article> mArticleList;
private int resourceId;
private Context ctx;
public ListAdapter(Context context, int textViewResourceId, ArrayList<Article> objects) {
resourceId = textViewResourceId;
this.mArticleList = objects;
this.ctx = context;
}
@Override
public int getCount() {
return mArticleList.size();
}
@Override
public Article getItem(int position) {
return mArticleList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Article article = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null) {
view= LayoutInflater.from(ctx).inflate(resourceId, null);
viewHolder = new ViewHolder();
viewHolder.title = (TextView) view.findViewById(R.id.title);
viewHolder.summary = (TextView) view.findViewById(R.id.summary);
viewHolder.postTime = (TextView) view.findViewById(R.id.postTime);
view.setTag(viewHolder);
} else {
view=convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.title.setText(article.getTitle());
viewHolder.summary.setText(article.getSummary());
viewHolder.postTime.setText(article.getPostTime());
return view;
}
static class ViewHolder {
public TextView title;
public TextView summary;
public TextView postTime;
}
}
4、佈局檔案,就上面一個標題和下面一個listView,自己在下載原始碼檢視。
5、MainActivity.java
package com.example.osnews;
import java.io.IOException;
import java.util.ArrayList;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView listview;
private String path = "http://www.oschina.net/news";
private ListAdapter adapter;
@SuppressLint("HandlerLeak")
private Handler handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 1 :
listview.setAdapter(adapter);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
listview = (ListView) this.findViewById(R.id.listview);
new GetListData().execute(path);
}
class GetListData extends AsyncTask<String, Void, ArrayList<Article>> {
@Override
protected ArrayList<Article> doInBackground(String... arg0) {
ArrayList<Article> articleList =new ArrayList<Article>();
try {
Document doc = Jsoup.connect(path).timeout(5000).get();
Element masthead = doc.getElementById("RecentNewsList");
Elements articleElements = masthead.select("ul.List li");
if (doc != null) {
for(int i = 0; i < articleElements.size(); i++) {
Element articleElement = articleElements.get(i);
Elements titleElement = articleElement.select("h2 a");
Elements summaryElement = articleElement.select("p.detail");
Elements timeElement = articleElement.select("p.date");
String title = titleElement.text();
String summary = summaryElement.text();
//if(summary.length() > 70)
// summary = summary.substring(0, 70);
String postTime = timeElement.text();
Log.i("title", title);
Log.i("summary", summary);
Log.i("postTime", postTime);
Article article = new Article(title,summary,postTime);
articleList.add(article);
}
}
} catch (IOException e) {
e.printStackTrace();
}return articleList;
}
@Override
protected void onPostExecute(ArrayList<Article> articleList) {
super.onPostExecute(articleList);
adapter = new ListAdapter(MainActivity.this,R.layout.item_article_list,articleList);
Log.i("adapter", "----------"+adapter.isEmpty());
Message msg = Message.obtain();
msg.what=1;
handler.sendMessage(msg);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
6.AndroidManifest.xml中新增的上網許可權
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
原始碼下載:http://download.csdn.net/detail/chunxiao123ouc/9478282