【问题】
之前已经实现了基本的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中,自己找了找,看到一些和网络相关的,比如:
貌似最接近我的需求。
其中包括了很多的Http相关的类:
HttpRequest
An HTTP request.HttpResponse
An HTTP response.
下面,就是去找找其示例代码,然后去写代码了。
3.去看看对应的类的详细解释:
不过没看到太多有用的。
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.后来找到:
好像更像是所需要的。
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.所以再去网上找找,如何添加这两个权限。
最后是参考:
去到AndroidManifest.xml中添加了这两个权限:
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
所以,还真是之前的问题,所以再去修改:
把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:
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);
    	    }
    	});的运行结果:
【总结】
想要实现抓取网页,必须有个前提,那就是:
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中如何用代码实现去抓取网页



