接上
前面我们说到如何用Firefox浏览器抓取数据,并 对json进行了分析,下面就是用Java代码来进行操作。以下代码都没有导入包,有需要自行导入
Java获取12306余票信息(一)
Java获取12306余票信息(二)
Java获取12306余票信息(三)
首先创建JavaBean,用于存放数据
public class TicketingBean {
private String station_train_code;//车次
private String from_station_name;//始发站名字
private String to_station_name;//到达站名字
private String start_time;//出发时间
private String arrive_time;//到达时间
private String lishi;//历时
private String gjrw;//高级软卧
private String rw;//软卧
private String wz;//无座
private String yw;//硬卧
private String yz;//硬座
private String ed;//二等座
private String yd;//一等座
private String td;//商务座,特等座
}
//getter() , setter() , toString() 方法自行实现
创建ReturnJson类,用于获取json
public class ReturnJson {
public static String returnJson(String urlString) throws Exception {
ignoreSSL();//忽略证书 调用自 class IgnoreSSL{}
URL url = new URL(urlString);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
InputStreamReader input = new InputStreamReader(con.getInputStream(),
"utf-8");
BufferedReader bufferedReader = new BufferedReader(input);
StringBuffer stringBuffer = new StringBuffer();
String tempStr = "";
while ((tempStr = bufferedReader.readLine()) != null) {
stringBuffer.append(tempStr);
}
return stringBuffer.toString();
}
}
IngoreSSL类,用于忽略证书问题
12306存在安全证书问题,可以在本地安装证书,也可以用这个来忽略证书
public class IgnoreSSL {
/*
*Ignore the 12306 certificate.
*
* */
public static void ignoreSSL() throws Exception {
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager ignoreSSL = new miTM();
trustAllCerts[0] = ignoreSSL;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
}
static class miTM implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs,
String authType) throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs,
String authType) throws java.security.cert.CertificateException {
return;
}
}
}
创建一个GetJsonAndDeal类,用于对获得json进行处理
思路就是把json字符串通过正则表达式处理,取出我们需要的,然后放进一个List,并返回
public class GetJsonAndDeal {
/*
*分析返回的json得到以下信息
* info.get(3);// 车次信息
* info.get(6); // 出发地代号
* info.get(7);// 目的地代号
* info.get(8);// 出发时间
* info.get(9); // 到达时间
* info.get(10);// 历时
* info.get(11); // Y
* info.get(21); // 高级软卧
* info.get(23); // 软卧
* info.get(26); // 无座
* info.get(28); // 硬卧
* info.get(29); // 硬座
* info.get(30); // 二等座
* info.get(31);// 一等座
* info.get(32); // 商务,特等座
*/
// 获得余票信息的json字符串,并进行处理
// https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-01-22&leftTicketDTO.from_station=NJH&leftTicketDTO.to_station=HZH&purpose_codes=ADULT
public static List<String> getTicketsInfo(String train_date, String from_station, String to_station, String purpose_codes) throws Exception {
List<String> ticketsInfo_list = new ArrayList<>();
List<String> jsonLists = new ArrayList<>();
String urlStr = "https://kyfw.12306.cn/otn/leftTicket/queryO?"
+ "leftTicketDTO.train_date="
+ train_date
+ "&leftTicketDTO.from_station="
+ from_station
+ "&leftTicketDTO.to_station="
+ to_station
+ "&purpose_codes="
+ purpose_codes;
String ticketsInfo_json = returnJson(urlStr); //调用class ReturnJson.returnJson(String);获取json
JSONObject jsonObject = JSONObject.fromObject(ticketsInfo_json);//将获取的json字符串转换为json对象
JSONArray jsonArray_result = jsonObject.getJSONObject("data").getJSONArray("result");//取出result
JSONObject jsonObject_map = jsonObject.getJSONObject("data").getJSONObject("map");//取map
Pattern p = Pattern.compile("(^[^\\|]).*");//正则表达式,不匹配 分割符 `|`
for (Object object : jsonArray_result) {
Matcher m = p.matcher(object.toString());
if (m.find()) {
jsonLists.add(m.group(0)); //匹配后放到jsonList,每一条数据就是一组
}
}
for (int i = 0; i < jsonLists.size(); i++) { //遍历list
String tempStr = jsonLists.get(i).toString(); //将每一条list转换为String
String tempArr[] = tempStr.split("\\|"); //进行分割
List<String> info = new ArrayList<>();
for (String str : tempArr) {
info.add(str); //遍历,放入list
}
List<String> ticketsInfo_list_temp = new ArrayList<>(); //临时的list,将info里的数据分别存到list中,组成一条我们需要的数据
ticketsInfo_list_temp.add(info.get(3));
ticketsInfo_list_temp.add((String) jsonObject_map.get(info.get(6)));
ticketsInfo_list_temp.add((String) jsonObject_map.get(info.get(7)));//得到车站名字
ticketsInfo_list_temp.add(info.get(8));
ticketsInfo_list_temp.add(info.get(9));
ticketsInfo_list_temp.add(info.get(10));
ticketsInfo_list_temp.add(info.get(21));
ticketsInfo_list_temp.add(info.get(23));
ticketsInfo_list_temp.add(info.get(26));
ticketsInfo_list_temp.add(info.get(28));
ticketsInfo_list_temp.add(info.get(29));
ticketsInfo_list_temp.add(info.get(30));
ticketsInfo_list_temp.add(info.get(31));
ticketsInfo_list_temp.add(info.get(32));
ticketsInfo_list.add(ticketsInfo_list_temp.toString()); //最后放到list
}
return ticketsInfo_list;
}
创建QueryTickets类
public class QueryTickets {
// 从处理好的list中查找,存入javabean
public static List<TicketingBean> queryTickets(String train_date,String from_station,String to_station, String purpose_codes) throws Exception {
List<String> list = getTicketsInfo(train_date, from_station,to_station, purpose_codes);
Pattern p = Pattern.compile("[^\\[].*[^\\]]");
Matcher m ;
TicketingBean bean;
List<TicketingBean> beanList = new ArrayList<>();
for(int i =0 ; i<list.size();i++){
m = p.matcher(list.get(i));
if(m.find())
m.group(0);
JSONArray jsonArray = JSONArray.fromObject(m.group(0).split(","));
bean = new TicketingBean();
BeanUtils.setProperty(bean, "station_train_code",jsonArray.get(0).toString());
BeanUtils.setProperty(bean, "from_station_name",jsonArray.get(1).toString());
BeanUtils.setProperty(bean, "to_station_name",jsonArray.get(2).toString());
BeanUtils.setProperty(bean, "start_time",jsonArray.get(3).toString());
BeanUtils.setProperty(bean, "arrive_time",jsonArray.get(4).toString());
BeanUtils.setProperty(bean, "lishi",jsonArray.get(5).toString());
BeanUtils.setProperty(bean, "gjrw",jsonArray.get(6).toString());
BeanUtils.setProperty(bean, "rw",jsonArray.get(7).toString());
BeanUtils.setProperty(bean, "wz",jsonArray.get(8).toString());
BeanUtils.setProperty(bean, "yw",jsonArray.get(9).toString());
BeanUtils.setProperty(bean, "yz",jsonArray.get(10).toString());
BeanUtils.setProperty(bean, "ed",jsonArray.get(11).toString());
BeanUtils.setProperty(bean, "yd",jsonArray.get(12).toString());
BeanUtils.setProperty(bean, "td",jsonArray.get(13).toString());
beanList.add(bean);
}
return beanList;
}
}
前面说到过,车站名字代号,写一个getCodeByName方法,放到GetJsonAndDeal类中
public static String getCodeByName(String stationName) throws Exception {
Map<String,String> map = new HashMap<>();
//获取json写入字符串
String urlStr = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9030";
String nameString = returnJson(urlStr);
//第一次处理json字符串
String[] nameArr = nameString.split("\\@");//获得json由@分割开
Pattern p = Pattern.compile("[^\\@].*\\|.*");
List<String> jsonLists = new ArrayList<String>();
for (Object object : nameArr) {
Matcher m = p.matcher(object.toString());
if (m.find()) {
jsonLists.add(m.group(0));
}
}
//第二次处理json字符互串
for (int i = 0; i < jsonLists.size(); i++) {
String temp = jsonLists.get(i).toString();
String jsonArr[] = temp.split("\\|");
List<String> mapLists = new ArrayList<String>();
for (Object object : jsonArr) {
mapLists.add(object.toString());
}
map.put(mapLists.get(1), mapLists.get(2));
}
return map.get(stationName);
}
测试
@Test
public void test() throws Exception {
System.out.println(queryTickets("2018-03-23",getCodeByName("北京"),getCodeByName("上海"),"ADULT"));
}
写在最后
以上就是整个思路,获得天气啊什么的都是差不多的。源码我已经贴到了GitHub上
wufeiwua.github
当然还用到了一些工具包,JDK不自带的,GitHub 下 lib 文件夹下面都有,有需要的可以下载
主要是:
- commons-beanutils-1.7.0.jar(commons一类)
- json-lib-2.4-jdk15.jar(json处理一类的)
- json-simple-1.1.1,jar
完结
我也是新手一个,可能说的有误,希望指正。