上周接了一个活,在没有api的情况下,对一个管理系统的网页进行移动端开发,因为之前做过一个没有现成api的项目,所以一开始就用fiddler进行抓包,结果很明显:什么都没有。
在网上搜索得知Jsoup可以做到,那就先学学Jsoup怎么用吧。
我选择 http://www.jcodecraeer.com/plus/list.php?tid=18 为样本,这个网页有标题,有描述,有时间,有图片。。。 非常适合做成listview啊。
用谷歌内核的浏览器访问网站 按下F12 出现调试工具 发现 该页面的每一个文章 是在 <li class="archive-item clearfix">中 所有的文章是在<ul class="archive-list">中
而Jsoup就是靠这些信息来帮我们选定需要的数据
新建方法 LoadHtml 前面2个参数都是空 因为访问网址直接在里面固定了 不需要获取 第三个参数 返回我们需要的list就行了
class LoadHtml extends AsyncTask<Void, Void, List<ArticleBean>>{ ProgressDialog bar; @Override protected List<ArticleBean> doInBackground(Void... params) { List<ArticleBean>articleBeans=new ArrayList<ArticleBean>(); try { Document doc = Jsoup.connect("http://www.jcodecraeer.com/plus/list.php?tid=18").timeout(5000).get(); Element masthead=doc.select("ul.archive-list").first(); //System.out.println("masthead"+masthead.toString()+"masthead"); Elements articleElements=masthead.select("li.archive-item.clearfix"); System.out.println("articleElements"+articleElements.toString()+"articleElements"); for (int i = 0; i < articleElements.size(); i++) { ArticleBean article = new ArticleBean(); Element articleElement=articleElements.get(i); Element titleElement=articleElement.select("h3").first(); System.out.println(titleElement.toString()+"titleElement"); //Elements titleElements=masthead.select("div.archive-detail h3"); Element summaryElement=articleElement.select("div.archive-detail p").first(); //Elements summaryElements=masthead.select("div.archive-detail p"); Element postTimeElement=articleElement.select("div.archive-text div.archive-detail div.archive-data span.glyphicon-class").first(); //Elements postTimeElements=masthead.select("div.archive-detail div.archive-data span.glyphicon-class"); String url="http://www.jcodecraeer.com/" +titleElement.attr("href"); String title=titleElement.text(); String summary=summaryElement.text(); String data=postTimeElement.text(); article.setTitle(title); article.setSummary(summary); article.setData(data); article.setNewsUrl(url); articleBeans.add(article); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return articleBeans; } @Override protected void onPreExecute() { super.onPreExecute(); bar=new ProgressDialog(MainActivity.this); bar.setMessage("waiting"); bar.setIndeterminate(false); bar.setCancelable(false); bar.show(); } @Override protected void onPostExecute(List<ArticleBean> result) { // TODO Auto-generated method stub super.onPostExecute(result); bar.dismiss(); TestAdapter adapter =new TestAdapter(result, getApplicationContext()); listView.setAdapter(adapter); } }
在doInBackground 方法中 使用Jsoup.connect方法访问网页 ,获取到Document对象。
每一个文章 是在 <li class="archive-item clearfix">中 所有的文章是在<ul class="archive-list">中
先找到整个文章的对象 Element masthead=doc.select("ul.archive-list").first();
再从整个文章的对象里面找到每个文章的对象 Elements articleElements=masthead.select("li.archive-item.clearfix");
看图可以发现 我们需要的数据全部都在里面 关键是如何取出来
我抽取一个 文章 标题在第10行 <h3>标签里
内容简介在第11行 <p>标签里
而时间在第34行 <span class="glyphicon-class">标签里
一开始我以为 都要把前面的标签都放进去 但是不需要 .first()方法是取第一个这种标签里面的数据 时间数据 和 观看人数 的标签是一样的 但是人数在前面 所以结果的图片显示的人数 而不是时间
标题 Element titleElement=articleElement.select("h3").first();
简介 Element summaryElement=articleElement.select("p").first();
时间 Element postTimeElement=articleElement.select("span.glyphicon-class").first(); 这么写 会显示最先使用这个标签的 “人数”
下面的形式也行 不过麻烦多了
简介 Element summaryElement=articleElement.select("div.archive-detail p").first();
时间使用下面的写法 才能正确的显示 ”时间“
Element postTimeElement=articleElement.select("div.archive-data span.glyphicon-class").first();
Element postTimeElement=articleElement.select("div.archive-text div.archive-detail div.archive-data span.glyphicon-class").first();
1 <li class="archive-item clearfix"> 2 <a href="/a/anzhuokaifa/androidkaifa/2016/0425/4178.html" title="解读Android官方MVP项目单元测试"> 3 4 <div class='covercon'> <img src='/uploads/20160425/1461550497774572-lp.png' class='cover imgloadinglater' style='display: block;' /> </div> 5 6 </a> 7 8 <div class="archive-text"> 9 <div class="archive-detail"> 10 <h3><a href="/a/anzhuokaifa/androidkaifa/2016/0425/4178.html" title="解读Android官方MVP项目单元测试" >解读Android官方MVP项目单元测试</a></h3> 11 <p>Google在3月份推出了一个项目,用来介绍Android MVP架构的各种组合,可以认为是官方在这方面的最佳实践。令人称道的是除了MVP本身之外,这些工程配备了极其完善的单元测试用例,学习价值极高。本文着重针对todo-mvp的单元测试进行解读。 写在前面 关于MVP 关 </p> 12 <div class="archive-info clearfix"> 13 <ul> 14 <li class="list-user"> 15 <a href="" target="_blank"> 16 <img src="/templets/jcodecraeer/images/iconfont-morentouxiang.png"> 17 <strong>泡在网上的日子</strong> 18 </a> 19 </li> 20 <li class="list-tag"><span><a href='/tags.php?/MVP/' class='tag'>MVP</a>,<a href='/tags.php?/单元测试/' class='tag'>单元测试</a> </span></li> 21 <li class="list-msg"> 22 <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> 23 <span class="glyphicon-class">102</span> 24 <span class="glyphicon glyphicon-comment" aria-hidden="true"></span> 25 <span class="glyphicon-class">0</span> 26 <span class="glyphicon glyphicon-bookmark" aria-hidden="true"></span> 27 <span class="glyphicon-class">2</span> 28 </li> 29 30 </ul> 31 </div> 32 <div class="archive-data"> 33 <span class="glyphicon glyphicon-time" aria-hidden="true"></span> 34 <span class="glyphicon-class">16-04-25</span> 35 </div> 36 37 </div> 38 </div> 39 </li><li class="archive-item clearfix">
获取到对象之后 转为 String
String title=titleElement.text();
String summary=summaryElement.text();
String data=postTimeElement.text();
然后设置给bean 最后 return articleBeans;
article.setTitle(title);
article.setSummary(summary);
article.setData(data);
articleBeans.add(article);
Adapter 和 ArticleBean 这些就不说了,怎么简单怎么来,暂时没设置图片
1 package com.demon.AJsoup; 2 3 import java.util.List; 4 5 import android.content.Context; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.BaseAdapter; 10 import android.widget.ImageView; 11 import android.widget.TextView; 12 13 public class TestAdapter extends BaseAdapter { 14 15 private List<ArticleBean> mlist; 16 private LayoutInflater mInflater; 17 18 19 public TestAdapter(List<ArticleBean> data, Context context) { 20 mlist = data; 21 mInflater=LayoutInflater.from(context); 22 } 23 24 @Override 25 public int getCount() { 26 // TODO Auto-generated method stub 27 return mlist.size(); 28 } 29 30 @Override 31 public Object getItem(int arg0) { 32 // TODO Auto-generated method stub 33 return mlist.get(arg0); 34 } 35 36 @Override 37 public long getItemId(int arg0) { 38 // TODO Auto-generated method stub 39 return arg0; 40 } 41 42 @Override 43 public View getView(int arg0, View convertView, ViewGroup arg2) { 44 ViewHodler hodler=null; 45 if (convertView==null) { 46 hodler=new ViewHodler(); 47 convertView=mInflater.inflate(R.layout.item, null); 48 hodler.title=(TextView) convertView.findViewById(R.id.title); 49 hodler.summary=(TextView) convertView.findViewById(R.id.summary); 50 hodler.data=(TextView) convertView.findViewById(R.id.data); 51 hodler.iv=(ImageView) convertView.findViewById(R.id.iv); 52 53 convertView.setTag(hodler); 54 } 55 else { 56 hodler=(ViewHodler) convertView.getTag(); 57 } 58 59 hodler.title.setText(mlist.get(arg0).getTitle()); 60 hodler.summary.setText(mlist.get(arg0).getSummary()); 61 hodler.data.setText(mlist.get(arg0).getData()); 62 63 hodler.iv.setImageResource(R.drawable.ic_launcher); 64 65 return convertView; 66 } 67 68 class ViewHodler{ 69 public TextView title,summary,data; 70 public ImageView iv; 71 72 } 73 }
1 package com.demon.AJsoup; 2 3 public class ArticleBean { 4 @Override 5 public String toString() { 6 return "ArticleBean [Title=" + Title + ", Summary=" + Summary 7 + ", Data=" + Data + ", NewsUrl=" + NewsUrl + "]"; 8 } 9 public String getTitle() { 10 return Title; 11 } 12 public void setTitle(String title) { 13 Title = title; 14 } 15 public String getSummary() { 16 return Summary; 17 } 18 public void setSummary(String summary) { 19 Summary = summary; 20 } 21 public String getData() { 22 return Data; 23 } 24 public void setData(String data) { 25 Data = data; 26 } 27 public String getNewsUrl() { 28 return NewsUrl; 29 } 30 public void setNewsUrl(String newsUrl) { 31 NewsUrl = newsUrl; 32 } 33 public String Title; 34 public String Summary; 35 public String Data; 36 public String NewsUrl; 37 38 }
由于我使用了 ProgressDialog 所以在onPreExecute()方法中 要做下设置
@Override protected void onPreExecute() { super.onPreExecute(); bar=new ProgressDialog(MainActivity.this); bar.setMessage("waiting"); bar.setIndeterminate(false); bar.setCancelable(false); bar.show(); }
在 onPostExecute()方法中 要把ProgressDialog 注销 并把adapter适配给listview
@Override protected void onPostExecute(List<ArticleBean> result) { super.onPostExecute(result); bar.dismiss(); TestAdapter adapter =new TestAdapter(result, getApplicationContext()); listView.setAdapter(adapter); }
最后 回到oncreate方法中
new LoadHtml().execute();
效果如下 懒得改了 这里时间显示成了人数 具体原因 回去看红字
写这篇文章主要是为了学习一下 jsoup的使用方法 然而开发移动端 一般都会有json
能不能完成那个活 我还不确定 因为还有登陆这一个难题