獲取天氣預報亂碼處理


因為業務需求需要獲取獲取天氣信息,在獲取天氣信息遇到n多問題(感覺沒愛了),以下是問題及解決

1.url關閉

之前獲取天氣預報的url :http://m.weather.com.cn/data/101110101.html  直接gg了,所以只能找其他的url代替了,找了半天找到了它

http://wthrcdn.etouch.cn/weather_mini?citykey=xxxxx  后面的xxxx指的是城市id,那么這個城市id怎么獲取呢,

繼續找找找了這個url:http://cj.weather.com.cn/support/Detail.aspx?id=51837fba1b35fe0f8411b6df這里面我們可以找打很多的id號,但是這么多的id不至於我們一個一個手動輸入我們的數據庫吧,答案當然不是,這個時候我們就可以使用我們強大的htmlunit網頁抓取工具把我們想要的信息抓取出來,然后進行字符串分割保存到數據庫中,具體如何抓取代碼如下:

public static List<City> getCityInfo(){
        //設置htmlunit不打印日志
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog"); 
        WebClient webClient = new WebClient(BrowserVersion.CHROME);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        
        webClient.getOptions().setJavaScriptEnabled(true);
        webClient.getOptions().setActiveXNative(false);
        webClient.getOptions().setCssEnabled(false);
        webClient.getOptions().setThrowExceptionOnScriptError(false);

        webClient.setAjaxController(new NicelyResynchronizingAjaxController());

        webClient.getOptions().setJavaScriptEnabled(true);
        
        List<City> result = new ArrayList<City>();
        try {
            //獲取城市id的url
            String url = "http://cj.weather.com.cn/support/Detail.aspx?id=51837fba1b35fe0f8411b6df";
            
            //通過webclient模擬一個網頁,當然模擬的是這個url的
            HtmlPage page = webClient.getPage(url);
            
            //可以通過瀏覽器看到信息是放在p節點里的,所以我們獲取所有的p節點
            DomNodeList<DomElement> list = page.getElementsByTagName("p");
          
            //遍歷元素
            for(DomElement domElement : list){
                //這句話是為了過濾多余的標題和結尾信息
                String attr = domElement.getAttribute("style");
                
                //這句話是為了過濾第一行數據(city 城市 二級 一級)
                //如果child是0說明沒有子節點 如果不為0說明有子節點那就是第一行的p節點這個不是我們需要的
                //可以通過瀏覽器查看p元素的結構
                int child = domElement.getChildElementCount();
                if(attr.equals("text-align:left;") && (child == 0)){
                    String res = domElement.getTextContent();
                    
                    //這里其實有個坑 在獲取的第一行數據中后面2個逗號為中文的,其他的逗號都是英文的
                    //所以這里統一下全部改成中文
                    String a = res.replaceAll(",", ",");
                    
                    String []cityinfo = a.split(",");
                    City city = new City();
                    city.setId(cityinfo[0]);
                    city.setName(cityinfo[1]);
                    city.setSecgrade(cityinfo[2]);
                    city.setOndgrade(cityinfo[3]);
                    
                    result.add(city);
                }                
            }
            
            
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return result;
    }

這個方法可以寫到一個工具類里面直接獲取list就行了,不過有一個city  model需要你去建,拿到list后就可以保存到數據庫中,需要一點時間畢竟有2275條數據^_^

 

2.拿到城市id 和獲取天氣的url(http://wthrcdn.etouch.cn/weather_mini?citykey=xxxxx )后獲取的數據總是亂碼

這個問題是使用最糾結的,本來工具類是寫好get方法獲取數據的但是每次都是獲取亂碼,不論是給輸入流加了"utf-8"編碼還是使用URLDecode進行解碼全部無濟於事,人家仍是安安全全的給你返回亂碼代碼如下:

public static String sendGet(String url,String param){
        URL realUrl = null;
        //PrintWriter out = null;
        String response = "";
        BufferedReader br = null;
        try {
            //真實地址
            realUrl = new URL(url);
            
            //打開連接
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            
            //設置連接屬性            
            connection.setRequestProperty("accept", "application/xhtml+xml,application/json,application/xml;charset=UTF-8, text/javascript, */*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");

//            connection.setDoOutput(true);
//            connection.setDoInput(true);
            
//            out = new PrintWriter(connection.getOutputStream());
//            out.write(param);
           
            //out.flush();
            
            br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));
    
            String line = "";
            
            while((line=br.readLine())!=null){
                response +=line;
            }
            
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
                
        }finally{
            
            //out.close();
            
            try {
                br.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        return response;
    }
    

網上也是有很多人推薦的是這種方法,but不行,糾結痛苦半天后我想到wireshark抓包工具,於是打開之,開始抓包

獲取到抓包數據了 在我們的需要的數據上右擊追蹤流

 

然后我們就可以看見返回的數據信心,然后我們就會發現一個大坑,那就是返回的內容類型content-type:gzip,瀏覽器可以自動解析這個格式but我們java客戶端不會呀,這也是為什么當你把url直接輸入到瀏覽器可以看到完美的返回數據,但是從java http客戶端獲取就是亂碼的原因

 

於是就想辦法解決如何讀取gzip壓縮格式的文件,哈哈哈,還好sun公司已經封裝了這個讀取流^_^直接上代碼:

/**
     * 獲取天氣預報信息
     * @throws UnsupportedEncodingException 
     */
    public static String getWeather(String url) throws UnsupportedEncodingException{
    
        URL realUrl = null;
        ByteArrayOutputStream out = null;
        
        try {
            //真實地址
            realUrl = new URL(url);
            
            //打開連接
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            
            //設置連接屬性            
            connection.setRequestProperty("accept", "application/xhtml+xml,application/json,application/xml;charset=utf-8, text/javascript, */*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("contentType", "utf-8");
            connection.setRequestMethod("GET");
            connection.setRequestProperty("user-agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");

            //FileOutputStream out = new FileOutputStream("e:/text.txt");
            //這里獲取的數據時壓縮格式的數據所以用gzip進行解壓縮
            GZIPInputStream gip = new GZIPInputStream(connection.getInputStream());
            out = new ByteArrayOutputStream();
            //緩沖
            byte []buffer = new byte[1024];
            int len ;
            while((len = gip.read(buffer))!=-1){
                out.write(buffer, 0, len);
            }        
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
                
        }finally{
            //關閉流
            try {
                if(out != null){
                    out.close();
                }                
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        //把字節數據轉化為字符串返回回去
        return (new String(out.toByteArray(), "utf-8"));
    }

同樣這個方法寫到一個工具類中就可以直接使用^_^

整個問題的解決感覺最坑的一步就是url返回的是gzip格式的壓縮文件而不是我們希望的json數據 大坑~,

到此結束^_^

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM