android 开发--抓取网页解析网页内容的若干方法(网络爬虫)(正则表达式)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sac761/article/details/48379173

网页有两种格式,一种是xml另一种是html,目前似乎好像大部分都是html格式的,查看网页格式的方法是在浏览器中右键-->查看源码

一,XML解析的三大方法

(1) SAX: Simple API for XML

SAX是一个解析速度快并且占用内存少的XML解析器。SAX解析XML文件采用的是事件驱动,也就是它并不需要解析完整个文档,
在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否符合XML语法中的某部分,如果符合则触发事件其实就是一些回调函数,
这些方法定义在ContentHandler

(2)DOM:Document Object Model

DOM解析是将XML文件全部载入,组成一颗dom树,然后通过节点以及节点之间的关系来解析XML文件。
对于特别大的文档,解析和加载整个文档可能很慢且很耗资源。

(3)pull

Pull是Android内置的xml解析器Pull解析器的运行方式与SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。


二,HTML解析的三大方法

(1)Jsoup

jsoup 是一款 Java 的HTML 解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。
这个方法很简便,但是成功率不大,不推荐。
(2)urlconnection
与httpclient相似,httpclient是增强版的urlconnection

(3)httpclient

HttpClient是一个很方便进行Http连接操作的工具包,用它可以设置代理和模拟浏览器下载网页。而HtmlParser则是一个开源的,可以对HTML进行处理的工具包,可以很方便的对HTML进行解析。


三,HttpClient源码讲解

本源码实现了抓取网页上的部分内容,并分栏显示出来,改进自laihuan99的博文Android抓取CSDN首页极客头条内容--网页数据抓取

MainActivity2.java

package com.example.webdatashow;
 //使用HttpClient组件访问网络以及获取 网页内容的方法。
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;

import android.view.View;
import android.view.View.OnClickListener;

import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity2 extends Activity implements OnClickListener{
	ListView listview;
    private String TAG = "webdatashow";
    private Button jiazai;
    private TextView webDataShow;
    private String pediyUrl = "http://www.stdu.edu.cn/";   
	Handler handler; 
    List<Map<String, Object>> data;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);  
        jiazai = (Button)findViewById(R.id.button1);
        webDataShow = (TextView)findViewById(R.id.webDataShow1);
        jiazai.setOnClickListener(this);    
    }
 
    @Override
    public void onClick(View view) {
            handler = getHandler();
            ThreadStart();
    }
    
    /*httpClientWebData()
     * 返回值类型:String
     * 抓取网页的document
     * 
     * */
    protected String httpClientWebData() {
    	String content = null;
        DefaultHttpClient httpClinet = new DefaultHttpClient(); //创建一个HttpClient 
        HttpGet httpGet = new HttpGet(pediyUrl);//创建一个GET请求 
        ResponseHandler<String> responseHandler = new BasicResponseHandler();         
			try {
				content = httpClinet.execute(httpGet, responseHandler);
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}//发送GET请求,并响应内容
			return content;   
    }
    
    /*getDate()
     * 返回值类型:List<Map<String, Object>>
     * 提取网页document的所需内容
     * 
     * */
	private List<Map<String, Object>> getDate() {
		String httpstring = httpClientWebData();
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		Pattern p = Pattern.compile("latestnewsnews  |  </span>\\s*<span style="white-space:pre">	</span><a href=\"(.*?)\" title=\"(.*?)\"");//正则表达式
		Matcher m = p.matcher(httpstring);
		while (m.find()) {
			MatchResult mr=m.toMatchResult();
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("title", mr.group(1));
			map.put("url", mr.group(2));
			result.add(map);
		}
		return result;	
	}
	
	  /*ThreadStart()
     * 开辟新线程
     * 
     * */
	private void ThreadStart() {
		new Thread() {
			public void run() {
				Message msg = new Message();
				try {
					data = getDate();
					msg.what = data.size();
				} catch (Exception e) {
					e.printStackTrace();
					msg.what = -1;
				}
				handler.sendMessage(msg);
			}
		}.start();
	}
	private Handler getHandler() {
    	return new Handler(){
			public void handleMessage(Message msg) {
				if (msg.what < 0) {
					Toast.makeText(MainActivity2.this, "数据获取失败", Toast.LENGTH_SHORT).show();
				}else {
					initListview();
				}
			}
        };
	}
	
	  /*initListview()
     * 在listview中显示数据
     * 
     * */
	private void initListview() {
		Toast.makeText(getApplicationContext(), "doing......", Toast.LENGTH_SHORT).show(); 
		ListView listView = (ListView) findViewById(R.id.listView1);	
		listView.setAdapter(new SimpleAdapter(this,data , android.R.layout.simple_list_item_2,
				new String[] { "title","href" }, new int[] {
				android.R.id.text1,android.R.id.text2
		}));

	}

}
main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
   <TextView
       android:id="@+id/webDataShow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
         android:text="" />
    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="加载" />

    <ListView
        android:id="@+id/listView1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </ListView>
    
 

</LinearLayout>

manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.webdatashow"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.webdatashow.MainActivity2"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


最后写一点关于正则表达式的写法:

需要下载一个工具:RegexTester.exe下载

比如提取这一段源码中的新闻标题

 </div>
  	      <div class="contentarea">	
		  	
             <div id="news">
              			    <div id="news_1">
                		<div class="moduletablenews">
					<h3>学校新闻</h3>
					
<div class="newnotice"><div>今日共<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33.html"><font color="red">0</font></a>信息更新</div></div><ul class="feednews-ul">
	<li class="latestnewsnews">
	<span id="date">09-10  |  </span>
	<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33/21883-2015-09-10-03-51-32.html" title="我校召开第三十一个教师节庆祝表彰大会" target="_blank">
			我校召开第三十一个教师节庆祝表彰大会    
	</a></li>
	<li class="latestnewsnews">
	<span id="date">09-09  |  </span>
	<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33/21884-2015-09-10-07-09-14.html" title="重传承、勇创新:四方学院圆满完成迎新工作" target="_blank">
			重传承、勇创新:四方学院圆满完成迎...    
	</a></li>
	<li class="latestnewsnews">
	<span id="date">09-07  |  </span>
	<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33/21844-2015-09-07-10-10-04.html" title="交通学院:同忆抗战史,共筑中国梦" target="_blank">
			交通学院:同忆抗战史,共筑中国梦    
	</a></li>
	<li class="latestnewsnews">
	<span id="date">09-06  |  </span>
	<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33/21834-2015-09-06-08-16-17.html" title="欧洲科学院院士张传增教授来校做学术报告" target="_blank">
			欧洲科学院院士张传增教授来校做学术报告    
	</a></li>
共同的格式是这样的:

<li class="latestnewsnews">
	<span id="date">09-10  |  </span>
	<a href="http://xcb.stdu.edu.cn/2009-05-05-02-26-33/21883-2015-09-10-03-51-32.html" title="我校召开第三十一个教师节庆祝表彰大会" target="_blank">
			我校召开第三十一个教师节庆祝表彰大会    
	</a></li>
用(.*?)代替所需要的内容,于是在RegexTester.exe中输入下式能通过。(\2表示与第二个所需内容重复)

class="latestnewsnews">
	<span id="date">09-10  |  </span>
	<a href="(.*?)" title="(.*?)" target="_blank">
			\2 
继续精简去掉无用的:通过
latestnewsnews	<span>  |  </span>
	<a href=\"(.*?)\" title=\"(.*?)\" target=\"_blank\">
			\2 
再多试试去掉其它的杂草:

latestnewsnews	  |  </span>
	<a href="(.*?)" title="(.*?)"
最后用\\s代替换行,并在每个"前加\

latestnewsnews  |  </span>\\s*<span style="white-space:pre">	</span><a href=\"(.*?)\" title=\"(.*?)\"
这就是最好的形态,

说明一下,不好的正则表达式会严重地影响匹配时间从而影响你app的运行速度,要反复研究出最好的正则表达式以便让你的app更流畅。








猜你喜欢

转载自blog.csdn.net/sac761/article/details/48379173