制作网页的Android客户端(一)

当发现一个有趣的新闻网站(AnimeNews)没有android客户端时,打算做一个学习和自用。

0.简单的需求分析

  1.能看新闻

  2.能查单词

  3.单词表

1.建立新闻的抽象类

  需要的属性有:

    新闻标题 

    新闻内容链接

    新闻描述

    新闻发布时间

    新闻分类

    新闻编辑

    新闻封面

    新闻正文 

package com.saltwater.animenews;

/**新闻元素类
 * Created by xin on 2016/10/22.
 * @version 1.1
 */

public class NewsItem {
    private String mTitle=null;
    private String mLink=null;
    private String mDescription=null;
    private String mPubData=null;
    private String mCategory=null;
    private String mEditor=null;
    private String mCover=null;
    private String mContent=null;

    public String getTitle() {
        return mTitle;
    }

    public String getEditor() {
        return mEditor;
    }

    public String getDescription() {
        return mDescription;
    }

    public String getCover() {
        return mCover;
    }

    public String getContent() {
        return mContent;
    }

    public String getPubData() {
        return mPubData;
    }

    public String getLink() {
        return mLink;
    }

    public String getCategory() {
        return mCategory;
    }

    public void setTitle(String title) {
        mTitle = title;
    }

    public void setEditor(String author) {
        mEditor = author;
    }

    public void setDescription(String description) {
        mDescription = description;
    }

    public void setCover(String picture) {
        mCover = picture;
    }

    public void setContent(String content) {
        mContent = content;
    }

    public void setPubData(String pubData) {
        mPubData = pubData;
    }

    public void setLink(String link) {
        mLink = link;
    }

    public void setCategory(String Category) {
        this.mCategory = Category;
    }
}

 

2.获取新闻内容

  一开始的选择是爬虫获取所有的内容,然后建立自己的服务器。学习Python2天后,失败于爬虫,放弃。

  第二选择使用RSS(AnimeNewsRSS)。其他属性都有了,就缺少一个封面图的链接。为了美观还是选择放弃。如果打算使用RSS的话有个Rome的开源包很好用。

  最后选择jsoup解析HTML。优点是网页上展示的所有想要的东西都可以抓下来,还可以自动更新内容。缺点是新闻条目少,只有200多条,但是自用还是够了。然后如果网站的Html格式换了要重新去解析,RSS基本很少会变格式。

  

  Jsoup的使用

    首先添加jsoup的jar包(如果使用Android Studio直接在Library Dependency搜jsoup添加就好了)

    

    然后添加一个工具类使用jsoup解析Html,参考http://www.open-open.com/jsoup/学习jsoup解析。

    1.与目标URL建立链接,获取到Html文档  

 Document doc = Jsoup.connect(mURL).get();

    2.从Html文档提取需要的属性

      这里需要的属性需要从Html中去找,如果使用Chrome浏览器,可以很方便的用右键的检查功能来定位想要的属性在Html文档中的位置。

      

   

/*这是一个完整的新闻div*/ 
<div class="herald box news" data-topics="article108636 news people"> <div class="category-line news"></div> <div class="thumbnail" style="background-image: url(/thumbnails/cover400x200/cms/news/108636/bg_contents01.jpg); background-position: 51.873% 0.000%;"> <div class="overlay"> <div class="category news"> news </div> <div class="comments"><a href="/cms/discuss/108636">1 comments</a></div> </div> <a href="/news/2016-11-09/kamen-rider-blade-star-takayuki-tsubaki-seriously-injured-in-traffic-dispute/.108636" data-track="id=35655&amp;from=HP.MF"></a> </div> <div class="wrap"> <div> <h3> <a href="/news/2016-11-09/kamen-rider-blade-star-takayuki-tsubaki-seriously-injured-in-traffic-dispute/.108636" data-track="id=35655&amp;from=HP.MF"><i>Kamen Rider Blade</i> Star Takayuki Tsubaki Seriously Injured in Traffic Dispute</a> </h3> <div class="byline"> <time datetime="2016-11-09T09:37:48Z"> Nov 9, 04:37 </time> <div class="comments"><a href="/cms/discuss/108636">1 comments</a></div> <span class="topics"> <span class="people">people</span> </span> </div> <div class="preview"> <span class="intro">Actor allegedly struck in face with golf club Tuesday evening</span> <span class="full">― 34-year-old Kamen Rider Blade lead actor Takayuki Tsubaki sustained serious injuries when he was beaten in the face with a golf club at the end of a traffic dispute in Tokyo's Nakano Ward on Tuesday evening. Tsubaki had stepped from the sidewalk onto the roadway after 9:00 p.m. on Tuesday in Nakano's Chuo area, and he engaged in an argum...</span> </div> </div> </div> </div>

  我们可以发现每一条新闻都是在class="herald box news"这个div内,所以通过

 Elements elements = doc.select("div[class=herald box news]");

  获取到Html所有的class="herald box news"的div,放了elements这个集合中。然后通过foreach循环提取每个div中的内容

  需要提一下的是因为提起到的PubData属性是UTC时间字符串(<time datetime="2016-11-09T09:37:48Z">),所以需要转换一下。

  还有就是对class属性值含有空格的标签(div class="herald box news")进行提取时,利用doc.select("dherald box news")是提取不到结果的,因为这里有三个class。应该使用doc.select("div[class=herald box news]"),所以程序中尽可能还是用[attr=val]模式进行查询。

  

for(Element element : elements) {
                    mItem=new NewsItem();
                    mItem.setLink(element.getElementsByClass("wrap").select("div").select("h3").select("a").attr("href"));
                    mItem.setCover(element.getElementsByClass("thumbnail").attr("style"));
                    mItem.setTitle(element.getElementsByClass("wrap").select("div").select("h3").select("a").text());
                    mItem.setDescription(element.getElementsByClass("wrap").select("div").select("div[class=preview]").text());
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                    df.setTimeZone(TimeZone.getTimeZone("UTC"));
                    String time =new SimpleDateFormat("yyyy/MM/dd HH:mm").format(df.parse(element.getElementsByClass("wrap").select("div").select("div[class=byline]").select("time").attr("datetime")));
                    mItem.setPubData(time);
                    mItem.setCategory(element.getElementsByClass("wrap").select("div").select("div[class=byline]").select("span[class=topics]").text());
                    newsList.add(mItem);
                }

完整的工具类

  

package com.saltwater.animenews;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ListView;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

/**解析Html
 * Created by xin on 2016/10/28.
 * @version 2.0
 */

public class DataLoadTask extends AsyncTask<Void,Integer,List<NewsItem>> {
    private String mURL ="http://www.animenewsnetwork.com/news";
    private NewsItem mItem=null;
    public static List<NewsItem> newsList=null;
    private ListView mListView=null;
    private Context mContext=null;

    public DataLoadTask(Context context, ListView lv)
    {
        this.mContext=context;
        this.mListView=lv;
    }
    /*预处理方法*/
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    /*异步线程*/
    @Override
    protected List<NewsItem> doInBackground(Void... params) {

            try {
                Log.d("out","start");
                newsList=new ArrayList<NewsItem>();
                Document doc = Jsoup.connect(mURL).get();

                /*// 修改http包中的header,伪装成浏览器进行抓取
                conn.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:32.0) Gecko/    20100101 Firefox/32.0");*/

                /*解析Html,获取数据*/
                Elements elements = doc.select("div[class=herald box news]");

                for(Element element : elements) {
                    mItem=new NewsItem();
                    mItem.setLink(element.getElementsByClass("wrap").select("div").select("h3").select("a").attr("href"));
                    mItem.setCover(element.getElementsByClass("thumbnail").attr("style"));
                    mItem.setTitle(element.getElementsByClass("wrap").select("div").select("h3").select("a").text());
                    mItem.setDescription(element.getElementsByClass("wrap").select("div").select("div[class=preview]").text());
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                    df.setTimeZone(TimeZone.getTimeZone("UTC"));
                    String time =new SimpleDateFormat("yyyy/MM/dd HH:mm").format(df.parse(element.getElementsByClass("wrap").select("div").select("div[class=byline]").select("time").attr("datetime")));
                    mItem.setPubData(time);
                    mItem.setCategory(element.getElementsByClass("wrap").select("div").select("div[class=byline]").select("span[class=topics]").text());
                    newsList.add(mItem);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        finally {
                Log.d("out",newsList.size()+"item");
            }
        return newsList;
    }
    /*绑定adapter*/
    @Override
    protected void onPostExecute(final List<NewsItem> newsList) {
        super.onPostExecute(newsList);
        NewsListAdapter adapter=new NewsListAdapter(newsList,mContext);
        mListView.setAdapter(adapter);
    }
}

 

  

posted @ 2016-11-09 20:25  TheSaltWater  阅读(416)  评论(0编辑  收藏  举报