Android编写简单的网络爬虫
一、网络爬虫的基本知识
网络爬虫通过遍历互联网络,把网络中的相关网页全部抓取过来,这体现了爬的概念。爬虫如何遍历网络呢,互联网可以看做是一张大图,每个页面看做其中的一个节点,页面的连接看做是有向边。图的遍历方式分为宽度遍历和深度遍历,但是深度遍历可能会在深度上过深的遍历或者陷入黑洞。所以,大多数爬虫不采用这种形式。另一方面,爬虫在按照宽度优先遍历的方式时候,会给待遍历的网页赋予一定优先级,这种叫做带偏好的遍历。
实际的爬虫是从一系列的种子链接开始。种子链接是起始节点,种子页面的超链接指向的页面是子节点(中间节点),对于非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基于Jsoup 把content搞成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开发的过程中有所帮助。