实用攻略:12306抢票神器(二)——联系人设置与车次查询技巧
续马后炮之12306抢票工具(一) -- 登录
今天完成模块:
添加常用联系人
获取车站列表
获取车次信息
获取常用联系人已经在马后炮之12306抢票工具(一) -- 登录中介绍,不在重复
遇到问题:
1)用TextBox输出日志时,系统UI卡死
1 private void ShowMessage(string message, bool isNewLine = true) 2 { 3 this.Invoke(new Action<string, bool>((m, n) => { _ShowMessage(m, n); }), message, isNewLine); 4 5 } 6 private void _ShowMessage(string message, bool isNewLine = true) 7 { 8 richTextBox1.AppendText(message); 9 if (isNewLine) 10 { 11 richTextBox1.AppendText("\r\n"); 12 } 13 }
2)TextBox焦点一直在底部
1 richTextBox1.SelectionStart = richTextBox1.TextLength; 2 richTextBox1.ScrollToCaret();
3)checkedListBox使用DataSource属性绑定数据源(自定义类列表)后,显示绑定类型。
该问题未解决。如果知道的朋友,请提供以下代码,谢谢。
重写ToString方法。
public override string ToString()
{
return string.Format("{0} {1}({3})->{2}({4})", TrainValue, StartStation, EndStation, StartTime, EndTime);
}
添加常用联系人:
添加常用联系人分两步:
第一步:访问https://dynamic.12306.cn/otsweb/passengerAction.do?method=initUsualPassenger12306# 获取Token
格式:<div><input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="5d920dbd8e3216dd0bd18eae5f96ccc9"></div>
第二步:将Token和其他数据Post到https://dynamic.12306.cn/otsweb/passengerAction.do?method=savePassenger 创建联系人
PS:没有使用购票时”添加至常用联系人“选项,而是使用”我的12306"页面中的常用联系人功能。
因为在秒杀应用中,浪费十几毫秒都可能导致抢不到,虽然抢票没有秒杀那么夸张,但是不排除因为购票时使用添加联系人功能,导致浪费几十毫秒,甚至几秒。
1 private const string UrlCreateFavoriteContact1_GetToken = "https://dynamic.12306.cn/otsweb/passengerAction.do?method=initUsualPassenger12306#"; 2 3 string token = ""; 4 string str; 5 HttpWebResponse response; 6 7 #region 第一步获取Token 8 try 9 { 10 11 response = HttpHelper.CreateGetHttpResponse(UrlCreateFavoriteContact1_GetToken, timeout, userAgent, cookie ?? Cookies, ""); 12 13 cookies.Add(response.Cookies); 14 15 using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 16 { 17 str = reader.ReadToEnd(); 18 } 19 } 20 catch (Exception) 21 { 22 return new CreateFavoriteContactResponse() { IsCreated = false, Message = "网络可能存在问题,请您重试一下!", type = ErrorType.NetworkError }; 23 } 24 25 26 Regex Token = new Regex("<input type=\"hidden\" name=\"org.apache.struts.taglib.html.TOKEN\" value=\"(?<token>[^\"]*?)\"></div>"); 27 28 if (Token.IsMatch(str)) 29 { 30 token = Token.Matches(str)[0].Groups["token"].Value; 31 } 32 33 #endregion
private const string UrlCreateFavoriteContact2_Create = "https://dynamic.12306.cn/otsweb/passengerAction.do?method=savePassenger"; Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("org.apache.struts.taglib.html.TOKEN", token); dic.Add("name", name); dic.Add("sex_code", sexCode); dic.Add("born_date", bornDate); dic.Add("country_code", "CN"); dic.Add("card_type", cardType); dic.Add("card_no", cardNo); dic.Add("passenger_type", "1");//暂时只支持添加成人 dic.Add("mobile_no", mobileNo); dic.Add("phone_no", ""); dic.Add("email", ""); dic.Add("address", ""); dic.Add("postalcode", ""); dic.Add("studentInfo.province_code", "11"); dic.Add("studentInfo.school_code", ""); dic.Add("studentInfo.school_name", "简码/汉字"); dic.Add("studentInfo.department", ""); dic.Add("studentInfo.school_class", ""); dic.Add("studentInfo.student_no", ""); dic.Add("studentInfo.school_system", "4"); dic.Add("studentInfo.enter_year", "2002"); dic.Add("studentInfo.preference_card_no", ""); dic.Add("studentInfo.preference_from_station_name", "简码/汉字"); dic.Add("studentInfo.preference_from_station_code", ""); dic.Add("studentInfo.preference_to_station_name", "简码/汉字"); dic.Add("studentInfo.preference_to_station_code", ""); try { response = HttpHelper.CreatePostHttpResponse(UrlCreateFavoriteContact2_Create, dic, timeout, userAgent, Encoding.UTF8, cookie ?? Cookies, "https://dynamic.12306.cn/otsweb/passengerAction.do?method=initAddPassenger&"); cookies.Add(response.Cookies); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { str = reader.ReadToEnd(); } } catch (Exception) { return new CreateFavoriteContactResponse() { IsCreated = false, Message = "网络可能存在问题,请您重试一下!", type = ErrorType.NetworkError }; } Regex message = new Regex("var message = \"(?<message>[^\"]*?)\";"); if (message.IsMatch(str)) { str = message.Matches(str)[0].Groups["message"].Value; if (str.Contains("添加常用联系人成功")) { return new CreateFavoriteContactResponse() { IsCreated = true, Message = "", type = ErrorType.None }; } else { return new CreateFavoriteContactResponse() { IsCreated = false, Message = str, type = ErrorType.OtherError }; } } return new CreateFavoriteContactResponse() { IsCreated = false, Message = "其他错误!", type = ErrorType.OtherError };
获取车站列表:
访问https://dynamic.12306.cn/otsweb/js/common/station_name.js 获取车站列表(该页面可以匿名访问)
格式:var station_names
='@bjb|北京北|VAP|beijingbei|bjb|0@bjd|北京东|BOP|beijingdong|bjd|1@bji|北京|BJP|beijing|bj|2......@zzd|涿州东|ZAP|zhuozhoudong|zzd|2140@zzd|郑州东|ZAF|zhengzhoudong|zzd|2141';
private const string UrlGetStations = "https://dynamic.12306.cn/otsweb/js/common/station_name.js"; /// <summary> /// 获取车站信息 /// </summary> /// <param name="timeout"></param> /// <param name="userAgent"></param> /// <param name="cookie"></param> public static List<Station> GetStations(int? timeout = null, string userAgent = null, CookieCollection cookie = null) { List<Station> list = new List<Station>(); var response = HttpHelper.CreateGetHttpResponse(UrlGetStations, timeout, userAgent, cookie ?? Cookies); cookies.Add(response.Cookies); try { using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { var str = reader.ReadToEnd(); Regex stationNamesRegex = new Regex("'(?<stationNames>[^\']*?)'"); if (stationNamesRegex.IsMatch(str)) { string stationNames = stationNamesRegex.Matches(str)[0].Groups["stationNames"].Value; string[] stations = stationNames.Split('@'); foreach (var station in stations) { if (string.IsNullOrEmpty(station)) { continue; } string[] names = station.Split('|'); list.Add(new Station() { Shorthand = names[0], Name = names[1], Code = names[2], Pinyin = names[3], FirstLetter = names[4], Order = names[5] }); } } } } catch (Exception) { } return list; }
class Stations { static List<Station> list = new List<Station>(); private static object obj = new object(); public static List<Station> List { get { if (list.Count <= 0) { lock (obj) { if (list.Count <= 0) { list = _12306Class.GetStations(); } } } return list; } } } /// <summary> /// 站点信息 /// </summary> class Station { /// <summary> /// 站点名 /// </summary> public string Name; /// <summary> /// /// </summary> public string Code; /// <summary> /// 首字母 /// </summary> public string FirstLetter; /// <summary> /// 全拼 /// </summary> public string Pinyin; /// <summary> /// 简写 /// </summary> public string Shorthand; /// <summary> /// 排序 /// </summary> public string Order; }
获取车次信息:
第一步:将车站名转换为车站Code
第二步:将内容发送到https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=queryststrainall 页面
PS:需要注意,在不同时间获取的车次不同,可能返回空
var startStation = Stations.List.SingleOrDefault(fun => fun.Name == textBox1.Text.Trim()); if (startStation == null) { MessageBox.Show(string.Format("找不到站点:{0},请重新输入!", textBox1.Text.Trim())); return; } var endStation = Stations.List.SingleOrDefault(fun => fun.Name == textBox2.Text.Trim()); if (endStation == null) { MessageBox.Show(string.Format("找不到站点:{0},请重新输入!", textBox2.Text.Trim())); return; }
1 private const string UrlGetTrains = "https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=queryststrainall"; 2 3 public static List<Train> GetTrains(string data, string fromstation, string tostation, 4 int? timeout = null, string userAgent = null, CookieCollection cookie = null) 5 { 6 List<Train> list = new List<Train>(); 7 Dictionary<string, string> dic = new Dictionary<string, string>(); 8 dic.Add("date", data); 9 dic.Add("fromstation", fromstation); 10 dic.Add("tostation", tostation); 11 dic.Add("starttime", "00:00--24:00"); 12 13 string str = ""; 14 15 try 16 { 17 var response = HttpHelper.CreatePostHttpResponse(UrlGetTrains, dic, timeout, userAgent, Encoding.UTF8, cookie ?? Cookies, "https://dynamic.12306.cn/otsweb/passengerAction.do?method=initAddPassenger&"); 18 19 cookies.Add(response.Cookies); 20 21 using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 22 { 23 str = reader.ReadToEnd(); 24 } 25 } 26 catch (Exception) 27 { 28 return null; 29 } 30 31 if (!string.IsNullOrEmpty(str)) 32 { 33 // 解析第一次返回值,获取登录随机验证码loginRand,执行登录 34 var v = new IronJS.Hosting.CSharp.Context(); 35 string strJson = "var json = " + str; 36 dynamic dy = v.Execute(strJson); 37 38 for (int i = 0; i < dy.length; i++) 39 { 40 list.Add(new Train() 41 { 42 Id = dy[i].id, 43 EndStation = dy[i].end_station_name, 44 EndTime = dy[i].end_time, 45 StartStation = dy[i].start_station_name, 46 StartTime = dy[i].start_time, 47 TrainValue = dy[i].value 48 }); 49 } 50 } 51 52 return list; 53 }
class Trains { static List<Train> list = new List<Train>(); public List<Train> List { get { return list; } } public static void AddTrains(List<Train> trains) { var v = trains.Where(fun => list.SingleOrDefault(m => m.Id == fun.Id) == null); if (v.Any()) { list.AddRange(v); if (TrainsChanged != null) { TrainsChanged(v, list); } } } public static event EventHandler<List<Train>> TrainsChanged; } public class Train { public string Id; public string StartStation; public string EndStation; public string StartTime; public string EndTime; public string TrainValue; public virtual string ToString() { return string.Format("{0} {1}({3})->{2}({4})", TrainValue, StartStation, EndStation, StartTime, EndTime); } }
报文:
POST /otsweb/passengerAction.do?method=savePassenger HTTP/1.0 Accept-Language: zh-CN,en-GB;q=0.5 Pragma: no-cache Cache-Control: no-cache X-Requested-With: XMLHttpRequest Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Content-Type: application/x-www-form-urlencoded Referer: https://dynamic.12306.cn/otsweb/passengerAction.do?method=initAddPassenger& User-Agent: Mozilla/6.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20120131 Firefox/14.0 Host: dynamic.12306.cn Cookie: JSESSIONID=BE43978FDEF213DCB1659646FA17F82D; BIGipServerotsweb=2597585162.48160.0000 Content-Length: 691 Connection: Keep-Alive org.apache.struts.taglib.html.TOKEN=a42a32e61f183cfef893d6d945426196&name=XX&sex_code=M&born_date=1990-01-01&country_code=CN&card_type=2&card_no=1234567890123456789&passenger_type=1&mobile_no=15814000000&phone_no=&email=&address=&postalcode=&studentInfo.province_code=11&studentInfo.school_code=&studentInfo.school_name=简码/汉字&studentInfo.department=&studentInfo.school_class=&studentInfo.student_no=&studentInfo.school_system=4&studentInfo.enter_year=2002&studentInfo.preference_card_no=&studentInfo.preference_from_station_name=简码/汉字&studentInfo.preference_from_station_code=&studentInfo.preference_to_station_name=简码/汉字&studentInfo.preference_to_station_code=
GET /otsweb/js/common/station_name.js HTTP/1.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/6.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20120131 Firefox/14.0 Host: dynamic.12306.cn Cookie: JSESSIONID=BE43978FDEF213DCB1659646FA17F82D; BIGipServerotsweb=2597585162.48160.0000 Connection: Keep-Alive --------------------------------------------------------------------------------- var station_names ='@bjb|北京北|VAP|beijingbei|bjb|0@bjd|北京东|BOP|beijingdong|bjd|1@bji|北京|BJP|beijing|bj|2@bjn|北京南|VNP|beijingnan|bjn|3@bjx|北京西|BXP|beijingxi|bjx|4@cqb|重庆北|CUW|chongqingbei|cqb|5@cqi|重庆|CQW|chongqing|cq|6@cqn|重庆南|CRW|chongqingnan|cqn|7@sha|上海|SHH|shanghai|sh|8@shn|上海南|SNH|shanghainan|shn|9@shq|上海虹桥|AOH|shanghaihongqiao|shhq|10@shx|上海西|SXH|shanghaixi|shx|11@tjb|天津北|TBP|tianjinbei|tjb|12@tji|天津|TJP|tianjin|tj|13@tjn|天津南|TIP|tianjinnan|tjn|14@tjx|天津西|TXP|tianjinxi|tjx|15@cch|长春|CCT|changchun|cc|16@ccn|长春南|CET|changchunnan|ccn|17@ccx|长春西|CRT|changchunxi|ccx|18@cdd|成都东|ICW|chengdudong|cdd|19@cdn|成都南|CNW|chengdunan|cdn|20@cdu|成都|CDW|chengdu|cd|21@csh|长沙|CSQ|changsha|cs|22@csn|长沙南|CWQ|changshanan|csn|23@fzh|福州|FZS|fuzhou|fz|24@fzn|福州南|FYS|fuzhounan|fzn|25@gya|贵阳|GIW|guiyang|gy|26@gzb|广州北|GBQ|guangzhoubei|gzb|27@gzd|广州东|GGQ|guangzhoudong|gzd|28@gzh|广州|GZQ|guangzhou|gz|29@gzn|广州南|IZQ|guangzhounan|gzn|30@gzx|广州西|GXQ|guangzhouxi|gzx|31@heb|哈尔滨|HBB|haerbin|heb|32@hed|哈尔滨东|VBB|harbindong|hebd|33@hex|哈尔滨西|VAB|haerbinxi|hebx|34@hfe|合肥|HFH|hefei|hf|35@hfx|合肥西|HTH|hefeixi|hfx|36@hhd|呼和浩特东|NDC|huhehaotedong|hhhtd|37@hht|呼和浩特|HHC|hohhot|hhht|38@hkd|海口东|HMQ|haikoudong|hkd|39@hko|海口|VUQ|haikou|hk|40@hzh|杭州|HZH|hangzhou|hz|41@hzn|杭州南|XHH|hangzhounan|hzn|42@jna|济南|JNK|jinan|jn|43@jnd|济南东|JAK|jinandong|jnd|44@jnx|济南西|JGK|jinanxi|jnx|45@kmi|昆明|KMM|kunming|km|46@kmx|昆明西|KXM|kunmingxi|kmx|47@lsa|拉萨|LSO|lasa|ls|48@lzd|兰州东|LVJ|lanzhoudong|lzd|49@lzh|兰州|LZJ|lanzhou|lz|50@lzx|兰州西|LAJ|lanzhouxi|lzx|51@nch|南昌|NCG|nanchang|nc|52@nji|南京|NJH|nanjing|nj|53@njn|南京南|NKH|nanjingnan|njn|54@nni|南宁|NNZ|nanning|nn|55@sjb|石家庄北|VVP|shijiazhuangbei|sjzb|56@sjz|石家庄|SJP|shijiazhuang|sjz|57@sya|沈阳|SYT|shenyang|sy|58@syb|沈阳北|SBT|shenyangbei|syb|59@syd|沈阳东|SDT|shenyangdong|syd|60@tyb|太原北|TBV|taiyuanbei|tyb|61@tyd|太原东|TDV|taiyuandong|tyd|62@tyu|太原|TYV|taiyuan|ty|63@wha|武汉|WHN|wuhan|wh|64@wjx|王家营西|KNM|wangjiayingxi|wjyx|65@wlq|乌鲁木齐|WMR|wulumuqi|wlmq|66@xab|西安北|EAY|xianbei|xab|67@xan|西安|XAY|xian|xa|68@xan|西安南|CAY|xiannan|xan|69@xnx|西宁西|XXO|xiningxi|xnx|70@ych|银川|YIJ|yinchuan|yc|71@zzh|郑州|ZZF|zhengzhou|zz|72@aes|阿尔山|ART|aershan|aes|73@aka|安康|AKY|ankang|ak|74@aks|阿克苏|ASR|akesu|aks|75@alh|阿里河|AHX|alihe|alh|76@alk|阿拉山口|AKR|alashankou|alsk|77@api|安平|APT|anping|ap|78@aqi|安庆|AQH|anqing|aq|79@ash|安顺|ASW|anshun|as|80@ash|鞍山|AST|anshan|as|81@aya|安阳|AYF|anyang|ay|82@ban|北安|BAB|beian|ba|83@bbu|蚌埠|BBH|bengbu|bb|84@bch|白城|BCT|baicheng|bc|85@bha|北海|BHZ|beihai|bh|86@bhe|白河|BEL|baihe|bh|87@bji|白涧|BAP|baijian|bj|88@bji|宝鸡|BJY|baoji|bj|89@bji|滨江|BJB|binjiang|bj|90@bkt|博克图|BKX|bugt|bkt|91@bse|百色|BIZ|baise|bs|92@bss|白山市|HJL|baishanshi|bss|93@bta|北台|BTT|beitai|bt|94@btd|包头东|BDC|baotoudong|btd|95@bto|包头|BTC|baotou|bt|96@bts|北屯市|BXR|beitunshi|bts|97@bxi|本溪|BXT|benxi|bx|98@byb|白云鄂博|BEC|bayanobo|byeb|99@byx|白银西|BXJ|baiyinxi|byx|100@bzh|亳州|BZH|bozhou|bz|101@cbi|赤壁|CBN|chibi|cb|102@cde|常德|VGQ|changde|cd|103@cde|承德|CDP|chengde|cd|104@cdi|长甸|CDT|changdian|cd|105@cfe|赤峰|CFD|chifeng|cf|106@cli|茶陵|CDG|chaling|cl|107@cna|苍南|CEH|cangnan|cn|108@cpi|昌平|CPP|changping|cp|109@cre|崇仁|CRG|chongren|cr|110@ctu|昌图|CTT|changtu|ct|111@ctz|长汀镇|CDB|changtingzhen|ctz|112@cxi|崇信|CIJ|chongxin|cx|113@cxi|曹县|CXK|caoxian|cx|114@cxi|楚雄|COM|chuxiong|cx|115@cxt|陈相屯|CXT|chenxiangtun|cxt|116@czb|长治北|CBF|changzhibei|czb|117@czh|长征|CZJ|changzheng|cz|118@czh|池州|IYH|chizhou|cz|119@czh|常州|CZH|changzhou|cz|120@czh|郴州|CZQ|chenzhou|cz|121@czh|长治|CZF|changzhi|cz|122@czh|沧州|COP|cangzhou|cz|123@czu|崇左|CZZ|chongzuo|cz|124@dab|大安北|RNT|daanbei|dab|125@dch|大成|DCT|dacheng|dc|126@ddo|丹东|DUT|dandong|dd|127@dfh|东方红|DFB|dongfanghong|dfh|128@dgd|东莞东|DMQ|dongguandong|dgd|129@dhs|