android 爬虫服务器,Android编写简单的网络爬虫

本文详细介绍了Android平台上的网络爬虫实现过程,包括网络爬虫的基本概念、遍历策略,以及Android应用中网络爬虫的实战演示。通过HttpClient发送请求获取网页内容,使用Jsoup库解析HTML并提取所需数据,最后展示在ListView中。此外,还涉及了ListView的下拉刷新和上拉加载功能,以及数据解析和页面跳转的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、网络爬虫的基本知识

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

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

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

看一下效果

b7170f61e9ead94dddf196213435ff8b.png

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

是这样的

12098cf61139f37a5770af3631d2dc43.png

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

反正自己还挺喜欢的

然后就看看是怎么弄的

9a5376c45fb2539bc9dee179b5b0e180.png

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

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

c652ead558c700d2d66d49e25eb3019e.png

就像这样

然后把每一次遍历的数据都加到集合里面 给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开发的过程中有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值