Android编写简单的网络爬虫

作者:daisy 时间:2023-09-24 03:44:52 

一、网络爬虫的基本知识

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

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

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

看一下效果

Android编写简单的网络爬虫

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

是这样的

Android编写简单的网络爬虫

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

反正自己还挺喜欢的

然后就看看是怎么弄的

Android编写简单的网络爬虫

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

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

Android编写简单的网络爬虫

就像这样

然后把每一次遍历的数据都加到集合里面 给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,爬虫
0
投稿

猜你喜欢

  • 详解Java的位操作符

    2023-06-24 05:31:14
  • Flutter Flow实现滑动显隐层示例详解

    2022-01-29 23:50:56
  • 浅析Spring 中 Bean 的理解与使用

    2023-07-09 03:12:03
  • 一文理解kafka rebalance负载均衡

    2022-12-02 10:35:22
  • C#实现的字符串转MD5码函数实例

    2023-03-02 15:34:43
  • java面向对象设计原则之合成复用原则示例详解

    2023-11-09 16:55:51
  • 浅谈Android面向切面编程(AOP)

    2022-04-03 15:14:41
  • springboot vue组件开发实现接口断言功能

    2023-11-12 10:26:53
  • java10下编译lombok注解代码分享

    2023-06-06 11:02:35
  • MyBatis自定义映射关系和关联查询实现方法详解

    2021-12-18 21:25:28
  • Idea2020.2创建JavaWeb项目(部署Tomcat)方法详解

    2023-11-02 13:29:52
  • Java Redis Redisson配置教程详解

    2022-10-13 06:32:39
  • Spring Security权限管理实现接口动态权限控制

    2022-07-03 12:25:53
  • 清楚详解Android 进程间图传递图形buffer原理

    2023-05-14 12:57:09
  • Java下http下载文件客户端和上传文件客户端实例代码

    2021-09-09 16:52:11
  • Java使用BIO和NIO进行文件操作对比代码示例

    2023-04-18 16:14:21
  • Android开发实现控件双击事件的监听接口封装类

    2023-02-15 00:56:18
  • Java算法之最长公共子序列问题(LCS)实例分析

    2022-12-06 08:31:42
  • Android手机卫士之设置密码对话框

    2021-08-03 07:24:27
  • ContentProvider启动流程示例解析

    2023-07-31 03:57:34
  • asp之家 软件编程 m.aspxhome.com