【问题】
之前已经实现了基本的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中如何用代码实现去抓取网页