当前位置: 移动技术网 > 移动技术>移动开发>Android > Android编写简单的网络爬虫

Android编写简单的网络爬虫

2019年07月24日  | 移动技术网移动技术  | 我要评论
一、网络爬虫的基本知识 网络爬虫通过遍历互联网络,把网络中的相关网页全部抓取过来,这体现了爬的概念。爬虫如何遍历网络呢,互联网可以看做是一张大图,每个页面看做其中的一个节

一、网络爬虫的基本知识

网络爬虫通过遍历互联网络,把网络中的相关网页全部抓取过来,这体现了爬的概念。爬虫如何遍历网络呢,互联网可以看做是一张大图,每个页面看做其中的一个节点,页面的连接看做是有向边。图的遍历方式分为宽度遍历和深度遍历,但是深度遍历可能会在深度上过深的遍历或者陷入黑洞。所以,大多数爬虫不采用这种形式。另一方面,爬虫在按照宽度优先遍历的方式时候,会给待遍历的网页赋予一定优先级,这种叫做带偏好的遍历。

实际的爬虫是从一系列的种子链接开始。种子链接是起始节点,种子页面的超链接指向的页面是子节点(中间节点),对于非html文档,如excel等,不能从中提取超链接,看做图的终端节点。整个遍历过程中维护一张visited表,记录哪些节点(链接)已经处理过了,跳过不作处理。

二、android网络爬虫demo的简单实现

看一下效果

抓的是这个网页 然后写了一个app

是这样的

把listview做成卡片式的了 然后配色弄的也很有纸质感啊啊啊

反正自己还挺喜欢的

然后就看看是怎么弄的

看一下每个类都是干啥的 :

mainactivity:主界面的activity

mainadapter:listview的适配器

networkclass:链接网络 使用httpclient发送请求、接收响应得到content 大概就是拿到了这个网页的什么鬼东西

还有好多就是一个html的代码 要解析这个

news:这个类里有两个属性 一个标题 一个是这个标题新闻点进去那个url;

newsactivity:详细新闻界面

pulllistview:重写了listview 具有下拉刷新和上拉加载功能

然后从oncreat()开始看:

protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    initview();
    mainthread mt = new mainthread(newsurl);
    final thread t = new thread(mt, "mainthread");
    t.start();

    pulllistview.setonrefreshlistener(new pulllistview.onrefreshlistener() {
      @override
      public void onrefresh() {
        isgetmore = false;
        mainthread mt = new mainthread(newsurl);
        thread t = new thread(mt, "mainthread");
        t.start();

      }
    });

    pulllistview.setongetmorelistener(new pulllistview.ongetmorelistener() {
      @override
      public void ongetmore() {
        isgetmore = true;
        if (num > 1) {
          mainthread mt = new mainthread(nextpage);
          thread t = new thread(mt, "mainthread");
          t.start();
        }

      }
    });
    pulllistview.setonitemclicklistener(new adapterview.onitemclicklistener() {
      @override
      public void onitemclick(adapterview<?> parent, view view, int position, long id) {
        intent intent = new intent(mainactivity.this,newsactivity.class);
        intent.putextra("url",list.get(position-1).geturl());
        startactivity(intent);

      }
    });

  }

这个里面主要就是先初始化了数据

然后new了一个线程 因为涉及到了网络请求 所以我们要开线程去执行 然后有一些listview的下拉上拉点击的绑定

所以主要内容是在线程里面

再看线程之前 先看一下networkclass

package com.example.katherine_qj.news;

import android.net.http.httpresponsecache;
import android.util.log;

import org.apache.http.httpresponse;
import org.apache.http.client.httpclient;
import org.apache.http.client.methods.httpget;
import org.apache.http.impl.client.defaulthttpclient;

import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstream;
import java.io.inputstreamreader;

/**
 * created by katherine-qj on 2016/7/24.
 */
public class networkclass {
  public string getdatabyget(string url){
    log.e("qwe","content");
    string content ="";
    httpclient httpclient = new defaulthttpclient();
    log.e("qwe","content1");
    /*使用httpclient发送请求、接收响应很简单,一般需要如下几步即可。
    1. 创建httpclient对象。
    2. 创建请求方法的实例,并指定请求url。如果需要发送get请求,创建httpget对象;如果需要发送post请求,创建httppost对象。
    3. 如果需要发送请求参数,可调用httpget、httppost共同的setparams(hetpparams params)方法来添加请求参数;对于httppost对象而言,也可调用setentity(httpentity entity)方法来设置请求参数。
    4. 调用httpclient对象的execute(httpurirequest request)发送请求,该方法返回一个httpresponse。
    5. 调用httpresponse的getallheaders()、getheaders(string name)等方法可获取服务器的响应头;调用httpresponse的getentity()方法可获取httpentity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
    6. 释放连接。无论执行方法是否成功,都必须释放连接*/
    httpget httpget = new httpget(url);
    try {
      httpresponse httpresponse = httpclient.execute(httpget);
      // httpreponse是服务器接收到浏览器的请求后,处理返回结果常用的一个类。
      if(httpresponse.getstatusline().getstatuscode() == 200) {
        /*getstatusline()
        获得此响应的状态行。状态栏可以设置使用setstatusline方法之一,也可以在构造函数初始化*/
        inputstream is = httpresponse.getentity().getcontent();
        /*getentity()
        获取此响应的消息实体,如果有。实体是通过调用setentity提供。*/
        bufferedreader reader = new bufferedreader(new inputstreamreader(is));
        string line;
        while ((line = reader.readline()) != null){
          content += line;
        }
      }
    }catch (ioexception e)
    {
      log.e("http",e.tostring());
    }
    log.e("sdf",content);
    return content;
  }
}

注释的很详细了

大概就是 有一个getdatabyget方法 然后接受一个url参数 经过一系列请求得到网页内容 返回一个content

下来就是使用这个类的线程了

 public class mainthread implements runnable{
    private string url;
    public mainthread(string url){
      this.url = url;
    }
    @override
    public void run() {
      networkclass networkclass =new networkclass();//new 了一个network类
      content = networkclass.getdatabyget(url);//接收这个类返回的那个字符串也就是需要解析的那一串
      log.e("qwe",content);
      handler.sendemptymessage(111);
    }
  }

就是利用这个线程去得到content 然后通过handle传递到主线程去解析

   private final android.os.handler handler = new android.os.handler(){
    public void handlemessage(message msg){
      switch (msg.what){
        case 111:
          analysehtml();
          if(isgetmore){
            mainadapter.notifydatasetchanged();
      /*每一次notifydatasetchange()都会引起界面的重绘。当需要修改界面上view的相关属性的时候,
       最后先设置完成再调用notifydatasetchange()来重绘界面。*/
          }else {
            mainadapter = new mainadapter(mainactivity.this, list);
            pulllistview.setadapter(mainadapter);
          }
          pulllistview.refreshcomplete();
          pulllistview.getmorecomplete();
          break;
      }
    }
   };

analysehtml();

发现其实解析的东西在这个方法里面 所以 这里才是解析网页的东西啊:

 public void analysehtml(){
     if(content!=null){
       int x= 0;
       document document = jsoup.parse(content);
       //解析html字符串
       if (!isgetmore) {
         list.clear();
         element element = document.getelementbyid("fanye3942");//拿到fanye3942这个节点
         string text = element.text();//得到这个节点的文本部分
         system.out.print(text);
         num = integer.parseint(text.substring(text.lastindexof('/') + 1, text.length() - 1));
         system.out.print(num);
       }
         elements elements = document.getelementsbyclass("c3942");//得到c3942这个节点中的所有子节点
         while(true){
          if(x==elements.size()){
            system.out.print(elements.size());
            break;//遍历到最后就退出
          }
           news news = new news();
           news.settitle(elements.get(x).attr("title"));//分别得到每一个子节点的需要的文本部分
           news.seturl(elements.get(x).attr("href"));
          // list.add(news);
           if (!isgetmore||x>10){
             list.add(news);
             if(x>=25){
               break;
             }//这个是因为我们学校的网页有重复
           }
           x++;

         }
         if (num>1){
           nextpage = url+"/"+ --num+".htm";//因为有翻页这里得到了下一页的url在上拉的时候会开启线程去请求数据
           system.out.println("qqqqqqqqqqq"+nextpage);
         }

       }
     }

document 对象使我们可以从脚本中对 html 页面中的所有元素进行访问。

所以android基于jsoupcontent搞成document 对象

然后就可以慢慢分解去拿了 然后拿哪里的数据就要看需要了

我开始一直不知道那些fanye3942 c3942是啥 后来才知道是需要的数据的节点id或者class

就像这样

然后把每一次遍历的数据都加到集合里面 给listview绑定集合就好了

大概主页面就是这样 然后跳转页面 就是因为news里面还放入了每一个新闻点击之后的url所以传到newsactivity中再利用相同的思路去解析显示就好了

package com.example.katherine_qj.news;

import android.app.activity;
import android.os.bundle;
import android.os.message;
import android.util.log;
import android.widget.edittext;
import android.widget.textview;

import org.jsoup.jsoup;
import org.jsoup.nodes.document;
import org.jsoup.nodes.element;
import org.jsoup.select.elements;

/**
 * created by katherine-qj on 2016/7/25.
 */
public class newsactivity extends activity {
  private textview texttitle;
  private textview textedit;
  private textview textdetail;
  private string title;
  private string edit;
  private string detail;
  private stringbuilder text;
  private string url;
  private document document;
  private string content;
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_news);
    initview();
    url=getintent().getstringextra("url");
    log.e("qqq",url);
    newsthread newsthread = new newsthread(url);

    final thread t = new thread(newsthread,"newsactivity");
    t.start();

  }
  public void initview(){
    texttitle =(textview)findviewbyid(r.id.texttitle);
    textedit =(textview)findviewbyid(r.id.textedit);
    textdetail = (textview)findviewbyid(r.id.textdetail);
  }
  private final android.os.handler handler = new android.os.handler(){
   public void handlemessage(message msg){
     if(msg.what==1001){
       document = jsoup.parse(content);
       analysehtml(document);
       texttitle.settext(title);
       textedit.settext(edit);
       textdetail.settext(text);
     }

   }
  };
  public class newsthread implements runnable{
    string url;
    public newsthread(string url){
      this.url = url;
    }
    @override
    public void run() {

      networkclass networkclass = new networkclass();
      content = networkclass.getdatabyget(url);
      system.out.print("qqq"+content);
      handler.sendemptymessage(1001);
    }


  }
  public void analysehtml(document document){
    if (document!=null){
      element element = document.getelementbyid("nrys");
      elements elements = element.getallelements();
      title = elements.get(1).text();
      edit = elements.get(4).text();
      element melement = document.getelementbyid("vsb_content_1031");
      if(melement != null) {
        elements melements = melement.getallelements();
        text = new stringbuilder();
        for (element melement : melements) {
          if(melement.classname().equals("nrzwys") || melement.tagname().equals("strong")){
            continue;
          }

          if(!melement.text().equals(" ") && !melement.text().equals(""));{
            text.append(" ").append(melement.text()).append("\n");
          }
          if (melement.classname().equals("vsbcontent_end")) {
            break;
          }
        }
      }
    }
  }
}

以上就是基于android编写简单的网络爬虫的全部内容,本文介绍的很详细,希望给大家在android开发的过程中有所帮助。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网