今天,写了个小代码。抓取首页中的极客头条。效果如图:
分享给新手朋友。
要点:
1. 使用Apache HttpClient库实现GET请求。
2. 异步请求处理。
3. 正则表达式抓取自己需要的数据。
1. 使用Apache HttpClient库实现GET请求。
使用Apache只需简单三步
- HttpClient httpClient = new DefaultHttpClient(); //创建一个HttpClient
- HttpGet httpGet = new HttpGet(“http://www.youkuaiyun.com/”); //创建一个GET请求
- HttpResponse response = httpClient.execute(httpGet); //发送GET请求,并响应内容
异步请求的实现也很简单,开辟新线程执行请求处理,请求完成通过Handler在主线程处理所获得的数据。具体看代码。
3. 正则表达式抓取自己需要的数据。
这个更简单,我推荐一个工具RegexTester,使用方法在相关文档。
我这里说下,就算你什么正则表达式一点都不知道,你只要知道(.*?)就可以了。它可以让你抓取基本上所有你需要的数据。
".*?"注意是三个字符一起,代表贪婪匹配任意数量的任意字符。可以简单的理解为任何字符。
如"a.*?b"对字符串"eabcd",进行匹配,将找到"abcd",其中".*?"匹配"bc"。
我们需要抓取的内容一般用"(.*?)"表示,注意这里是包含括号的。这很重要,用括号表示我们要提取的内容。
我们具体分析优快云首页源代码,下面每步操作都应该在RegexTester测试进行。
很容易找到,我们要抓取内容的毎一条是如下格式。
- <li><a title="宇宙员在太空中如何洗澡、睡觉、上厕所?" href="http://geek.youkuaiyun.com/news/detail/1478" target="_blank" onclick="LogClickCount(this,363);">宇宙员在太空中如何洗澡、睡觉、上厕所?</a></li>
- <li><a title="(.*?)" href="(.*?)" target="_blank" onclick="LogClickCount(this,363);">\1</a></li>
同理如果我们用“\2”将代表与第二个括号相同内容。这里我们没有使用。
用工具测试通过,发现没问题,能找出。
再简化,我们删去一些对定位无关紧要的内容,这步简化要测试,保证匹配内容同上。
- title="(.*?)" href="(.*?)" target="_blank" onclick="LogClickCount(this,363)
提取我们要的内容。
- title="(.*?)" href="(.*?)".*?363
- "title=\"(.*?)\" href=\"(.*?)\".*?363"
- Pattern p = Pattern.compile("title=\"(.*?)\" href=\"(.*?)\".*?363");
- Matcher m = p.matcher(csdnString); //csdn首页的源代码字符串
- while (m.find()) { //循环查找匹配字串
- MatchResult mr=m.toMatchResult();
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("title", mr.group(1));//找到后group(1)是表达式第一个括号的内容
- map.put("url", mr.group(2));//group(2)是表达式第二个括号的内容
- result.add(map);
- }
- public class MainActivity extends ListActivity {
- ListView listview;
- Handler handler;
- List<Map<String, Object>> data;
- final String 优快云URL = "http://www.youkuaiyun.com/";
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- handler = getHandler();
- ThreadStart();
- }
- /**
- * 新开辟线程处理联网操作
- * @author Lai Huan
- * @created 2013-6-20
- */
- private void ThreadStart() {
- new Thread() {
- public void run() {
- Message msg = new Message();
- try {
- data = getCsdnNetDate();
- msg.what = data.size();
- } catch (Exception e) {
- e.printStackTrace();
- msg.what = -1;
- }
- handler.sendMessage(msg);
- }
- }.start();
- }
- /**
- * 联网获得数据
- * @return 数据
- * @author Lai Huan
- * @created 2013-6-20
- */
- private List<Map<String, Object>> getCsdnNetDate() {
- List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
- String csdnString = http_get(优快云URL);
- //<li><a title="(.*?)" href="(.*?)" target="_blank" onclick="LogClickCount this,363 ;">\1</a></li>
- //title="(.*?)" href="(.*?)".*?,363\)
- Pattern p = Pattern.compile("title=\"(.*?)\" href=\"(.*?)\".*?363");
- Matcher m = p.matcher(csdnString);
- 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;
- }
- /**
- * 处理联网结果,显示在listview
- * @return
- * @author Lai Huan
- * @created 2013-6-20
- */
- private Handler getHandler() {
- return new Handler(){
- public void handleMessage(Message msg) {
- if (msg.what < 0) {
- Toast.makeText(MainActivity.this, "数据获取失败", Toast.LENGTH_SHORT).show();
- }else {
- initListview();
- }
- }
- };
- }
- /**
- * 在listview里显示数据
- * @author Lai Huan
- * @created 2013-6-20
- */
- private void initListview() {
- listview = getListView();
- SimpleAdapter adapter = new SimpleAdapter(this, data,
- android.R.layout.simple_list_item_1, new String[] { "title"},
- new int[] { android.R.id.text1 });
- listview.setAdapter(adapter);
- listview.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- Map<String, Object> map = data.get(arg2);
- String url = (String)(map.get("url"));
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent .setData(Uri.parse(url));
- startActivity(intent);
- }
- });
- }
- /**
- * get请求URL,失败时尝试三次
- * @param url 请求网址
- * @return 网页内容的字符串
- * @author Lai Huan
- * @created 2013-6-20
- */
- private String http_get(String url) {
- final int RETRY_TIME = 3;
- HttpClient httpClient = null;
- HttpGet httpGet = null;
- String responseBody = "";
- int time = 0;
- do {
- try {
- httpClient = getHttpClient();
- httpGet = new HttpGet(url);
- HttpResponse response = httpClient.execute(httpGet);
- if (response.getStatusLine().getStatusCode() == 200) {
- //用utf-8编码转化为字符串
- byte[] bResult = EntityUtils.toByteArray(response.getEntity());
- if (bResult != null) {
- responseBody = new String(bResult,"utf-8");
- }
- }
- break;
- } catch (IOException e) {
- time++;
- if (time < RETRY_TIME) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- }
- continue;
- }
- e.printStackTrace();
- } finally {
- httpClient = null;
- }
- } while (time < RETRY_TIME);
- return responseBody;
- }
- private HttpClient getHttpClient() {
- HttpParams httpParams = new BasicHttpParams();
- //设定连接超时和读取超时时间
- HttpConnectionParams.setConnectionTimeout(httpParams, 6000);
- HttpConnectionParams.setSoTimeout(httpParams, 30000);
- return new DefaultHttpClient(httpParams);
- }
- }
正则表达式30分钟入门教程 http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html