【毕设梳理】开始尝试写代码——查票篇

提要:

查询余票网址、所需参数可见上篇博客(http://www.cnblogs.com/sei-cxt/p/8429069.html)。

参考网上发送https请求的案例代码写出能实现查询余票的简易程序,具体代码原理详情暂且不管。


关于对http和https的连接和请求,网上有多种版本,用的最多的就是HttpURLConnection、HttpsURLConnection和HttpClient。以下编写的代码参考于两个网址:

http://blog.csdn.net/qh_java/article/details/52311226

http://blog.csdn.net/guozili1/article/details/53995121

 

1. 工具类(HttpsRequest):暂时只写了GET方法,其中要注意的是:

GET方法的参数是直接追加在地址后面的,因此doOutput默认为false即可。

在此例中,若setRequestMethod为“POST”,会报411错误,是因为没有提供相应的BODY数据。需要把doOutput设置为true,并且使用OutputStream输出数据。(虽然不会报错了,但返回的数据为空)

同时有的网站不允许使用“POST”方法,当用OutputStream输出数据后会报405错误。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Map;
import java.util.Map.Entry;
import javax.net.ssl.HttpsURLConnection;

public class HttpsRequest {

    public static String methodGet(String urlStr, Map<String, Object> params) {

        String realUrl = urlStr;
        StringBuffer sb = new StringBuffer();
        
        // GET方法需要将查询字符串拼接在url后面
        if(params != null && params.size() != 0) {
            realUrl += encodeParam(params);
        }
        
        try {
            // 连接url
            URL url = new URL(realUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            
            conn.setRequestMethod("GET");
            // URL连接可用于输入和/或输出
            // 如果打算使用 URL连接进行输出,则将DoOutput标志设置为true,默认值为false
            // 如果打算使用 URL连接进行输入,则将DoInput标志设置为true,默认值为true
            // conn.setDoOutput(false);
            // conn.setDoInput(true);
            // 允许连接使用任何可用的缓存,默认值为true
            // conn.setUseCaches(true);
            
            conn.setSSLSocketFactory(MyX509TrustManager.getSSLSocketFactory());
            
            // 设置一般请求属性
            conn.setRequestProperty("accept", "*/*"); // 客户端可以处理哪些数据类型
            conn.setRequestProperty("connection", "Keep-Alive"); // 设置长连接,无过期时间
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); // 使用的何种浏览器
            
            // 建立通信链接
            conn.connect();
            
            // 读取response
            InputStreamReader isr = new InputStreamReader(conn.getInputStream(), "utf-8");
            BufferedReader br = new BufferedReader(isr);
            String res = null;
            while((res = br.readLine()) != null) {
                sb.append(res);
            }
            
            br.close();
            isr.close();
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        
        return sb.toString();
    }
    
    /**
     * 将查询的map形式的参数转码并拼成查询字符串
     * @param params
     * @return
     */
    private static String encodeParam(Map<String, Object> params) {
        if(params == null || params.size() == 0) {
            return "";
        }
        
        StringBuffer sb = new StringBuffer("?");
        for(Entry<String, Object> para : params.entrySet()) {
            try {
                sb.append(URLEncoder.encode(para.getKey(), "UTF-8"));
                sb.append("=");
                sb.append(URLEncoder.encode(para.getValue().toString(), "UTF-8"));
                sb.append("&");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        
        String query = sb.toString();
        // 去掉最后一个&
        return query.substring(0, query.length() - 1);
    }
}

 

2. 证书相关类(MyX509TrustManager):以后再弄明白原理。

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    public static SSLSocketFactory getSSLSocketFactory() throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException{  
        TrustManager[] tm = {new MyX509TrustManager()};  
        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
        sslContext.init(null, tm, new java.security.SecureRandom());  
        SSLSocketFactory ssf = sslContext.getSocketFactory();  
        return  ssf;  
    }  
}

 

3. main函数:

其中参数params我最开始用的HashMap,但是无法得到正确的返回数据。断点后看出拼接后的网址中查询字符串顺序有颠倒,与前篇博客中抓取的网址有细微的不同,并验证得知这就是错误原因。于是换为LinkedHashMap(可以按照插入的顺序遍历的Map),成功。

以后考虑换为JSON或者构造一个信息类,使用类的数组去解决问题。

正确:(使用LinkedHashMap)

错误:(使用HashMap)

    public static void main(String[] args) {
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        params.put("leftTicketDTO.train_date", "2018-02-24");
        params.put("leftTicketDTO.from_station", "BJP");
        params.put("leftTicketDTO.to_station", "SHH");
        params.put("purpose_codes", "ADULT");
        
        String url = "https://kyfw.12306.cn/otn/leftTicket/queryZ";
        
        String response = HttpsRequest.methodGet(url, params);
        System.out.println(response);
    }

 

4. 得到结果:

{"data":{"flag":"1","map":{"AOH":"上海虹桥","BJP":"北京","SHH":"上海","VNP":"北京南"},"result":["|预订|240000G1512M|G151|VNP|AOH|VNP|AOH|16:35|22:35|06:00|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P2|01|12|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|2400000G2302|G23|VNP|AOH|VNP|AOH|17:00|22:39|05:39|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P3|01|10|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|240000G1530E|G153|VNP|AOH|VNP|AOH|17:15|22:49|05:34|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P3|01|09|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|240000G1551S|G155|VNP|AOH|VNP|AOH|17:20|23:08|05:48|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P4|01|11|1|0|||||||||||无|无|无||O0M090|OM9|1","|预订|240000G1570K|G157|VNP|AOH|VNP|AOH|17:43|23:30|05:47|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P3|01|09|1|0|||||||||||无|无|无||O0M090|OM9|1","|预订|240000G1591Z|G159|VNP|AOH|VNP|AOH|17:48|23:44|05:56|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P4|01|09|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|24000000G704|G7|VNP|AOH|VNP|AOH|19:00|23:24|04:24|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P3|01|04|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|24000000G900|G9|VNP|AOH|VNP|AOH|19:05|23:39|04:34|N|usY%2BUl57hWKitIUp1d4m3n3e0ys4iJTdDfedKU6oXk7F3bAb|20180224|3|P4|01|05|1|0|||||||||||无|无|无||O0M090|OM9|0","|预订|240000T1090Z|T109|BJP|SHH|BJP|SHH|19:31|10:43|15:12|N|SPyTjS4UE%2BFObI0x4k%2BxWLp41d7MjhINm2wQh8uIolnaeFXRL%2FuqgWcGuRcAiAPUTzxg45bjonU%3D|20180224|3|P4|01|09|0|0||无||无|||无||无|无|||||1040601030|14613|0","UKEhCCI8hqymqGKMu%2B8o597E1HEFnc7PrfQE9WX27aIY0MUZDkZLk7N8xX7027vok5DOLqFeijxQ%0ArVQHPRvldY8ullIIyVt2YYVGSU4WB30nfCSyIgti51pNhRkDqgPRdDCYB34cRQ34xpSBesP53hzV%0Ay%2FqGj551m%2FeK%2BAxwtosRSxdmF95FvZwU6y0H4mbfrw5CAcLy4LfQ5lHEwRKlyOD8%2BHyUCCmiqAz8%0ATTniRABrPWmdQgu2a5nZ2yE%3D|预订|240000D3130T|D313|VNP|SHH|VNP|SHH|19:34|07:41|12:07|Y|%2FeEHM%2BOX%2FhkUjkIf%2Bhc9UBJHyhWbXMzLqkOUJ61gyvzxghhA|20180224|3|P3|01|04|0|0||||有|||无||||无||||O0O040|OO4|0","B2ptaQsZngo3cuVpKR490RKFxw%2FujNVfaO8q%2Fz9nOn%2Bv9%2BlQsoxygraTjYr8hjp4ls6MDs0jnusA%0Alafi6AR3NiTZBBs4vA41Stjj2m%2Fty%2FyLO2TDRnjk5Mzt00a7ADMG6L56oaDDK7NpYbx8pNPr7ZPP%0AMeVYdrHdxA3VSz78Sx7mRlmOfko8C6ep%2FB4PGNKvywXfmmmiWPr7p%2BRm39gQT5ISQ5WBmGDRFvbJ%0Al3CPql7gu563|预订|240000D3110J|D311|VNP|SHH|VNP|SHH|21:16|09:09|11:53|Y|%2BypbKTC2HZlFzZByUcQ3VvnTcGuNsar%2B|20180224|3|P2|01|04|0|0||||无||||||||||有|F040|F4|0","nr35RXw6%2BkkqgJ0axRZOQs8MeSPKVstyvt6jqk5NNZpZurw8b0HiI8mnxKbMGYPxoDKfGAvI4%2Bdv%0AsQoW9lSHwZK4PaPjoYpWM90B7gL1IjKy5NW6zsf95CtVyWh8Qgd0nIaDU%2F0NGpD%2FyJiX%2BnUa6igm%0AtPNlEGe2pjgpcCLkQeKs9z3dHdQS18rHxPTnChe8HRrsLTGcBzxzMW%2BbjNE%2FWQqQaLeYSwTJImP5%0Az%2F60kEOkSBw29fQO2Cbp%2Bps%3D|预订|240000D3210D|D321|VNP|SHH|VNP|SHH|21:23|09:15|11:52|Y|Qu9exXtC3AVH27oNnBfVX5zFLnqdhQ1lY5vwmAt4du%2FqF0zQ|20180224|3|P2|01|04|0|0||||有|||无||||无||||O0O040|OO4|0"]},"httpstatus":200,"messages":"","status":true}

 

posted @ 2018-02-24 16:30  逝逝  阅读(348)  评论(0编辑  收藏  举报