利用java呼叫百度API介面,解析返回的json資料,突破百度API介面呼叫結果的限制
近一段時間的專案的核心是百度API的POI(興趣點)資料,所以需要呼叫百度API資料,下面就來講一下整個流程和遇到的問題及解決辦法。
首先要檢視百度API文件,連結如下:http://lbsyun.baidu.com/index.php?title=webapi 專案中主要用到的是Place API 以及座標轉換API。
剛開始準備呼叫API的時候就遇到了一個很大的問題:每次呼叫API最多返回400條結果。也就是說,當爬取某個區域的POI資料時,最多隨機返回400條結果。由於Place API提供了一個引數tag,即標籤,碰到這個問題的第一反應是是否可以通過標籤分類進行更小粒度的爬取。然而Place API提供了三種區域範圍的搜尋:城市內檢索、矩形區域檢索、圓形區域檢索。如果按照城市內區域檢索,由於城市區域範圍過大,顯然利用標籤還是無法解決資料量限制的問題,所以只能通過矩形或者圓形區域檢索。這時想到了GIS專業軟體arcgs可以對區域進行分塊然後對每個小區域進行遍歷,於是就對整個城市進行了更小粒度的區域(600m*600m的正方形)劃分,最終返回每個小區域邊界的大地座標。
由於百度地圖POI的座標採用百度座標系,所以需要將大地座標轉換為百度座標,轉換座標的API服務地址為:
接下來就是要呼叫百度API,java程式碼如下:
是的package com.baiduapi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import com.baiduapi.ConvertCoordinate; import com.bean.CommunityInf; import com.bean.FoodInf; import com.conndatabase.DBOperateFood; import net.sf.json.JSONObject; import net.sf.json.JSONArray; import net.sf.json.JSONException; public class GetFoodDetail { String ak = ""; int count = 0; int num = 0; String query = null; String data = null; String la1 = null; String ln1 = null; String la2 = null; String ln2 = null; URL myURL = null; InputStreamReader insr = null; BufferedReader br = null; CommunityInf comm = null; String food_Uid; String food_Name; String food_Addr; String food_Lat; String food_Lng; String food_StreetId; String food_Tag; String food_Type; String food_Price; String food_OverAllRating; String food_TasteRating; String food_ServiceRating; String food_EnviorRating; String food_ImageNum; String food_GrouponNum; String food_CommentNum; String food_Location; String detail = null; public void getFood(String q, String lat1, String lng1, String lat2,String lng2, String region) throws IOException //獲取百度美食POI的資料 { try { query = java.net.URLEncoder.encode(q, "UTF-8"); la1 = java.net.URLEncoder.encode(lat1, "UTF-8"); ln1 = java.net.URLEncoder.encode(lng1, "UTF-8"); la2 = java.net.URLEncoder.encode(lat2, "UTF-8"); ln2 = java.net.URLEncoder.encode(lng2, "UTF-8"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } for (int j = 0; j < 20; j++) { String url = String .format("http://api.map.baidu.com/place/v2/search?query=%s&page_size=20&page_num=" + j + "&bounds=%s,%s,%s,%s&output=json&ak=%s", query, la1, ln1, la2, ln2, ak); // System.out.println(url); URLConnection conn = null; try { myURL = new URL(url); } catch (MalformedURLException e) { e.printStackTrace(); } try { conn = (URLConnection) myURL.openConnection(); if (conn != null) { insr = new InputStreamReader(conn.getInputStream(), "UTF-8"); br = new BufferedReader(insr); StringBuilder sb = new StringBuilder(""); while ((data = br.readLine()) != null) { System.out.println(data); sb.append(data.trim()); } String str = sb.toString(); JSONObject jsonObj = JSONObject.fromObject(str); // System.out.println(jsonObj); num = num + 1; System.out.println("#" + num); if (jsonObj.getInt("total") == 0) { break; } new FoodInf(); JSONArray results = jsonObj.getJSONArray("results"); // System.out.println(results.size()); for (int i = 0; i < results.size(); i++) { JSONObject results0 = results.getJSONObject(i); food_Uid = results0.getString("uid"); getDetail(food_Uid, region); } } } catch (IOException e) { e.printStackTrace(); } finally { if (insr != null) { insr.close(); } if (br != null) { br.close(); } } } } private void getDetail(String uid, String region) throws IOException, net.sf.json.JSONException { // 獲取美食POI的細節資料並解析儲存到本地資料庫中 String detail_url = String .format("http://api.map.baidu.com/place/v2/detail?uid=%s&output=json&scope=2&ak=%s", uid, ak); URLConnection conn = null; try { myURL = new URL(detail_url); } catch (MalformedURLException e) { e.printStackTrace(); } try { conn = (URLConnection) myURL.openConnection(); if (conn != null) { insr = new InputStreamReader(conn.getInputStream(), "UTF-8"); br = new BufferedReader(insr); StringBuilder sb = new StringBuilder(); while ((data = br.readLine()) != null) { System.out.println(data); sb.append(data.trim()); } String detail = sb.toString(); System.out.println("##" + detail); try { JSONObject results0 = JSONObject.fromObject(detail) .getJSONObject("result"); food_Name = results0.getString("name"); food_Addr = results0.getString("address"); try { results0.getString("street_id"); } catch (JSONException jsonExp) { food_StreetId = "-"; } try { results0.getString("location"); food_Location = results0.getString("location"); String loc[] = food_Location.split(","); food_Lng = (String) loc[0].subSequence( food_Location.indexOf(":") + 1, food_Location.indexOf(",")); food_Lat = (String) loc[1].subSequence( loc[1].indexOf(":") + 1, loc[1].indexOf("}")); } catch (JSONException jsonExp) { food_Lng = "-"; food_Lat = "-"; } results0.getString("detail_info"); detail = results0.getString("detail_info"); JSONObject jsonObj1 = JSONObject.fromObject(detail); // System.out.println(jsonObj1); try { jsonObj1.getString("image_num"); food_ImageNum = jsonObj1.getString("image_num"); } catch (JSONException jsonExp) { food_ImageNum = "-"; } try { jsonObj1.getString("price"); food_Price = jsonObj1.getString("price"); } catch (JSONException jsonExp) { food_Price = "-"; } try { jsonObj1.getString("tag"); food_Tag = jsonObj1.getString("tag"); } catch (JSONException jsonExp) { food_Tag = "-"; } try { jsonObj1.getString("type"); food_Type = jsonObj1.getString("type"); } catch (JSONException jsonExp) { food_Type = "-"; } try { jsonObj1.getString("overall_rating"); food_OverAllRating = jsonObj1 .getString("overall_rating"); } catch (JSONException jsonExp) { food_OverAllRating = "-"; } try { jsonObj1.getString("taste_rating"); food_TasteRating = jsonObj1.getString("taste_rating"); } catch (JSONException jsonExp) { food_TasteRating = "-"; } try { jsonObj1.getString("service_rating"); food_ServiceRating = jsonObj1 .getString("service_rating"); } catch (JSONException jsonExp) { food_ServiceRating = "-"; } try { jsonObj1.getString("environment_rating"); food_EnviorRating = jsonObj1 .getString("environment_rating"); } catch (JSONException jsonExp) { food_EnviorRating = "-"; } try { jsonObj1.getString("groupon_num"); food_GrouponNum = jsonObj1.getString("groupon_num"); } catch (JSONException jsonExp) { food_GrouponNum = "-"; } try { jsonObj1.getString("comment_num"); food_CommentNum = jsonObj1.getString("comment_num"); } catch (JSONException jsonExp) { food_CommentNum = "-"; } } catch (JSONException jsonExp) { food_ImageNum = "-"; food_Price = "-"; food_Tag = "-"; food_Type = "-"; food_OverAllRating = "-"; food_TasteRating = "-"; food_ServiceRating = "-"; food_EnviorRating = "-"; food_GrouponNum = "-"; food_CommentNum = "-"; } FoodInf food = new FoodInf(); food.setFood_Addr(food_Addr); food.setFood_CommentNum(food_CommentNum); food.setFood_EnviorRating(food_EnviorRating); food.setFood_GrouponNum(food_GrouponNum); food.setFood_ImageNum(food_ImageNum); food.setFood_Lat(food_Lat); food.setFood_Lng(food_Lng); food.setFood_Name(food_Name); food.setFood_OverAllRating(food_OverAllRating); food.setFood_Price(food_Price); food.setFood_ServiceRating(food_ServiceRating); food.setFood_StreetId(food_StreetId); food.setFood_Tag(food_Tag); food.setFood_TasteRating(food_TasteRating); food.setFood_Type(food_Type); food.setFood_Uid(uid); food.setFood_region(region); // System.out.println(community.getCommunity_Uid()+"#"+community.getCommunity_Name() // + "#" // +community.getCommunity_Addr()+"#"+community.getCommunity_StreetId()+"#"+community.getCommunity_Lng()+"#"+community.getCommunity_Lat()+"#"+community.getCommunity_Image_Num()+"#"+community.getCommunity_Price()+"#"+community.getCommunity_Tag()+"#"+community.getCommunity_Type()+"#"+community.getCommunity_Overall_Rating()+"#"+community.getCommunity_Region()); DBOperateFood operate = new DBOperateFood(); operate.inserData(food); } } catch (IOException e) { e.printStackTrace(); } finally { if (insr != null) { insr.close(); } if (br != null) { br.close(); } } } public void setCoor(String la1, String ln1, String la2, String ln2, String region) throws IOException { //轉換座標系 ConvertCoordinate coor = new ConvertCoordinate(); Object[] llocation = coor.getCoordinate(la1, ln1); String lat1 = llocation[0].toString(); String lng1 = llocation[1].toString(); Object[] rlocation = coor.getCoordinate(la2, ln2); String lat2 = rlocation[0].toString(); String lng2 = rlocation[1].toString(); // System.out.println(lat1+"#"+lng1+"#"+lat2+"#"+lng2); GetFoodDetail foodDetail = new GetFoodDetail(); foodDetail.getFood("美食", lat1, lng1, lat2, lng2, region); }
程式碼寫的比較爛,大體實現了整個功能,但是仍有幾點需要注意和解決的問題:
1、利用arcgis劃分的區域並不算太準確,在邊界處可能存在越界的問題,所以需要對爬取下來的資料進行進一步的篩選。
2、就算是劃分到600m*600m的小區域內,呼叫API所返回的資料也有可能超過400條,這種情況目前所能想到的解決辦法就是儘可能的根據POI標籤進行分類爬取。