最新消息:20210917 已从crifan.com换到crifan.org

【已解决】Android中如何用代码实现去抓取网页

Android crifan 4011浏览 0评论

【问题】

之前已经实现了基本的Android的app的界面了,并且也可以获得从输入框中所输入的内容了:

【记录】实现安卓版的DownloadSongtasteMusic中的响应按钮点击

然后接着去要实现,在Android中,通过代码实现抓取对应的网页的内容。

比如songtaste中的某个歌曲播放页面:

http://www.songtaste.com/song/3208674/

现在要获得对应的html的代码。

【解决过程】

1.去网上搜,找到了:

How to create web crawler in java?

然后去打开了对应的android的API。

2.在Android的API中,自己找了找,看到一些和网络相关的,比如:

org.apache.http

貌似最接近我的需求。

其中包括了很多的Http相关的类:

HttpRequest
An HTTP request. 

HttpResponse
An HTTP response.

下面,就是去找找其示例代码,然后去写代码了。

3.去看看对应的类的详细解释:

public interface HttpRequest

不过没看到太多有用的。

4.去API Guides中看看。

好像Connectivity中的:

Android’s HTTP Clients

Most network-connected Android apps will use HTTP to send and receive data. Android includes two HTTP clients: HttpURLConnection and Apache HTTP Client. Both support HTTPS, streaming uploads and downloads, configurable timeouts, IPv6 and connection pooling.

像是所需要的。

但是悲催的去打开:

http://android-developers.blogspot.com/2011/09/androids-http-clients.html

却无法打开了。

5.后来找到:

public interface HttpClient

好像更像是所需要的。

6.不过又看到这个:

Android Asynchronous Http Client

貌似已经帮我们封装好了对应的库了。

7.这里:

Android中使用HTTPClient进行网络通讯的例子(Android HttpClient use example)

也有不错的,关于HttpClient的参考代码。

但是,还是决定先去试试上面那个封装好的库。

8.点击:

Android Asynchronous Http Client

中的下载:

http://cloud.github.com/downloads/loopj/android-async-http/android-async-http-1.4.2.jar

得到26KB的:android-async-http-1.4.2.jar

放到对应的app的lib文件夹:

D:\tmp\tmp_dev_root\android\android_root\DownloadSongtasteMusic\libs

下面。

去源码中导入,结果出错,具体解决过程参考:

【已解决】Android中导入一个lib后出错:The import com.loopj cannot be resolved

9.然后继续写测试代码,运行一下,看看结果如何,结果始终无法运行到onSuccess,具体折腾过程参见:

【未解决】Android中使用Android Asynchronous Http Client结果无法执行到onSuccess函数

 

10.实在受不了了,还是自己去参考之前的HttpClient,自己写代码吧。

参考:

Android中使用HTTPClient进行网络通讯的例子(Android HttpClient use example)

去写代码:

import java.io.IOException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.HttpStatus;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.ClientProtocolException;



    	HttpGet request = new HttpGet(strSongUrl);
    	HttpClient httpClient = new DefaultHttpClient();
    	
        try {
            HttpResponse response = httpClient.execute(request);
            //if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
            	System.out.println(response);
            //}
        } catch (ClientProtocolException cpe) {
            // TODO Auto-generated catch block
        	cpe.printStackTrace();    
        } catch (IOException ioe) {
            // TODO Auto-generated catch block
        	ioe.printStackTrace();
        }
    }
}

结果,也还是无法运行到

System.out.println(response);

所以,貌似此处app的网络访问有问题。

13.参考:

Android HTTP Access – Tutorial

看起来像是我的app没有设置网络权限,所以才无法访问网络的。

所以就去配置权限。

安装教程所说,由于此处是Android 4.2,所以需要添加代码运行在UI中使用Network,但是又由于当前API level是8,不是9,所以又不能添加StrictMode,所以干脆先注释掉对应代码:

//import android.os.StrictMode;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
//        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
//		StrictMode.setThreadPolicy(policy); 
    }

然后再继续去配置。

但是,教程中,并没有对相应的权限参数:

  • android.permission.INTERNET
  • android.permission.ACCESS_NETWORK_STATE

进行解释。

14.所以再去网上找找,如何添加这两个权限。

最后是参考:

android.permission.INTERNET

去到AndroidManifest.xml中添加了这两个权限:

add two permission

15.再去运行上述代码,看看效果如何。

结果无法调试出所需要的效果

具体折腾参见:

【未解决】Android开发中,用ADT调试apk时,无法单步调试Step Over,会跳转到Source Not Found

16.然后再去参考:

第三十讲:URLConnection和HttpClient使用入门

去试试:

    	String googleWeatherUrl2 = "http://www.google.com/ig/api?hl=zh-cn&weather=zhengzhou";
    	DefaultHttpClient httpclient = new DefaultHttpClient();
    	//HttpGet httpget = new HttpGet(googleWeatherUrl2);
    	HttpGet httpget = new HttpGet(strSongUrl);
    	ResponseHandler<String> responseHandler = new BasicResponseHandler();
		try {
			String content = httpclient.execute(httpget, responseHandler);
			Toast.makeText(getApplicationContext(), "连接Google Weather API成功!", Toast.LENGTH_SHORT).show();
			etUrlOrId.setText(content);
		} catch (Exception e) {
			Toast.makeText(getApplicationContext(), "连接Google Weather API失败", Toast.LENGTH_SHORT).show();
			e.printStackTrace();
		}
		httpclient.getConnectionManager().shutdown();

结果还是不行。

17.再去参考:

Android HTTP Access – Tutorial

用代码:

    	//http://www.vogella.com/articles/AndroidNetworking/article.html

    	// Somewhere in your code this is called
    	// in a thread which is not the user interface
    	// thread
		try {
			//URL url = new URL("http://www.vogella.com");
			URL url = new URL(strSongUrl);
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			readStream(con.getInputStream());
		  } 
		catch (Exception e) {
			e.printStackTrace();
		}

出错了。

但是,至少可以获得当前出错的原因:

android.os.NetworkOnMainThreadException

android.os.NetworkOnMainThreadException

所以,还真是之前的问题,所以再去修改:

把AndroidManifest.xml中的:

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

改为:

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="16" />

然后再去添加对应的代码:

import android.os.StrictMode;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy); 
    }

然后再去试试,结果没了此异常了。

18.所以再回去试试之前的代码:

    	HttpGet request = new HttpGet(strSongUrl);
    	HttpClient httpClient = new DefaultHttpClient();
    	
        try {
            HttpResponse response = httpClient.execute(request);
            etUrlOrId.setText(response.toString());
            Log.d("Http Response:", response.toString());
            if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
            	System.out.println(response);
            }
        } catch (ClientProtocolException cpe) {
            // TODO Auto-generated catch block
        	cpe.printStackTrace();    
        } catch (IOException ioe) {
            // TODO Auto-generated catch block
        	ioe.printStackTrace();
        }

终于就可以正常执行了,返回的状态码是200:

statuscode 200

19.对应的,也去试了试之前的几种代码,可以的:

代码:

    	String strSongUrl = "http://www.songtaste.com/song/" + "3208674";
    	
    	//String baiduUrl = "http://www.baidu.com";
    	AsyncHttpClient client = new AsyncHttpClient();
    	//client.get("http://www.google.com", new AsyncHttpResponseHandler() {
    	client.get(strSongUrl, new AsyncHttpResponseHandler() {
    	//client.get(baiduUrl, new AsyncHttpResponseHandler() {
    	    @Override
    	    public void onSuccess(String response) {
    	        System.out.println(response);
    	    }
    	});

的运行结果:

async also work

 

【总结】

想要实现抓取网页,必须有个前提,那就是:

1. 能访问网络

  • 修改AndroidManifest.xml,在<application>xxx</application>之前,添加对应的:
	<uses-permission android:name="android.permission.INTERNET"></uses-permission>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>

2. 由于新版Android中不能在UI中访问网络,所以要规避这个限制

  • 要保证确保你的api level是大于9的,否则就像我这里要去修改AndroidManifest.xml,把:
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

改为:

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="16" />
  • 去你的程序MainActivity.java中,添加:
import android.os.StrictMode;

然后在onCreate函数中,添加上:

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy);

 

满足了前提条件之后,再去实现你的代码,比如类似于这样的代码:

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpStatus;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;

    /** Called when the user clicks the Download button */
    public void preformDownload(View view) {
        String strSongUrl = "http://www.songtaste.com/song/" + "3208674";
        
        HttpGet request = new HttpGet(strSongUrl);
        HttpClient httpClient = new DefaultHttpClient();
        
        try {
            HttpResponse response = httpClient.execute(request);
            if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                System.out.println(response);
            }
        } catch (ClientProtocolException cpe) {
            // TODO Auto-generated catch block
            cpe.printStackTrace();    
        } catch (IOException ioe) {
            // TODO Auto-generated catch block
            ioe.printStackTrace();
        }
    }

 

就最终可以实现访问网络,获得响应,获得网页的源码了。

转载请注明:在路上 » 【已解决】Android中如何用代码实现去抓取网页

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
93 queries in 0.182 seconds, using 23.40MB memory