diff --git a/src/12306 b/src/12306 deleted file mode 160000 index a495af8..0000000 --- a/src/12306 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a495af88346a0d794493c6030f6a6207debb5824 diff --git a/src/12306/.dockerignore b/src/12306/.dockerignore new file mode 100644 index 0000000..e18c7ff --- /dev/null +++ b/src/12306/.dockerignore @@ -0,0 +1,15 @@ +**/*.html +**/*.pyc +**/*.yaml +**/*.log +**/*~ +**/.DS_Store +**/Thumbs.db +*.png +.idea/ +.git/ +.github/ +*.md +UnitTest/ +uml/ +*.h5 diff --git a/src/12306/.gitignore b/src/12306/.gitignore new file mode 100644 index 0000000..3d01bc3 --- /dev/null +++ b/src/12306/.gitignore @@ -0,0 +1,6 @@ +*.html +*.pyc +*.yaml +*.log +.idea/ +tkcode.png \ No newline at end of file diff --git a/src/12306/12306.image.model.h5 b/src/12306/12306.image.model.h5 new file mode 100644 index 0000000..870516f Binary files /dev/null and b/src/12306/12306.image.model.h5 differ diff --git a/src/12306/Dockerfile b/src/12306/Dockerfile new file mode 100644 index 0000000..7237e0f --- /dev/null +++ b/src/12306/Dockerfile @@ -0,0 +1,24 @@ +FROM python:2.7.15 +WORKDIR /usr/src/app +ADD . /usr/src/app + +ENV DEBIAN_FRONTEND noninteractive +ENV TZ Asia/Shanghai + + +## install python requirements +RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyspider --no-cache-dir -r requirements.txt +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +## install ntpdate, not accept but saving code +#RUN echo 'deb http://mirrors.163.com/debian/ jessie main non-free contrib \ +# deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib \ +# deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib' > /etc/apt/sources.list \ +# && apt-get update\ +# && apt-get install ntpdate -y \ + + +#EXPOSE 5010 + +CMD [ "python", "run.py" ] +#ENTRYPOINT [ "python", "run.py" ] diff --git a/src/12306/Dockerfile37 b/src/12306/Dockerfile37 new file mode 100644 index 0000000..3018e53 --- /dev/null +++ b/src/12306/Dockerfile37 @@ -0,0 +1,51 @@ +FROM python:3.7-slim-buster + +ARG CDV=77.0.3865.40 + +RUN sed -i 's/deb.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list + +RUN apt-get -y update && apt-get install -y \ + fonts-liberation \ + libappindicator3-1 \ + libasound2 \ + libatk-bridge2.0-0 \ + libatk1.0-0 \ + libatspi2.0-0 \ + libcups2 \ + libdbus-1-3 \ + libgtk-3-0 \ + libnspr4 \ + libnss3 \ + libx11-xcb1 \ + libxcomposite1 \ + libxcursor1 \ + libxdamage1 \ + libxfixes3 \ + libxi6 \ + libxrandr2 \ + libxss1 \ + libxtst6 \ + lsb-release \ + unzip \ + wget \ + xdg-utils \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +ENV TZ Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +WORKDIR /usr/src/app + +RUN wget -q https://dl.lancdn.com/landian/soft/chrome/m/77.0.3865.120_amd64.deb && \ + dpkg -i 77.0.3865.120_amd64.deb && rm -f 77.0.3865.120_amd64.deb + +RUN wget -q https://npm.taobao.org/mirrors/chromedriver/$CDV/chromedriver_linux64.zip && \ + unzip chromedriver_linux64.zip && rm -f chromedriver_linux64.zip + +## install python requirements +COPY requirements-docker37.txt ./ +RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir -r requirements-docker37.txt + +COPY . . + +CMD [ "sh", "-c", "python run.py c && python run.py r" ] diff --git a/src/12306/LICENSE b/src/12306/LICENSE new file mode 100644 index 0000000..a0bf476 --- /dev/null +++ b/src/12306/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/12306/README.md b/src/12306/README.md new file mode 100644 index 0000000..ef646fa --- /dev/null +++ b/src/12306/README.md @@ -0,0 +1,141 @@ +### 12306 购票小助手 +#### python版本 + - [ ] 2.7.10 - 2.7.15 + - [x] 3.6 - 3.7.4 + - [ ] 2.7.9 + +#### 已有功能 + - [x] 自动打码 + - [x] 自动登录 + - [x] 准点预售和捡漏 + - [x] 智能候补 + - [x] 邮件通知 + - [x] server酱通知 + +#### 依赖库 + - 验证码目前可以本地识别,需要下载模型,放于项目根目录,全部代码来源于此项目 [传送门](https://github.com/zhaipro/easy12306),表示感谢 + ``` + 1. 模型下载链接:https://pan.baidu.com/s/1rS155VjweWVWIJogakechA 密码:bmlm + 群里面也可以下载 + 2. git仓库下载:https://github.com/testerSunshine/12306model.git + ``` + - 自托管云打码服务器搭建:[12306_code_server](https://github.com/YinAoXiong/12306_code_server) + - 如果大家有空闲的服务器,可搭建之后在这个 [issues](https://github.com/testerSunshine/12306/issues/446) 里面填入自己的服务器(请注意服务器安全!) + - 项目依赖 [requirements.txt](requirements.txt) + - 安装方法x: + - root用户(避免多python环境产生问题): `pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt` + - 非root用户(避免安装和运行时使用了不同环境): `pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt` + - 许多windows的用户装不了tensorflow的话,可以适当降低版本或者升高版本都是可以的 + ``` + 1. tensorflow的兼容版本 1.14.0rc\1.14.0rc\1.15.0\1.15.0rc + 以上版本都测试无问题 + 2. 如果pip代理的清华源无法下载,可以更换其他源解决此问题 + ``` + +#### 项目使用说明 + + - 服务器启动: + - 修改[配置](TickerConfig.py)文件 + - 可以配置邮箱,配置邮箱的格式在[配置](TickerConfig.py)里面可以看到ex + ``` + # 测试邮箱和server酱是否可用, server酱测试的前提是server酱开关开启 + # 可以配置server酱提醒(推荐)[配置教程](https://www.jianshu.com/p/8d10b5b9c4e3) + # 用python3 还是python 完全取决于安装的时候配置的环境变量是否为python3,以下启动默认环境变量为python3 + python3 run.py t + ``` + - 配置[配置](TickerConfig.py)文件的时候,需注意空格和遵循python语法格式 + - 启动前请先筛选cdn,这点很`重要` + ``` + python3 run.py c + ``` + - 启动服务 + ``` + python3 run.py r + ``` + - 如果你不知道如何操作,下面的命令可能会帮助你 + ``` + python3 run.py -h + + —————————————————————————— + sage: run.py [-h] operate + + positional arguments: + operate r: 运行抢票程序, c: 过滤cdn, t: 测试邮箱和server酱,server酱 + ``` + - 如果你的服务器安装了docker与docker-compose, 那么你可以忽略上面的**所有**步骤,直接按以下步骤操作,即可开始抢票: + - 前提条件: + - 请确认你安装的docker版本为18.09及以上: `docker -v` + - 请确认你安装的docker-compose版本为1.23.2及以上: `docker-compose -v` + - 请根据自己需要修改好配置文件:`TickerConfig.py` + - 请修改配置文件`TickerConfig.py`中的变量`AUTO_CODE_TYPE`和`HOST`,`AUTO_CODE_TYPE`改为`3`, HOST改为`"captcha:80"`(这里很重要,这是本地打码服务器的配置) + - 运行命令: + - 开始抢票:`docker-compose up --build -d` + - 停止抢票:`docker-compose down` + - 查看抢票log: `docker logs --follow ticket` + +#### 目录对应说明 + - agency - cdn代理 + - config - 项目配置 + - verify - 自动打码 + - init - 项目主运行目录 + - inter - 接口 + - myException - 异常 + - myUrllib request网络请求库 + +#### 思路图 +- ![image](uml/uml.png) + +#### 项目声明: + - 本软件只供学习交流使用,勿作为商业用途,交流群号 + - 1群:286271084(已满) + - 2群:649992274(已满) + - 3群:632501142(已满) + - 4群: 606340519(已满) + - 5群: 948526733(已满) + - 7群: 660689659(已满) + - 8群: 620629239(已满) + - 6群: 608792930(未满) + - 9群: 693035807(未满) + - 请不要重复加群,一个群就可以了,把机会留给更多人 + - **进群先看公告!!!进群先看公告!!!进群先看公告!!! 重要的事情说三遍** + - 能为你抢到一张回家的票,是我最大的心愿 + +#### 日志列子 + - 成功log,如果是购票失败的,请带上失败的log给我,我尽力帮你调,也可加群一起交流,程序只是加速买票的过程,并不一定能买到票 + ``` + 正在第355次查询 乘车日期: 2018-02-12 车次G4741,G2365,G1371,G1377,G1329 查询无票 代理设置 无 总耗时429ms + 车次: G4741 始发车站: 上海 终点站: 邵阳 二等座:有 + 正在尝试提交订票... + 尝试提交订单... + 出票成功 + 排队成功, 当前余票还剩余: 359 张 + 正在使用自动识别验证码功能 + 验证码通过,正在提交订单 + 提交订单成功! + 排队等待时间预计还剩 -12 ms + 排队等待时间预计还剩 -6 ms + 排队等待时间预计还剩 -7 ms + 排队等待时间预计还剩 -4 ms + 排队等待时间预计还剩 -4 ms + 恭喜您订票成功,订单号为:EB52743573, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付! + ``` +#### 使用帮助(一些安装问题和使用反馈较多的问题): + - 测试邮箱是否可用 [邮箱配置问题看issues](https://github.com/testerSunshine/12306/issues/107) + - 学生票issues [学生票修改](https://github.com/testerSunshine/12306/issues/47) + - 依赖安装不对的问题(ImportError)[requirements.txt问题](https://github.com/testerSunshine/12306/issues/91) + - 若快豆子疑问 [点我](https://github.com/testerSunshine/12306/issues/67) + - IOError: 【Errno 0】 Error 问题 [点我](https://github.com/testerSunshine/12306/issues/159) + + - 测试下单接口是否可用,有两个下单接口,随便用哪个都ok + - 如果下载验证码过期或者下载失败的问题,应该是12306封ip的策略,多重试几次,12306现在封服务器(阿里云和腾讯云)ip比较严重,尽量不要放在服务器里面 + - 目前12306对服务器ip比较敏感,大家还是在自己家里挂着吧 + - 自动更换ip软件目前已支持TPLINK和小米路由器,只限家庭网络[点我跳转](https://github.com/testerSunshine/AutoRouterIP) + + +#### 感谢一下小伙伴对本项目提供的帮助 + - @sun7127@126.com + - @ 才 + - @[MonsterTan](https://github.com/MonsterTan) + - 以及所有为此项目提供pr的同学 +#### 更新日志 + - [更新日志](Update.md) diff --git a/src/12306/TickerConfig.py b/src/12306/TickerConfig.py new file mode 100644 index 0000000..faee155 --- /dev/null +++ b/src/12306/TickerConfig.py @@ -0,0 +1,157 @@ +# -*- coding=utf-8 -*- +# 关于软件使用配置说明,一定要看!!! +# ps: 如果是候补车票,需要通过人证一致性核验的用户及激活的“铁路畅行”会员可以提交候补需求,请您按照操作说明在铁路12306app.上完成人证核验 +# 关于候补了之后是否还能继续捡漏的问题在此说明: 软件为全自动候补加捡漏,如果软件候补成功则会停止抢票,发出邮件通知,但是不会影响你继续捡漏, +# 如果这个时候捡漏捡到的话,也是可以付款成功的,也就是说,捡漏+候补,可以最大程度提升抢票成功率 + +# 刷票模式:1=刷票 2=候补+刷票 +TICKET_TYPE = 1 + +# 出发日期(list) "2018-01-06", "2018-01-07" +STATION_DATES = [ + "2020-01-18" +] + +# 填入需要购买的车次(list),"G1353" +# 修改车次填入规则,注:(以前设置的车次逻辑不变),如果车次填入为空,那么就是当日乘车所有车次都纳入筛选返回 +# 不填车次是整个list为空才算,如果不是为空,依然会判断车次的,这种是错误的写法 [""], 正确的写法 [] +STATION_TRAINS = [] + +# 出发城市,比如深圳北,就填深圳就搜得到 +FROM_STATION = "广州南" + +# 到达城市 比如深圳北,就填深圳就搜得到 +TO_STATION = "隆回" + +# 座位(list) 多个座位ex: +# "商务座", +# "一等座", +# "二等座", +# "特等座", +# "软卧", +# "硬卧", +# "硬座", +# "无座", +# "动卧", +SET_TYPE = ["二等座"] + +# 当余票小于乘车人,如果选择优先提交,则删减联系人和余票数一致在提交 +# bool +IS_MORE_TICKET = True + +# 乘车人(list) 多个乘车人ex: +# "张三", +# "李四" +TICKET_PEOPLES = [] + +# 12306登录账号 +USER = "" +PWD = "" + +# 加入小黑屋时间默认为5分钟,此功能为了防止僵尸票导致一直下单不成功错过正常的票 +TICKET_BLACK_LIST_TIME = 5 + +# 自动打码 +IS_AUTO_CODE = True + +# 设置2本地自动打码,需要配置tensorflow和keras库,3为云打码,由于云打码服务器资源有限(为2h4C的cpu服务器),请不要恶意请求,不然只能关闭服务器 +# ps: 请不要一直依赖云服务器资源,在此向所有提供服务器同学表示感谢 +AUTO_CODE_TYPE = 3 + +# 此处设置云打码服务器地址,如果有自建的服务器,可以自行更改 +HOST = "120.77.154.140:8000" +REQ_URL = "/verify/base64/" +HTTP_TYPE = "http" +# HOST="12306.yinaoxiong.cn" #备用服务器稳定性较差 +# REQ_URL="/verify/base64/" +# HTTP_TYPE="https" + +# 邮箱配置,如果抢票成功,将通过邮件配置通知给您 +# 列举163 +# email: "xxx@163.com" +# notice_email_list: "123@qq.com" +# username: "xxxxx" +# password: "xxxxx +# host: "smtp.163.com" +# 列举qq ,qq设置比较复杂,需要在邮箱-->账户-->开启smtp服务,取得授权码==邮箱登录密码 +# email: "xxx@qq.com" +# notice_email_list: "123@qq.com" +# username: "xxxxx" +# password: "授权码" +# host: "smtp.qq.com" +EMAIL_CONF = { + "IS_MAIL": True, + "email": "", + "notice_email_list": "", + "username": "", + "password": "", + "host": "smtp.qq.com", +} + +# 是否开启 server酱 微信提醒, 使用前需要前往 http://sc.ftqq.com/3.version 扫码绑定获取 SECRET 并关注获得抢票结果通知的公众号 +SERVER_CHAN_CONF = { + "is_server_chan": False, + "secret": "" +} + +# 是否开启cdn查询,可以更快的检测票票 1为开启,2为关闭 +IS_CDN = 1 + +# 下单接口分为两种,1 模拟网页自动捡漏下单(不稳定),2 模拟车次后面的购票按钮下单(稳如老狗) +ORDER_TYPE = 2 + +# 下单模式 1 为预售,整点刷新,刷新间隔0.1-0.5S, 然后会校验时间,比如12点的预售,那脚本就会在12.00整检票,刷新订单 +# 2 是捡漏,捡漏的刷新间隔时间为0.5-3秒,时间间隔长,不容易封ip +ORDER_MODEL = 1 + +# 是否开启代理, 0代表关闭, 1表示开始 +# 开启此功能的时候请确保代理ip是否可用,在测试放里面经过充分的测试,再开启此功能,不然可能会耽误你购票的宝贵时间 +# 使用方法: +# 1、在agency/proxy_list列表下填入代理ip +# 2、测试UnitTest/TestAll/testProxy 测试代理是否可以用 +# 3、开启代理ip +IS_PROXY = 0 + +# 预售放票时间, 如果是捡漏模式,可以忽略此操作 +OPEN_TIME = "12:59:57" +# 1=使用selenium获取devicesID +# 2=使用网页端/otn/HttpZF/logdevice获取devicesId,这个接口的算法目前可能有点问题,如果登录一直302的请改为配置1 +# 3=自己打开浏览器在headers-Cookies中抓取RAIL_DEVICEID和RAIL_EXPIRATION,这个就不用配置selenium +COOKIE_TYPE = 3 +# 如果COOKIE_TYPE=1,则需配置chromeDriver路径,下载地址http://chromedriver.storage.googleapis.com/index.html +# chromedriver配置版本只要和chrome的大版本匹配就行 +CHROME_PATH = "/usr/src/app/chromedriver" + +# 为了docker37 准备的环境变量,windows环境可以不用管这个参数 +CHROME_CHROME_PATH = "/opt/google/chrome/google-chrome" + +# 如果COOKIE_TYPE=3, 则需配置RAIL_EXPIRATION、RAIL_DEVICEID的值 +RAIL_EXPIRATION = "" +RAIL_DEVICEID = "" +# RAIL_EXPIRATION = "1577034103293" +# RAIL_DEVICEID = "CDno29Erc_Pf3FSXb4dzq-Op64EhWrsi5yUZKVIKR1MAfYo2qFlCeXD8VkexY7_1qg-ClV-fE8j9jgVlPZxRh3wVc2iqLe_5A8sdr62qZx4B22JPF8lFCjpgTKZ5ODW90HJd5tiQsJ1KR9nOqHRxHj1FT5LEIwfw" + + +# 1=>为一直随机ua,2->只启动的时候随机一次ua +RANDOM_AGENT = 2 + +PASSENGER_TICKER_STR = { + '一等座': 'M', + '特等座': 'P', + '二等座': 'O', + '商务座': 9, + '硬座': 1, + '无座': 1, + '软座': 2, + '软卧': 4, + '硬卧': 3, +} + +# 保护12306官网请求频率,设置随机请求时间,原则为5分钟不大于80次 +# 最大间隔请求时间 +MAX_TIME = 3 +# 最小间隔请求时间 +MIN_TIME = 1 + +# 软件版本 +RE_VERSION = "1.2.004" diff --git a/src/12306/UnitTest/TestAll.py b/src/12306/UnitTest/TestAll.py new file mode 100644 index 0000000..b73091a --- /dev/null +++ b/src/12306/UnitTest/TestAll.py @@ -0,0 +1,119 @@ +# coding=utf-8 +import base64 +import threading +import unittest +from collections import OrderedDict + +import requests + +import TickerConfig +from agency.agency_tools import proxy +from config.emailConf import sendEmail +from config.serverchanConf import sendServerChan +from inter.LiftTicketInit import liftTicketInit + + +def _set_header_default(): + header_dict = OrderedDict() + header_dict["Accept"] = "*/*" + header_dict["Accept-Encoding"] = "gzip, deflate" + header_dict["X-Requested-With"] = "superagent" + + header_dict[ + "User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1" + header_dict["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8" + + +class testAll(unittest.TestCase): + def testProxy(self): + """ + 测试代理是否可用 + :return: + """ + _proxy = proxy() + proxie = _proxy.setProxy() + url = "http://httpbin.org/ip" + rsp = requests.get(url, proxies=proxie, timeout=5, headers=_set_header_default()).content + print(u"当前代理ip地址为: {}".format(rsp)) + + def testEmail(self): + """ + 实测邮箱是否可用 + :return: + """ + sendEmail(u"订票小助手测试一下") + + # def testConfig(self): + # """ + # 测试config是否配置正确 + # :return: + # """ + + def testServerChan(self): + """ + 实测server酱是否可用 + :return: + """ + sendServerChan(u"server酱 微信通知测试一下") + + def testUserAgent(self): + """ + 测试UserAgent + :return: + """ + from fake_useragent import UserAgent + for i in range(10000): + ua = UserAgent(verify_ssl=False) + print(ua.random) + + def testVerfyImage(self): + """ + 测试模型加载识别 + :return: + """ + from verify.localVerifyCode import Verify + v = Verify() + with open('../tkcode.png', 'rb') as f: + base64Image = base64.b64encode(f.read()) + for i in range(5): + t = threading.Thread(target=v.verify, args=(base64Image,)) + t.start() + + def testRemoteVerfy(self): + """ + 测试打码是否可用 + :return: + """ + import requests + import time + while True: + try: + starttime = time.time() + rsp = requests.post(url="http://120.77.154.140:8000/verify/base64/", + data={ + 'imageFile': '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'}, + timeout=60, + ) + print(rsp.content) + print(f"响应时间{time.time()-starttime}m") + except: + pass + + def testCdn(self): + """ + 测试cdn筛选 + :return: + """ + cdn = ["60.9.0.19", "60.9.0.20", "113.16.212.251", "36.250.248.27"] + from inter.LiftTicketInit import liftTicketInit + from init.select_ticket_info import select + from config.getCookie import getDrvicesID + + s = select() + s.httpClint.cdn = cdn[3] + getDrvicesID(s) + liftTicketInit(s).reqLiftTicketInit() + + +if __name__ == '__main__': + unittest.main() diff --git a/src/12306/UnitTest/__init__.py b/src/12306/UnitTest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/Update.md b/src/12306/Update.md new file mode 100644 index 0000000..cc5c979 --- /dev/null +++ b/src/12306/Update.md @@ -0,0 +1,191 @@ +- 2017.5.13跟新 + - 增加登陆错误判断(密码错误&ip校验) + - 修改queryOrderWaitTime,校验orderId字段bug,校验msg字段bug,校验messagesbug + - 修改checkQueueOrder 校验 data 字段的列表推导式bug + - 增加代理ip方法,目前已可以过滤有用ip + + +- 2018.1.7 号更新 + - 增加自动配置 + ``` + #station_date:出发日期,格式ex:2018-01-06 + #from_station: 始发站 + #to_station: 到达站 + #set_type: 坐席(商务座,二等座,特等座,软卧,硬卧,硬座,无座) + #is_more_ticket:余票不足是否自动提交 + #select_refresh_interval:刷新间隔时间,1为一秒,0.1为100毫秒,以此类推 + #ticke_peoples: 乘客 + #damatu:打码图账号,用于自动登录 + ``` + - 优化订票流程 + - 支持自动刷票,自动订票 + +- 2018.1.8 更新 + - 增加小黑屋功能 + - 修复bug若干 + - 增加多账号同时订票功能 + - 增加按照选定车次筛选购买车次 + +- 2018.1.9 更新 + + - 增加手动打码,只是登录接口,完全不用担心提交票的效率问题,要挂linux系统的话,还是去注册个打码兔吧 + ``` + 思路 + 1.调用PIL显示图片 + 2.图片位置说明,验证码图片中每个图片代表一个下标,依次类推,1,2,3,4,5,6,7,8 + 3.控制台输入对应下标,按照英文逗号分开,即可手动完成打码, + ``` + - 修改无座和硬座的座位号提交是个字符串的问题 + - 增加校验下单需要验证码功能 + - 增强下单成功判断接口校验 + +- 2018.1.10 更新 + - 优化查票流程 + - 修改二等座的余票数返回为字符串的问题 + - 优化订单查询bug +- 2018.1.12更新 + - 优化抢票页面逻辑 + -增强代码稳定性 + +- 2018.1.13更新 + - 修改下单验证码功能 + - 优化大量调用user接口导致联系人不能用,理论加快订票速度 + - 增加邮箱功能 + ``` + #is_email: 是否需要邮件通知 ex: True or False 切记,邮箱加完一定要到config目录下测试emailConf功能是否正常 + #email: 发送的邮箱地址 ex: 1@qq.com + #notice_email_list: 被通知人邮箱 ex: 2@qq.com + #username: 邮箱账号 + #password: 邮箱密码 + #host: 邮箱地址 + ``` + +- 2018.1.14更新 + - 优化订票流程 + - 优化挂机功能 + - 修改之前程序到11点自动跳出功能,现在修改为到早上7点自动开启刷票 + - 需要开启打码兔代码功能,is_auto_code 设置为True + - 增加异常判断 + +- 2018.1.15更新 + - 增加捡漏自动检测是否登录功能,建议捡漏不要刷新太快,2S最好,否则会封IP + - 优化提交订单有很大记录无限排队的情况,感谢群里的小伙伴提供的思路 + - 修改休眠时间为早上6点 + +- 2018.1.20更新,好久没跟新了,群里的小伙伴说登录不行了,今晚抽空改了一版登录,妥妥的 + - 更新新版登录功能,经测试,更稳定有高效 + - 优化手动打码功能 + - 更新请求第三方库 + - 优化若干代码,小伙伴尽情的放肆起来 + +- 2018.1.21跟新 + - 修复若干bug + - 合并dev + - 恢复之前因为12306改版引起的订票功能 + - 增加派对失败自动取消订单功能 + - 优化接口请求规范 + - 增加多日期查询,请严格按照yaml格式添加 即可 + - 注意:如果多日期查询的话,可能查询时间会比较长 + - 增加如果排队时间超过一分钟,自动取消订单 + +- 2018.1.23更新 + - 增加若快平台打码,yaml新增字段auto_code_type,1=打码兔,2=若快 若快注册地址:http://www.ruokuai.com/client/index?6726 + - 修改is_auto_code字段为全部是否自动打码字段,也就是说字段为True,则全部自动打码,为False全部手动打码,包括提交订单,注意centOs不可设置手动打码 + - 修复bug + - 优化抢票功能 + +- 2018.1.25更新 + - 删除 expect_refresh_interval 无用字段,优化代码 + +- 2018.1.29更新 + - 增加cdn轮训功能,优势, is_cdn=1为开启cdn,2为普通查询 + - 能够一定程度躲避封ip + - 查询余票快人一步 + - 提交订单快人一步 + - 僵尸票可能会少很多 + - 兼容Windows cmd命令乱码问题 + - 规范12306接口提交参数 + - 修改已知bug + - 最后感谢群里提供测试和代码的小伙伴,能为你们买到一张回家的票真的感到灰常开心 + +- 2018.2.28更新,收12306风控影响,代码可能有时候会进入慢排队,请自行调整刷新参数 + - 修改已知bug + - 优化接口提交参数规范 + +- 2018.8.29更新,解决慢排队问题,增加双订票接口 + - 修改已知bug + - 优化代码结构 + - 新增第三方库wrapcache,需要重新安装requirements.txt + +- 2018.9.21更新,修复已知问题,增加余票不足优先提交功能 + - 修改已知bug + - 优化查询攻略 + - 优化随机查询1-3秒,经测试很稳定,不会封ip + - 增加余票不足优先提交功能(当余票小于乘车人,如果选择优先提交,则删减联系人和余票数一致在提交) + - 开关为ticket_config.yaml配置文件中is_more_ticket参数 + +- 2018.12.26更新 + - 优化已知bug + - 开启cdn查询 + - 自动识别查询接口 + +- 2019.01.09更新 + - ticket_config 配置文件增加order_model字段(下单模式) + - mac和linux服务器自动对点 + - 增加预售踩点查询下单,经测试,误差在0.004s + +- 2019.01.12更新 + - 增加对python3语法的支持 + - 删除校验时间很多机器不兼容的问题(win10会阻拦对时功能,导致大面积报错),如果是预售,为了不耽误宝贵的时间,请手动对时 + +- 2019.01.15更新 + - 删除敏感信息打印 + - 增加server酱推送购票成功通知 + - 修改11点都登录消耗快豆问题 + - 增加gui界面 + +- 2019.04.01更新 + - 增加登录接口,解决无法03.31登录 + +- 2019.04.23更新 + - 修复登录302问题,如果下次没来得及更新,请自行抓包修改urlConf中getDevicesId接口即可登录 + +- 2019.04.23更新 + - 更新本地识别 + +- 2019.08.31更新 + - 删除若快打码 + - 修复不能下单问题 + - 放弃支持python2.7,只支持3.6以上版本 + +- 2019.09.01更新 + - 去除yaml配置文件,改为py文件配置 + - 增加候补订单功能 + - 新增TICKET_TYPE字段,1=刷票 2=候补 + - 目前候补只支持单车次,多乘车人候补,由于目前不是很懂候补的需求,所以暂时这样做 + +- 2019.09.02更新 + - 剔除新增TICKET_TYPE字段,发现此字段冗余,目前改为全天自动候补+捡漏 + - 增加候补订单功能 + - 优先级:下单再候补 + +- 2019.09.03更新 + - 恢复TICKET_TYPE字段,1=刷票 2=候补+刷票 + - 优化候补逻辑 + - 候补订单只能在规定车次内候补 + +- 2019.09.07更新 + - 优化候补逻辑 + - 去除敏感信息打印 + +- 2019.09.09更新 + - 优化候补逻辑 + +- 2019.09.15更新 + - 增长随机停留时长 + - 增长用户心跳时间,减少对服务器压力 + - 优化下单逻辑 + +- 2019.09.18更新 + - 修改下单问题 + - 优化车次打印 \ No newline at end of file diff --git a/src/12306/__init__.py b/src/12306/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/agency/__init__.py b/src/12306/agency/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/agency/agency_tools.py b/src/12306/agency/agency_tools.py new file mode 100644 index 0000000..6868435 --- /dev/null +++ b/src/12306/agency/agency_tools.py @@ -0,0 +1,107 @@ +# encoding=utf8 +import os +import random +import socket +import time + +import requests +from bs4 import BeautifulSoup + + +class proxy: + def __init__(self): + self.proxy_list = [] + self.proxy_filter_list = [] + + def get_proxy(self): + """ + 获取未加工代理列表 + :return: + """ + User_Agent = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0' + header = dict() + header['User-Agent'] = User_Agent + + for i in range(1, 5): + time.sleep(1) + url = 'http://www.xicidaili.com/nn/' + str(i) + res = requests.get(url=url, headers=header).content + + soup = BeautifulSoup(res, "html.parser") + ips = soup.findAll('tr') + + for x in range(1, len(ips)): + ip = ips[x] + tds = ip.findAll("td") + ip_temp = tds[1].contents[0] + ":" + tds[2].contents[0] + print(ip_temp) + self.proxy_list.append(ip_temp) + + def filter_proxy(self): + """ + 将不可用IP剔除 + :return: + """ + socket.setdefaulttimeout(1) + path = os.path.join(os.path.dirname(__file__), './proxy_list') + f = open(path, "w") + head = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36', + 'Connection': 'keep-alive'} + url = "http://icanhazip.com" + proxy_num = 0 + for proxy in self.proxy_list: + proxy_temp = {"https": "https://{}".format(proxy)} + try: + req = requests.get(url, proxies=proxy_temp, timeout=2, headers=head).content + print(req) + write_proxy = proxy + "\n" + f.write(write_proxy) + proxy_num += 1 + except Exception: + print ("代理链接超时,去除此IP:{0}".format(proxy)) + continue + print("总共可使用ip量为{}个".format(proxy_num)) + + def get_filter_proxy(self): + """ + 读取该可用ip文件 + :return: 可用ip文件list + """ + path = os.path.join(os.path.dirname(__file__), './proxy_list') + try: + with open(path, "r", encoding="utf-8") as f: + lins = f.readlines() + for i in lins: + p = i.strip("\n") + self.proxy_filter_list.append(p) + except Exception: + with open(path, "r", ) as f: + lins = f.readlines() + for i in lins: + p = i.strip("\n") + self.proxy_filter_list.append(p) + return self.proxy_filter_list + + def main(self): + # self.get_proxy() + self.filter_proxy() + + def setProxy(self): + """ + 开启此功能的时候请确保代理ip是否可用 + 查询的时候设置代理ip,ip设置格式是ip地址+端口,推荐可用的ip代理池:https://github.com/jhao104/proxy_pool + :return: + """ + ip = self.get_filter_proxy() + setIp = ip[random.randint(0, len(ip) - 1)] + proxie = { + 'http': 'http://{}'.format(setIp), + 'https': 'http://{}'.format(setIp), + } + return proxie + + +if __name__ == "__main__": + a = proxy() + print(a.get_filter_proxy()) diff --git a/src/12306/agency/cdn_utils.py b/src/12306/agency/cdn_utils.py new file mode 100644 index 0000000..01b95bc --- /dev/null +++ b/src/12306/agency/cdn_utils.py @@ -0,0 +1,101 @@ +# encoding=utf8 +import datetime +import operator +import os +import requests +from config import urlConf +import threading +from config.urlConf import urls + +from myUrllib.httpUtils import HTTPClient + +cdn_list = [] + + +class CDNProxy(threading.Thread): + def __init__(self, cdns): + super().__init__() + self.cdns = cdns + self.urlConf = urlConf.urls + self.httpClint = requests + self.city_list = [] + self.timeout = 5 + + def run(self): + for cdn in self.cdns: + http = HTTPClient(0) + url = urls["loginInitCdn"] + http._cdn = cdn.replace("\n", "") + start_time = datetime.datetime.now() + rep = http.send(url) + retTime = (datetime.datetime.now() - start_time).microseconds / 1000 + if rep and "message" not in rep and retTime < 3000: + if cdn.replace("\n", "") not in cdn_list: # 如果有重复的cdn,则放弃加入 + print(f"加入cdn: {cdn}") + cdn_list.append({"ip": cdn.replace("\n", ""), "time": retTime}) + + +def open_cdn_file(cdnFile): + cdn = [] + path = os.path.join(os.path.dirname(__file__), f'../{cdnFile}') + try: + with open(path, "r", encoding="utf-8") as f: + for i in f.readlines(): + if i and "kyfw.12306.cn:443" not in i: + cdn.append(i.replace("\n", "")) + return cdn + except Exception: + with open(path, "r") as f: + for i in f.readlines(): + if i and "kyfw.12306.cn:443" not in i: + cdn.append(i.replace("\n", "")) + return cdn + + +def sortCdn(): + """ + 对cdn进行排序 + :return: + """ + ips = [] + cs = sorted(cdn_list, key=operator.itemgetter('time')) + for c in cs: + print(f"当前ip: {c['ip']}, 延时: {c['time']}") + ips.append(c["ip"]) + return ips + + +def filterCdn(): + """ + 过滤cdn, 过滤逻辑为当前cdn响应值小于1000毫秒 + 过滤日志: + 加入cdn: 116.77.75.146 + :return: + """ + cdns = open_cdn_file("cdn_list") + cdnss = [cdns[i:i + 50] for i in range(0, len(cdns), 50)] + cdnThread = [] + for cdn in cdnss: + t = CDNProxy(cdn) + cdnThread.append(t) + for cdn_t in cdnThread: + cdn_t.start() + + for cdn_j in cdnThread: + cdn_j.join() + + print(f"当前有效cdn个数为: {len(cdn_list)}") + if cdn_list: + ips = sortCdn() + path = os.path.join(os.path.dirname(__file__), f'../filter_cdn_list') + f = open(path, "a+") + f.seek(0) + f.truncate() + f.writelines("") + for ip in ips: + f.writelines(f"{ip}\n") + f.close() + + +if __name__ == '__main__': + filterCdn() diff --git a/src/12306/agency/proxy_list b/src/12306/agency/proxy_list new file mode 100644 index 0000000..fb30cba --- /dev/null +++ b/src/12306/agency/proxy_list @@ -0,0 +1 @@ +119.101.114.196:9999 \ No newline at end of file diff --git a/src/12306/cdn_list b/src/12306/cdn_list new file mode 100644 index 0000000..60e3050 --- /dev/null +++ b/src/12306/cdn_list @@ -0,0 +1,1830 @@ +112.123.33.18 +112.28.196.75 +112.28.196.100 +112.29.227.103 +112.29.227.250 +112.29.227.106 +112.30.197.137 +112.28.196.54 +112.30.197.16 +112.28.196.251 +112.28.196.249 +112.28.196.53 +112.28.196.74 +112.30.198.110 +112.29.227.251 +112.29.227.107 +112.30.197.250 +112.30.197.17 +60.174.243.155 +211.162.1.168 +60.174.243.190 +112.29.227.45 +60.174.243.156 +60.174.243.157 +112.29.227.102 +112.28.196.101 +103.254.191.203 +103.254.189.230 +61.132.238.93 +61.132.238.126 +61.132.238.94 +60.174.243.166 +111.206.186.37 +114.112.160.123 +61.132.238.91 +103.254.191.210 +106.120.178.253 +111.200.194.219 +106.120.178.20 +114.112.172.52 +103.254.189.229 +106.120.178.22 +114.112.160.201 +114.112.160.29 +114.112.172.123 +114.112.160.31 +114.112.172.56 +114.112.172.55 +114.112.160.30 +61.132.238.92 +114.112.160.124 +114.112.172.241 +114.112.160.253 +122.70.142.175 +114.112.172.54 +114.112.172.53 +114.113.88.86 +122.70.142.176 +114.113.88.85 +106.120.178.19 +114.112.172.58 +114.113.88.84 +114.113.88.88 +122.70.142.148 +122.70.142.147 +114.112.172.57 +114.113.88.123 +114.112.172.60 +114.112.172.61 +114.112.172.59 +114.112.160.32 +159.226.225.149 +114.113.88.89 +159.226.225.154 +36.110.141.253 +39.134.134.74 +159.226.225.139 +159.226.225.140 +114.113.88.87 +122.70.142.252 +61.149.22.254 +39.134.134.77 +61.149.22.35 +61.149.22.34 +61.149.9.150 +61.149.9.170 +61.149.9.239 +112.47.14.198 +112.47.14.199 +112.47.20.250 +112.47.14.201 +112.47.20.67 +112.47.20.77 +112.47.14.200 +112.47.20.88 +112.47.20.68 +112.47.27.132 +112.47.20.89 +112.47.20.209 +112.47.20.79 +112.47.27.131 +112.47.56.174 +112.47.27.172 +112.47.56.117 +112.51.121.107 +112.47.56.118 +112.51.125.243 +112.5.62.12 +112.51.121.108 +112.51.125.254 +112.51.125.33 +112.51.125.53 +112.51.125.251 +112.51.125.54 +112.51.125.62 +112.51.125.252 +112.51.121.251 +112.51.125.65 +117.27.241.110 +112.51.125.74 +117.27.241.112 +112.51.125.73 +117.27.241.125 +117.27.241.113 +117.27.241.126 +117.27.241.111 +117.27.241.213 +117.27.241.214 +117.27.241.254 +117.27.241.218 +117.27.241.76 +117.27.245.223 +117.27.245.225 +117.27.245.227 +117.27.245.254 +117.27.245.52 +117.27.245.97 +117.27.245.54 +125.77.130.247 +125.77.130.251 +125.77.130.44 +125.77.130.45 +125.77.130.46 +125.77.130.47 +125.77.130.48 +125.77.130.49 +125.77.140.120 +125.77.140.121 +125.77.140.30 +125.77.140.42 +125.77.140.53 +125.77.140.54 +125.77.140.55 +125.77.140.64 +125.77.140.91 +125.77.140.92 +125.77.140.95 +125.77.147.254 +125.77.147.62 +125.77.147.67 +125.77.147.63 +125.77.147.66 +125.77.147.68 +125.77.147.69 +125.77.147.83 +125.77.147.80 +125.77.147.82 +125.77.147.88 +175.43.20.64 +175.43.20.118 +183.253.58.102 +175.43.20.65 +183.253.58.137 +183.253.58.103 +183.253.58.253 +183.253.58.76 +27.148.151.175 +27.148.151.174 +27.148.151.177 +27.148.151.176 +27.148.151.178 +27.148.151.179 +27.148.151.180 +27.148.151.251 +27.155.72.251 +27.148.151.72 +27.155.72.44 +27.155.72.47 +36.250.233.185 +36.250.233.208 +36.250.233.209 +36.250.233.210 +36.250.233.211 +36.250.233.212 +36.250.233.214 +36.250.233.228 +36.250.248.218 +36.250.248.217 +36.250.233.254 +36.250.248.210 +36.250.248.219 +36.250.248.220 +36.250.248.221 +36.250.248.223 +36.250.248.222 +36.250.248.25 +36.250.248.24 +36.250.248.252 +36.250.248.254 +36.250.248.27 +36.250.248.55 +36.250.248.56 +36.250.74.128 +36.250.74.127 +36.250.74.244 +59.56.30.250 +59.56.30.51 +118.180.15.252 +59.56.30.52 +118.180.15.33 +118.180.15.86 +118.180.15.87 +118.180.57.100 +118.180.57.101 +118.180.57.250 +125.74.58.134 +125.74.58.135 +125.74.58.136 +125.74.58.137 +125.74.58.138 +125.74.58.254 +125.75.35.173 +125.75.35.189 +125.75.35.190 +180.95.178.250 +202.201.14.181 +180.95.178.38 +112.90.133.246 +112.90.133.247 +112.90.133.253 +112.90.135.228 +112.90.135.229 +112.90.135.238 +112.90.135.240 +112.90.135.244 +112.90.135.91 +112.90.135.92 +112.90.135.93 +112.90.135.94 +112.90.135.95 +112.90.135.96 +112.90.135.97 +112.90.135.98 +112.90.135.99 +113.104.14.227 +113.104.14.23 +113.104.14.24 +113.104.14.248 +113.104.14.25 +113.104.14.26 +113.104.14.27 +113.104.14.28 +222.186.145.51 +122.228.237.248 +222.186.145.54 +222.44.151.24 +150.138.167.51 +58.216.21.63 +222.186.145.52 +121.46.247.75 +60.210.23.26 +221.235.187.119 +59.63.221.41 +60.210.23.116 +61.147.226.46 +222.186.145.53 +61.147.226.48 +122.224.186.223 +60.210.23.29 +221.235.187.67 +58.221.78.58 +183.146.22.142 +183.146.22.139 +221.235.187.121 +121.46.247.72 +122.225.83.26 +222.186.145.251 +153.101.208.89 +61.147.227.53 +113.104.14.29 +113.104.14.32 +113.104.14.30 +113.104.14.31 +113.104.14.33 +113.104.14.34 +116.199.127.50 +116.199.127.54 +116.77.73.164 +116.77.73.165 +116.199.127.55 +116.77.75.133 +116.77.75.137 +116.199.127.56 +116.77.75.138 +116.77.75.145 +116.77.75.144 +116.77.75.169 +116.77.75.146 +116.77.75.147 +116.77.75.170 +120.198.197.251 +116.77.75.183 +119.147.183.43 +120.198.197.87 +120.198.197.88 +120.241.57.161 +120.241.57.252 +120.241.57.30 +120.241.57.48 +120.241.57.57 +120.241.57.92 +121.11.81.100 +121.11.81.101 +121.11.81.102 +121.11.81.103 +121.11.81.104 +121.11.81.237 +125.90.206.240 +125.90.206.241 +125.90.206.242 +125.90.206.243 +125.90.206.244 +125.90.206.245 +125.90.206.246 +125.90.206.248 +125.90.206.42 +125.90.206.43 +125.90.206.77 +14.17.80.68 +14.17.80.71 +14.17.80.73 +125.90.206.79 +125.90.206.76 +125.90.206.49 +125.90.206.78 +125.90.206.80 +14.17.80.253 +125.90.206.81 +14.17.80.69 +14.17.80.67 +14.17.80.70 +125.90.206.82 +14.17.80.74 +14.17.80.72 +14.17.80.254 +14.17.80.76 +14.17.80.75 +14.17.80.77 +14.17.80.78 +14.17.80.79 +14.17.80.80 +14.17.80.81 +14.17.80.82 +14.17.80.83 +14.17.80.84 +14.17.80.85 +14.17.80.86 +14.17.80.88 +14.18.17.239 +14.18.17.240 +14.18.17.249 +14.18.17.241 +14.21.78.112 +14.21.78.138 +14.21.78.43 +14.21.78.44 +14.21.78.45 +14.21.78.46 +14.21.78.47 +157.255.76.25 +14.21.78.48 +157.255.76.26 +157.255.76.30 +157.255.76.48 +163.177.132.254 +163.177.132.27 +163.177.132.28 +163.177.132.29 +163.177.132.30 +163.177.132.31 +163.177.243.10 +163.177.243.240 +163.177.243.247 +183.236.28.116 +183.236.28.121 +183.236.28.122 +183.236.28.123 +183.236.28.124 +183.236.28.146 +183.236.28.151 +183.236.28.25 +183.236.28.27 +183.236.28.48 +183.240.52.106 +183.240.52.107 +183.240.52.108 +183.240.52.109 +183.240.52.132 +183.47.216.18 +183.47.216.19 +183.47.216.20 +183.47.216.35 +183.47.216.36 +183.47.216.37 +183.47.216.87 +183.56.172.251 +183.56.172.30 +183.56.172.31 +183.56.172.32 +183.56.172.33 +183.56.172.34 +183.56.172.35 +183.62.114.154 +183.62.114.155 +183.62.114.195 +210.38.3.23 +210.38.3.24 +210.38.3.42 +210.38.3.49 +210.38.3.50 +210.38.3.60 +218.13.52.109 +61.145.100.15 +61.145.100.17 +61.145.100.20 +61.145.100.27 +123.128.14.71 +123.53.139.37 +61.145.100.30 +221.235.187.106 +61.145.100.33 +61.145.100.44 +61.145.100.45 +61.145.100.54 +113.16.208.143 +113.16.208.233 +113.16.208.251 +113.16.208.77 +113.16.208.78 +113.16.212.21 +113.16.212.251 +113.16.212.48 +113.16.212.49 +222.218.87.247 +222.218.87.252 +222.218.87.26 +222.218.87.27 +222.218.87.28 +222.218.87.29 +36.159.115.250 +36.159.115.88 +36.159.115.89 +110.242.21.24 +110.242.21.23 +110.242.21.254 +110.242.21.243 +110.242.21.41 +110.242.21.71 +110.242.21.70 +111.62.194.141 +111.62.194.30 +111.62.194.31 +111.62.194.254 +111.62.89.38 +111.62.92.55 +111.62.92.56 +111.62.92.59 +111.62.92.60 +111.62.92.6 +111.62.92.61 +111.63.72.55 +111.63.72.126 +121.22.247.202 +121.22.247.204 +121.22.247.254 +123.183.164.34 +111.63.72.56 +121.22.247.203 +123.183.164.248 +123.183.164.249 +123.183.164.35 +123.183.164.79 +123.183.164.80 +123.183.164.251 +123.183.164.81 +123.183.164.82 +123.183.164.91 +123.183.164.94 +123.183.164.92 +123.183.164.96 +123.183.164.97 +123.183.164.99 +124.236.28.100 +124.236.28.252 +124.236.28.67 +124.236.28.247 +124.236.28.69 +124.236.28.68 +124.236.28.91 +124.236.28.93 +124.236.28.92 +124.236.28.94 +124.236.28.95 +124.236.28.96 +124.236.28.97 +124.236.28.98 +124.236.28.99 +124.236.97.38 +124.236.97.45 +124.236.97.39 +124.236.97.48 +124.236.97.49 +124.239.182.115 +124.239.182.116 +124.239.182.117 +124.239.182.118 +124.239.182.119 +124.239.182.120 +124.239.182.95 +175.188.163.55 +175.188.163.8 +218.12.228.202 +218.12.228.203 +218.12.228.204 +218.12.228.205 +218.12.228.221 +218.12.228.224 +218.12.228.246 +218.12.228.38 +218.12.228.39 +218.12.228.40 +221.194.180.26 +221.194.180.54 +221.194.180.92 +221.194.180.95 +221.194.180.93 +60.9.0.14 +60.9.0.16 +60.9.0.17 +60.9.0.18 +60.9.0.19 +60.9.0.20 +60.9.0.21 +60.9.0.22 +60.9.0.23 +60.9.0.252 +60.9.0.254 +111.6.176.208 +111.6.176.209 +111.6.176.248 +111.6.176.25 +111.6.176.94 +111.6.176.95 +111.6.176.97 +111.6.177.215 +111.6.177.254 +115.54.16.151 +111.6.177.216 +115.54.16.249 +115.54.16.62 +115.54.16.252 +115.54.16.86 +115.54.16.245 +115.54.16.87 +115.54.16.88 +115.54.16.91 +115.54.16.92 +123.53.139.252 +123.53.139.253 +123.53.139.36 +123.53.139.38 +123.53.139.39 +123.53.139.59 +123.53.139.60 +125.42.203.62 +218.29.198.42 +218.29.198.43 +218.29.198.62 +218.29.50.27 +219.157.114.149 +219.157.114.150 +219.157.114.252 +219.157.114.70 +219.157.114.71 +219.157.114.72 +219.157.114.73 +221.15.67.155 +221.15.67.156 +221.15.67.157 +221.15.67.158 +221.15.67.161 +221.15.67.162 +221.15.67.163 +221.15.67.164 +221.15.67.231 +221.15.67.234 +221.15.67.248 +222.138.255.252 +222.138.255.250 +222.138.255.41 +222.138.255.45 +222.138.255.46 +222.138.255.47 +61.136.107.45 +61.136.107.46 +61.136.107.57 +61.54.7.158 +61.54.7.174 +61.54.7.179 +61.54.7.243 +111.40.183.249 +111.40.183.55 +111.40.183.56 +111.40.183.65 +111.41.54.102 +111.41.54.103 +111.41.54.254 +111.41.54.80 +113.5.80.102 +113.5.80.251 +113.5.80.33 +118.203.202.206 +118.203.202.207 +118.203.202.208 +118.203.202.209 +118.203.202.222 +219.147.93.104 +219.147.93.105 +219.147.93.242 +219.147.93.244 +219.147.93.243 +219.147.93.62 +221.206.126.108 +221.206.126.110 +221.206.126.111 +221.206.126.227 +221.206.126.228 +221.206.126.245 +61.167.54.236 +61.167.54.242 +61.167.54.26 +61.167.54.31 +61.167.54.55 +61.167.54.57 +111.178.233.197 +111.178.233.207 +111.178.233.220 +111.178.233.221 +111.47.220.251 +111.47.220.66 +111.47.220.67 +115.156.188.243 +115.156.188.247 +115.157.63.19 +115.157.63.49 +115.157.63.50 +115.157.63.51 +115.157.63.52 +115.157.63.62 +116.207.132.181 +116.207.132.183 +116.207.132.184 +116.207.132.253 +119.36.60.253 +119.36.60.29 +119.36.60.30 +119.36.91.138 +119.36.91.139 +119.36.91.182 +202.114.51.32 +202.114.51.35 +202.114.51.59 +202.114.51.60 +202.114.51.65 +202.114.51.75 +219.138.186.254 +219.138.186.41 +219.138.186.42 +219.138.186.43 +219.138.186.44 +219.138.26.195 +219.138.26.196 +219.138.26.197 +219.138.26.214 +219.138.27.107 +219.138.27.108 +219.138.27.249 +219.138.27.28 +219.138.27.30 +219.138.27.31 +221.235.187.129 +221.235.187.130 +221.235.187.131 +221.235.187.132 +221.235.187.133 +221.235.187.134 +221.235.187.220 +221.235.187.244 +221.235.187.65 +221.235.187.66 +221.235.187.90 +221.235.187.98 +222.20.147.143 +222.20.147.144 +222.20.147.145 +222.20.147.150 +222.20.147.158 +222.20.147.164 +222.20.147.169 +222.20.147.174 +222.20.147.183 +222.20.147.189 +222.20.147.184 +222.20.147.198 +222.20.147.200 +222.20.147.201 +49.210.3.156 +49.210.3.160 +222.20.147.199 +49.210.3.177 +49.210.3.213 +58.51.168.202 +58.51.168.196 +58.51.168.206 +49.210.3.164 +58.51.168.45 +58.51.168.46 +58.51.168.47 +58.51.168.62 +58.51.168.63 +58.51.168.64 +58.51.168.65 +58.51.168.74 +61.136.167.17 +61.136.167.18 +61.136.167.20 +61.136.167.19 +61.136.167.21 +61.136.167.22 +61.136.167.254 +61.184.117.22 +61.184.117.25 +61.184.117.24 +61.184.117.23 +61.184.117.27 +61.184.118.86 +61.184.118.84 +61.184.117.50 +61.184.117.29 +120.226.48.144 +120.226.48.28 +120.226.48.25 +120.226.48.27 +120.226.48.26 +120.226.49.146 +120.226.49.252 +120.226.49.80 +120.226.49.87 +120.226.49.81 +120.226.49.83 +120.226.49.82 +120.226.55.144 +120.226.55.151 +120.226.55.254 +183.214.1.227 +183.214.1.24 +183.214.1.25 +183.214.1.251 +183.214.1.26 +183.214.1.30 +183.214.1.253 +183.214.1.32 +183.214.132.106 +183.214.132.120 +183.214.132.16 +183.214.132.17 +183.214.132.185 +183.214.132.186 +183.214.132.251 +183.214.132.187 +183.214.140.203 +183.214.140.204 +218.75.154.40 +218.75.154.89 +183.214.140.238 +218.75.154.94 +218.76.105.108 +218.76.105.109 +218.76.105.252 +218.76.129.173 +218.76.129.174 +218.76.129.176 +218.76.129.175 +58.20.179.253 +218.76.129.252 +58.20.179.31 +58.20.179.74 +58.20.179.73 +106.41.0.37 +106.41.0.44 +106.41.0.45 +106.41.0.46 +106.41.0.47 +106.41.0.61 +106.41.0.62 +111.26.107.19 +111.26.157.7 +119.52.120.138 +119.52.120.139 +119.52.120.140 +119.52.120.144 +119.52.120.145 +119.52.120.146 +122.136.46.119 +122.136.46.120 +122.136.46.126 +122.136.46.66 +139.209.49.140 +139.209.49.138 +139.209.49.144 +139.209.49.151 +139.209.49.152 +139.209.49.153 +222.163.194.230 +222.163.194.27 +222.163.194.28 +222.163.194.29 +222.163.194.30 +222.163.202.172 +222.163.202.241 +222.163.202.212 +36.104.132.251 +36.104.132.48 +36.104.132.49 +112.25.81.118 +112.25.81.67 +112.25.81.68 +112.25.81.69 +112.84.104.162 +112.84.104.163 +112.84.104.19 +112.84.104.52 +114.236.140.125 +114.236.140.253 +114.236.88.254 +114.236.88.45 +114.236.88.46 +114.236.88.47 +114.236.88.48 +153.101.208.254 +153.101.208.90 +153.101.208.92 +153.101.208.91 +153.101.208.93 +153.99.174.201 +153.99.174.212 +153.99.235.112 +153.99.235.217 +153.99.235.91 +180.97.178.141 +180.97.178.142 +180.97.178.146 +180.97.178.147 +180.97.178.163 +180.97.178.164 +180.97.178.165 +180.97.178.166 +180.97.178.172 +180.97.178.228 +180.97.178.229 +180.97.178.230 +180.97.178.253 +180.97.180.164 +180.97.180.165 +180.97.180.196 +218.92.209.12 +218.92.209.249 +218.92.209.41 +218.92.209.42 +221.230.141.170 +221.230.141.171 +221.230.141.172 +221.230.141.174 +221.230.141.224 +222.186.141.132 +222.186.141.135 +222.186.141.141 +222.186.141.142 +222.186.141.143 +222.186.141.145 +222.186.141.146 +222.186.141.162 +222.186.141.165 +222.186.141.166 +222.186.141.178 +222.186.141.186 +222.186.145.254 +222.186.145.84 +222.186.145.85 +222.186.145.86 +223.111.156.173 +222.186.145.87 +223.111.156.174 +223.111.156.175 +223.111.156.176 +223.111.156.188 +223.111.156.202 +223.111.156.210 +223.111.156.216 +223.111.156.249 +223.111.18.161 +223.111.18.162 +223.111.18.163 +223.111.18.217 +223.111.19.124 +223.111.19.126 +223.111.19.81 +223.111.19.90 +223.111.19.91 +223.111.196.125 +223.111.196.48 +223.111.196.49 +223.111.198.252 +223.111.198.65 +223.111.198.75 +223.111.203.126 +223.111.203.35 +223.111.203.36 +223.111.22.170 +223.111.22.249 +223.113.14.126 +223.113.14.16 +223.113.14.17 +223.113.14.215 +223.113.14.216 +223.113.14.230 +36.156.73.145 +36.156.73.146 +36.156.73.157 +36.156.73.158 +36.156.73.220 +36.156.73.254 +58.216.109.105 +58.216.109.106 +58.216.109.107 +58.216.109.108 +58.216.109.109 +58.216.109.110 +58.216.109.187 +58.216.109.192 +58.216.109.95 +58.216.109.96 +58.216.109.97 +58.216.109.99 +58.216.110.36 +58.216.21.149 +58.216.21.21 +58.216.21.22 +58.216.21.247 +58.216.21.250 +58.216.21.65 +58.216.22.17 +58.216.22.20 +58.216.22.22 +58.216.22.56 +58.216.23.100 +58.216.23.102 +58.220.220.115 +58.220.220.114 +58.220.220.251 +58.220.220.118 +58.220.220.119 +58.220.220.117 +58.220.220.252 +58.220.71.253 +58.220.71.51 +58.220.71.52 +58.220.71.62 +58.220.71.63 +58.220.71.64 +58.220.71.65 +58.220.71.66 +58.220.71.67 +58.221.28.245 +58.221.28.51 +58.221.28.52 +58.221.28.53 +58.221.28.54 +58.221.78.186 +58.221.78.229 +58.221.78.231 +58.221.78.42 +58.221.78.45 +58.221.78.46 +58.221.78.47 +58.221.78.48 +58.221.78.56 +58.221.78.57 +58.221.78.70 +58.223.164.229 +58.223.164.231 +58.223.164.232 +58.223.164.233 +58.223.164.234 +58.223.164.247 +58.223.166.116 +58.223.166.117 +58.223.166.118 +58.223.166.119 +58.223.166.120 +58.223.166.121 +58.223.166.122 +58.223.166.253 +59.83.232.17 +59.83.232.18 +59.83.232.50 +61.147.210.193 +61.147.210.195 +61.147.226.185 +61.147.210.242 +61.147.226.47 +61.147.226.49 +61.147.227.102 +61.147.227.126 +61.147.227.233 +61.147.227.52 +61.147.227.54 +61.147.227.55 +61.147.228.115 +61.147.228.117 +61.147.228.116 +61.147.228.118 +61.147.228.201 +61.147.228.60 +61.147.228.248 +61.147.228.61 +61.147.228.78 +61.147.228.89 +61.160.209.254 +61.160.209.26 +61.160.209.98 +61.160.209.96 +113.194.59.80 +113.194.59.199 +113.194.59.81 +117.169.93.247 +117.169.93.249 +117.169.93.85 +117.21.217.26 +117.169.93.86 +117.21.217.27 +117.21.217.98 +118.212.138.106 +118.212.138.107 +118.212.138.215 +118.212.150.100 +118.212.150.101 +118.212.150.102 +120.206.189.252 +120.206.189.253 +120.206.189.52 +120.206.189.53 +182.108.171.149 +182.108.171.150 +182.108.171.170 +182.108.171.171 +182.108.171.172 +182.108.171.250 +182.108.171.251 +183.216.176.116 +183.216.176.248 +183.216.176.251 +183.216.176.63 +183.216.176.64 +183.216.176.65 +183.216.176.74 +183.216.176.75 +183.216.176.83 +183.216.176.89 +219.220.29.175 +219.220.29.177 +219.220.29.182 +219.220.29.189 +219.220.29.190 +59.63.221.250 +59.63.221.253 +59.63.221.35 +59.63.221.44 +59.63.221.45 +59.63.221.46 +59.63.221.47 +59.63.221.56 +59.63.241.54 +59.63.241.81 +59.63.241.82 +59.63.241.83 +59.63.241.84 +59.63.241.85 +101.246.182.157 +101.246.182.160 +101.246.182.161 +101.246.182.209 +101.246.182.214 +101.246.182.219 +101.246.182.251 +123.184.108.251 +123.184.108.60 +123.184.108.61 +124.95.148.124 +124.95.148.254 +124.95.148.30 +124.95.148.29 +124.95.148.31 +182.201.212.140 +182.201.212.141 +182.201.212.142 +182.201.212.242 +182.201.212.79 +218.60.185.100 +218.60.185.102 +218.60.185.103 +218.60.185.215 +218.60.185.248 +218.60.185.251 +218.60.185.46 +218.60.185.47 +218.60.185.48 +221.180.192.100 +221.180.192.131 +221.180.192.235 +221.180.192.254 +221.180.192.39 +221.180.192.49 +221.180.192.61 +221.180.208.190 +221.180.208.214 +221.180.208.252 +221.180.208.46 +221.180.208.47 +221.180.208.48 +221.180.208.50 +221.180.208.54 +221.180.218.248 +221.180.218.73 +221.180.218.74 +42.176.192.171 +42.176.192.226 +42.176.192.76 +42.176.192.77 +42.176.192.78 +59.44.25.58 +59.44.25.8 +59.44.30.121 +59.44.30.25 +59.44.30.26 +59.44.30.27 +59.44.30.54 +59.47.227.144 +59.47.227.146 +59.47.227.148 +59.47.227.149 +60.18.86.100 +60.18.86.101 +60.18.86.253 +60.18.86.91 +61.243.144.141 +61.243.144.142 +61.243.144.244 +106.40.140.224 +106.40.140.222 +110.18.244.134 +106.40.140.254 +110.18.244.13 +110.18.244.252 +110.18.244.44 +110.18.244.63 +110.18.244.76 +110.19.204.219 +110.19.204.220 +110.19.204.221 +110.19.204.222 +110.19.204.254 +117.161.19.126 +117.161.19.19 +117.161.19.22 +117.161.66.125 +117.161.66.71 +218.21.175.24 +222.74.113.196 +222.74.113.219 +222.74.113.228 +222.74.113.230 +222.74.113.231 +222.74.113.229 +36.102.230.136 +36.102.230.137 +36.102.230.138 +36.102.230.19 +36.102.230.20 +36.102.230.21 +36.102.230.22 +36.102.230.253 +36.102.230.254 +58.18.254.207 +58.18.254.221 +58.18.254.253 +120.253.100.20 +120.253.100.21 +120.253.100.22 +120.253.100.23 +120.253.100.30 +211.138.60.159 +211.138.60.189 +112.240.60.172 +112.240.60.208 +112.240.60.209 +112.240.60.210 +112.240.60.211 +112.240.60.212 +112.240.60.213 +112.240.60.214 +112.240.60.215 +112.240.60.216 +112.240.60.217 +112.240.60.222 +112.240.60.236 +112.240.60.253 +112.240.60.69 +112.240.60.72 +112.240.60.73 +112.240.60.75 +112.253.38.37 +112.240.60.88 +119.176.61.23 +119.176.61.26 +119.176.61.99 +120.220.18.112 +120.220.18.113 +120.220.18.252 +120.221.23.39 +120.221.23.62 +120.221.23.63 +120.221.23.64 +120.221.64.160 +120.221.64.161 +120.221.64.169 +120.221.64.251 +120.221.64.53 +120.221.64.54 +120.221.64.55 +120.221.64.77 +123.128.14.254 +123.128.14.69 +123.128.14.68 +123.128.14.49 +123.128.14.70 +123.128.14.72 +150.138.111.251 +150.138.111.31 +150.138.111.32 +150.138.111.33 +150.138.167.234 +150.138.167.50 +150.138.167.52 +150.138.169.120 +150.138.169.121 +150.138.169.123 +150.138.169.124 +150.138.169.136 +150.138.169.137 +150.138.169.238 +150.138.214.122 +150.138.214.84 +150.138.214.124 +150.138.214.85 +150.138.214.86 +182.34.127.22 +182.34.127.21 +182.34.127.253 +182.34.127.23 +182.34.127.45 +182.34.127.48 +218.58.206.37 +218.58.206.39 +218.58.206.40 +218.58.206.41 +218.58.206.43 +218.58.206.46 +218.58.206.49 +218.58.206.53 +218.58.206.55 +218.58.206.57 +218.58.206.78 +27.195.145.121 +27.195.145.123 +27.195.145.124 +27.195.145.249 +27.195.145.52 +27.195.145.62 +27.195.145.61 +59.80.28.254 +59.80.28.58 +59.80.29.21 +59.80.29.20 +59.80.29.22 +59.80.29.30 +59.80.29.40 +59.80.29.33 +59.83.211.215 +59.83.228.160 +59.83.228.88 +59.83.228.89 +60.210.21.85 +60.210.21.86 +60.210.21.87 +60.210.21.88 +60.210.21.89 +60.210.23.175 +60.210.23.177 +60.210.23.178 +60.210.23.23 +60.210.23.25 +60.210.23.27 +60.213.21.117 +60.213.21.118 +60.213.21.156 +60.213.21.157 +60.213.21.214 +60.213.21.244 +60.213.21.243 +60.213.21.245 +60.213.21.252 +60.213.22.34 +60.213.22.57 +61.156.243.108 +61.156.243.109 +61.156.243.110 +61.156.243.111 +61.156.243.112 +61.156.243.246 +61.162.100.102 +61.162.100.103 +61.162.100.105 +61.162.100.107 +61.162.100.252 +61.162.100.41 +61.162.100.44 +124.165.125.126 +124.165.125.13 +124.165.125.134 +124.165.125.253 +124.167.218.116 +124.167.218.251 +124.167.218.117 +183.201.225.249 +183.201.225.74 +183.201.225.73 +218.26.75.149 +218.26.75.150 +218.26.75.151 +218.26.75.152 +218.26.75.153 +218.26.75.206 +218.26.75.236 +59.49.89.100 +59.49.89.45 +59.49.89.69 +60.220.196.220 +60.220.196.221 +60.220.196.222 +60.220.196.223 +60.220.196.235 +60.220.196.250 +60.220.196.240 +60.222.200.71 +111.19.215.40 +111.19.215.39 +111.19.215.127 +111.19.215.41 +111.19.215.69 +111.19.233.252 +111.19.233.253 +111.19.233.59 +111.19.233.60 +111.19.233.99 +113.142.80.223 +111.19.233.87 +113.142.80.69 +113.142.80.71 +113.142.80.72 +113.142.88.253 +113.142.88.31 +113.142.90.226 +113.142.90.235 +113.142.90.236 +117.23.2.241 +117.23.2.252 +117.23.2.28 +117.23.2.29 +117.23.2.30 +123.138.157.85 +123.138.157.122 +123.138.157.93 +123.138.157.96 +123.138.203.115 +123.138.203.20 +123.138.203.21 +123.138.203.56 +123.138.60.154 +124.116.133.15 +124.116.133.126 +124.116.133.16 +124.116.133.17 +124.116.133.18 +124.116.133.19 +124.116.133.20 +124.116.133.63 +124.116.133.76 +219.145.171.249 +124.116.133.77 +219.145.171.40 +219.145.171.41 +222.24.122.79 +222.24.122.86 +222.24.122.89 +101.227.99.21 +101.227.99.22 +101.227.99.233 +121.46.247.247 +121.46.247.73 +121.46.247.74 +121.46.248.79 +124.14.20.219 +180.169.63.51 +180.169.63.52 +180.169.63.59 +180.169.63.60 +211.144.81.22 +211.144.81.24 +218.242.102.131 +218.242.102.137 +218.242.102.138 +218.242.102.139 +218.242.102.151 +218.78.185.251 +218.78.185.34 +218.78.185.35 +222.44.151.191 +222.44.151.25 +61.151.238.197 +61.151.238.222 +61.151.238.229 +117.174.21.130 +117.174.21.135 +117.174.21.238 +117.176.232.253 +117.176.232.83 +117.176.232.84 +118.118.216.129 +118.118.216.130 +118.118.216.131 +118.118.216.252 +118.118.216.46 +118.123.233.14 +118.123.233.15 +118.123.233.252 +118.123.233.254 +118.123.233.30 +118.123.233.31 +118.123.233.32 +118.123.237.174 +118.123.237.176 +118.123.237.245 +118.123.237.254 +118.123.237.27 +118.123.237.28 +118.123.237.29 +118.123.251.19 +118.123.251.247 +118.123.251.254 +118.123.251.73 +118.123.251.76 +118.123.251.77 +125.64.102.254 +125.64.102.69 +125.64.102.71 +125.66.85.108 +125.66.85.31 +125.66.85.30 +182.136.72.130 +182.136.72.131 +182.140.147.54 +182.140.218.23 +182.140.218.24 +182.140.218.25 +182.140.218.254 +182.140.218.26 +182.140.236.124 +182.140.236.57 +182.140.236.58 +183.222.97.163 +183.222.97.164 +183.222.97.165 +183.222.97.166 +183.222.97.246 +183.222.97.254 +202.98.156.253 +202.98.156.59 +202.98.156.60 +202.98.156.61 +211.162.189.192 +211.162.189.193 +211.162.189.194 +211.162.189.207 +211.162.189.223 +223.86.219.254 +223.86.219.65 +223.86.219.66 +60.255.143.93 +60.255.143.94 +60.255.143.95 +60.255.143.96 +61.157.124.252 +61.157.124.38 +61.157.124.40 +61.157.124.42 +61.157.124.47 +61.157.124.48 +61.188.191.254 +61.188.191.34 +61.188.191.81 +61.188.191.82 +61.188.191.83 +111.161.122.100 +111.161.122.128 +111.161.122.133 +111.161.122.134 +111.161.122.135 +111.161.122.137 +111.161.122.181 +111.161.122.240 +111.161.122.67 +111.161.22.15 +111.161.22.16 +111.161.22.17 +111.161.22.18 +111.161.22.19 +111.161.22.62 +125.39.1.134 +125.39.1.191 +42.81.144.179 +42.81.144.180 +42.81.144.191 +42.81.144.23 +42.81.144.31 +42.81.144.39 +42.81.144.53 +42.81.144.54 +42.81.144.55 +42.81.144.56 +42.81.144.77 +42.81.144.78 +42.81.144.79 +60.28.100.155 +60.28.100.156 +60.28.100.157 +60.28.100.158 +60.28.100.248 +117.180.229.254 +117.180.229.142 +117.145.179.22 +117.145.179.20 +117.145.179.19 +117.145.179.248 +106.57.180.253 +106.57.180.62 +106.57.180.63 +14.204.185.100 +14.204.185.101 +14.204.185.102 +14.204.185.123 +14.204.185.254 +182.242.50.245 +182.242.50.46 +14.204.185.91 +182.242.50.48 +220.165.142.137 +220.165.142.253 +220.165.142.9 +222.221.102.254 +222.221.102.39 +39.130.253.226 +222.221.102.40 +39.130.253.227 +39.130.253.253 +39.130.253.45 +39.130.253.46 +39.130.253.48 +39.130.253.52 +39.130.253.53 +101.69.104.20 +101.69.104.21 +101.69.104.29 +101.69.104.30 +101.69.104.63 +101.69.104.74 +101.69.146.234 +101.69.146.30 +101.69.146.31 +101.69.146.32 +101.69.146.33 +101.69.146.35 +101.69.146.34 +101.69.146.41 +111.0.23.138 +111.0.22.116 +111.0.23.139 +112.16.227.101 +112.16.227.102 +112.16.227.103 +112.16.227.104 +112.16.227.125 +112.16.227.254 +112.17.175.197 +112.17.27.254 +112.17.27.55 +112.17.53.253 +112.17.53.97 +112.17.53.98 +113.215.16.58 +115.223.24.254 +113.215.16.59 +115.223.24.80 +115.223.24.81 +115.223.24.82 +115.223.24.83 +115.223.7.123 +115.223.7.125 +115.223.7.124 +115.223.7.126 +115.223.7.127 +115.223.7.128 +115.223.7.173 +115.223.7.174 +115.223.7.175 +115.223.7.176 +115.223.7.248 +115.223.7.249 +117.148.128.68 +117.148.128.93 +117.148.128.96 +117.148.128.97 +117.148.128.98 +117.149.154.185 +117.149.154.186 +117.149.154.187 +117.149.154.188 +117.149.154.237 +117.149.154.250 +117.149.154.251 +117.149.155.148 +117.149.155.147 +117.149.155.49 +117.149.155.76 +122.224.186.221 +122.224.186.222 +122.224.186.224 +122.224.186.225 +122.224.186.226 +122.224.186.227 +122.224.186.252 +122.224.186.253 +122.225.28.159 +122.225.28.160 +122.225.28.161 +122.225.28.163 +122.225.28.251 +122.225.83.25 +122.225.83.28 +122.228.237.74 +122.228.237.75 +122.228.237.76 +122.228.239.233 +122.228.239.234 +122.228.239.235 +122.228.239.236 +122.228.239.238 +122.228.239.243 +122.228.239.244 +122.228.239.246 +122.228.24.103 +122.228.24.105 +122.228.24.106 +122.228.24.107 +122.228.24.114 +122.228.24.173 +122.228.6.197 +122.228.6.200 +122.228.6.201 +122.228.6.209 +122.228.6.217 +122.228.6.220 +122.228.6.218 +183.131.124.249 +183.131.124.38 +183.131.124.39 +183.131.124.40 +183.131.124.43 +183.131.124.58 +183.131.124.59 +183.131.124.60 +183.131.124.61 +183.131.124.62 +183.131.168.146 +183.131.168.147 +183.131.168.148 +183.131.168.187 +183.131.171.42 +183.131.171.47 +183.131.26.41 +183.131.26.42 +183.131.26.43 +183.131.26.44 +183.131.26.45 +183.131.26.46 +183.131.26.47 +183.131.26.5 +183.131.26.60 +183.134.12.26 +183.134.12.254 +183.134.12.27 +183.134.12.28 +183.134.42.153 +183.134.42.154 +183.134.42.155 +183.134.42.156 +183.134.42.157 +183.134.42.158 +183.134.42.159 +183.134.42.17 +183.134.42.18 +183.134.42.19 +183.134.42.190 +183.134.42.191 +183.134.42.20 +183.134.42.247 +183.134.53.153 +183.134.53.155 +183.134.53.156 +183.134.53.157 +183.134.53.158 +183.134.53.223 +183.134.53.252 +183.134.53.248 +183.146.22.135 +183.146.22.136 +183.146.22.137 +183.146.22.138 +183.146.22.143 +183.146.22.145 +183.146.22.146 +183.146.22.159 +183.146.22.171 +183.146.22.179 +36.25.241.249 +36.25.241.250 +36.25.241.39 +36.25.241.40 +36.25.241.41 +36.25.241.75 +36.25.241.76 +36.25.241.77 +113.207.0.17 +113.207.0.97 +113.207.0.98 +113.207.10.204 +113.207.10.218 +113.207.6.210 +113.207.6.211 +113.207.6.212 +113.207.6.213 +113.207.70.194 +113.207.70.207 +113.207.70.208 +113.207.72.102 +113.207.72.103 +113.207.70.209 +113.207.77.117 +113.207.77.118 +113.207.77.121 +113.207.77.247 +113.207.77.252 +113.207.79.17 +113.207.79.34 +113.207.79.42 +113.207.79.37 +113.207.81.126 +113.207.81.76 +113.207.81.77 +113.207.81.78 +113.207.81.81 +119.84.128.19 +119.84.128.21 +119.84.128.22 +119.84.128.254 +183.66.108.204 +183.66.108.205 +183.66.109.253 +183.66.109.254 +183.66.109.38 +183.66.109.44 +183.66.109.45 +183.66.109.50 +211.162.212.156 +211.162.212.210 +211.162.212.211 +211.162.212.212 +211.162.212.213 +211.162.212.246 +221.178.0.252 \ No newline at end of file diff --git a/src/12306/config/AutoSynchroTime.py b/src/12306/config/AutoSynchroTime.py new file mode 100644 index 0000000..4b41946 --- /dev/null +++ b/src/12306/config/AutoSynchroTime.py @@ -0,0 +1,39 @@ +# coding=utf-8 +import os +import platform + +import ntplib +import datetime + + +def autoSynchroTime(): + """ + 同步北京时间,执行时候,请务必用sudo,sudo,sudo 执行,否则会报权限错误,windows打开ide或者cmd请用管理员身份 + :return: + """ + c = ntplib.NTPClient() + + hosts = ['ntp1.aliyun.com', 'ntp2.aliyun.com', 'ntp3.aliyun.com', 'ntp4.aliyun.com', 'cn.pool.ntp.org'] + + print(u"正在同步时间,请耐心等待30秒左右,如果下面有错误发送,可以忽略!!") + print(u"系统当前时间{}".format(str(datetime.datetime.now())[:22])) + system = platform.system() + if system == "Windows": # windows 同步时间未测试过,参考地址:https://www.jianshu.com/p/92ec15da6cc3 + for host in hosts: + os.popen('w32tm /register') + os.popen('net start w32time') + os.popen('w32tm /config /manualpeerlist:"{}" /syncfromflags:manual /reliable:yes /update'.format(host)) + os.popen('ping -n 3 127.0.0.1 >nul') + sin = os.popen('w32tm /resync') + if sin is 0: + break + else: # mac同步地址,如果ntpdate未安装,brew install ntpdate linux 安装 yum install -y ntpdate + for host in hosts: + sin = os.popen('ntpdate {}'.format(host)) + if sin is 0: + break + print(u"同步后时间:{}".format(str(datetime.datetime.now())[:22])) + + +if __name__ == '__main__': + autoSynchroTime() \ No newline at end of file diff --git a/src/12306/config/TicketEnmu.py b/src/12306/config/TicketEnmu.py new file mode 100644 index 0000000..9e9f294 --- /dev/null +++ b/src/12306/config/TicketEnmu.py @@ -0,0 +1,41 @@ +# coding=utf-8 +from enum import Enum + + +class ticket(object): + QUERY_C = u"查询到有余票,尝试提交订单" + QUERY_IN_BLACK_LIST = u"该车次{} 正在被关小黑屋,跳过此车次" + + SUCCESS_CODE = 000000 + FAIL_CODE = 999999 + AUTO_SUBMIT_ORDER_REQUEST_C = u"提交订单成功" + AUTO_SUBMIT_ORDER_REQUEST_F = u"提交订单失败,重新刷票中" + AUTO_SUBMIT_NEED_CODE = u"需要验证码" + AUTO_SUBMIT_NOT_NEED_CODE = u"不需要验证码" + + TICKET_BLACK_LIST_TIME = 5 # 加入小黑屋的等待时间,默认5 min + + DTO_NOT_FOUND = u"未查找到常用联系人, 请查证后添加!!" + DTO_NOT_IN_LIST = u"联系人不在列表中,请查证后添加!!" + + QUEUE_TICKET_SHORT = u"当前余票数小于乘车人数,放弃订票" + QUEUE_TICKET_SUCCESS = u"排队成功, 当前余票还剩余: {0}张" + QUEUE_JOIN_BLACK = u"排队发现未知错误{0},将此列车 {1}加入小黑屋" + QUEUE_WARNING_MSG = u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋" + + OUT_NUM = 120 # 排队请求12306的次数 + WAIT_OUT_NUM = u"超出排队时间,自动放弃,正在重新刷票" + WAIT_ORDER_SUCCESS = u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!" + WAIT_AFTER_NATE_SUCCESS = u"候补订单已完成,请立即打开浏览器登录12306,访问‘候补订单’,在30分钟内完成支付!" + WAIT_ORDER_CONTINUE = u"排队等待时间预计还剩 {0} ms" + WAIT_ORDER_FAIL = u"排队等待失败,错误消息:{0}" + WAIT_ORDER_NUM = u"第{0}次排队中,请耐心等待" + WAIT_ORDER_SUB_FAIL = u"订单提交失败!,正在重新刷票" + + CANCEL_ORDER_SUCCESS = u"排队超时,已为您自动取消订单,订单编号: {0}" + CANCEL_ORDER_FAIL = u"排队超时,取消订单失败, 订单号{0}" + + REST_TIME = u"12306休息时间,本程序自动停止,明天早上6点将自动运行" + REST_TIME_PAST = u"休息时间已过,重新开启检票功能" + + LOGIN_SESSION_FAIL = u"用户检查失败:{0},可能未登录,可能session已经失效, 正在重新登录中" diff --git a/src/12306/config/__init__.py b/src/12306/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/config/configCommon.py b/src/12306/config/configCommon.py new file mode 100644 index 0000000..7faef5a --- /dev/null +++ b/src/12306/config/configCommon.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +import datetime +import os +import random +import sys +import time + +from myException.ticketConfigException import ticketConfigException + +rushRefreshMinTimeIntval = 2000 +rushRefreshMaxTimeIntval = 3600000 +rushRefreshTimeIntval = 100 +# 最早运行时间 +maxRunTime = 6 +# 程序停止时间 +maxRunStopTime = 23 +# 可售天数 +maxDate = 29 + +RS_SUC = 0 +RS_TIMEOUT = 1 +RS_JSON_ERROR = 2 +RS_OTHER_ERROR = 3 + +seat_conf = {'商务座': 32, + '一等座': 31, + '二等座': 30, + '特等座': 25, + '软卧': 23, + '硬卧': 28, + '软座': 24, + '硬座': 29, + '无座': 26, + '动卧': 33, + } +if sys.version_info.major == 2: + seat_conf_2 = dict([(v, k) for (k, v) in seat_conf.iteritems()]) +else: + seat_conf_2 = dict([(v, k) for (k, v) in seat_conf.items()]) + + +def getNowTimestamp(): + return time.time() + + +def decMakeDir(func): + def handleFunc(*args, **kwargs): + dirname = func(*args, **kwargs) + if not os.path.exists(dirname): + os.makedirs(dirname) + elif not os.path.isdir(dirname): + pass + + return dirname + + return func + + +def getWorkDir(): + return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# +# def fileOpen(path): +# """ +# 文件读取兼容2和3 +# :param path: 文件读取路径 +# :return: +# """ +# try: +# with open(path, "r", ) as f: +# return f +# except TypeError: +# with open(path, "r", ) as f: +# return f + + + +@decMakeDir +def getTmpDir(): + return os.path.join(getWorkDir(), "tmp") + + +@decMakeDir +def getLogDir(): + return os.path.join(getTmpDir(), "log") + + +@decMakeDir +def getCacheDir(): + return os.path.join(getTmpDir(), "cache") + + +@decMakeDir +def getVCodeDir(): + return os.path.join(getTmpDir(), "vcode") + + +def getVCodeImageFile(imageName): + return os.path.join(getVCodeDir(), imageName + ".jpg") + + +def getCacheFile(cacheType): + return os.path.join(getCacheDir(), cacheType + ".cache") + + +def checkSleepTime(session): + now = datetime.datetime.now() + if now.hour >= maxRunStopTime or now.hour < maxRunTime: + print(u"12306休息时间,本程序自动停止,明天早上六点将自动运行") + open_time = datetime.datetime(now.year, now.month, now.day, maxRunTime) + if open_time < now: + open_time += datetime.timedelta(1) + time.sleep((open_time - now).seconds + round(random.uniform(1, 10))) + session.call_login() + + +def checkDate(station_dates): + """ + 检查日期是否合法 + :param station_dates: + :return: + """ + today = datetime.datetime.now() + maxDay = (today + datetime.timedelta(maxDate)).strftime("%Y-%m-%d") + for station_date in station_dates[::-1]: + date = datetime.datetime.strftime(datetime.datetime.strptime(station_date, "%Y-%m-%d"), "%Y-%m-%d") + if date < today.strftime("%Y-%m-%d") or date > maxDay: + print(u"警告:当前时间配置有小于当前时间或者大于最大时间: {}, 已自动忽略".format(station_date)) + station_dates.remove(station_date) + if not station_dates: + print(u"当前日期设置无符合查询条件的,已被全部删除,请查证后添加!!!") + raise ticketConfigException(u"当前日期设置无符合查询条件的,已被全部删除,请查证后添加!!!") + else: + station_dates[station_dates.index(station_date)] = date + return station_dates \ No newline at end of file diff --git a/src/12306/config/emailConf.py b/src/12306/config/emailConf.py new file mode 100644 index 0000000..639873a --- /dev/null +++ b/src/12306/config/emailConf.py @@ -0,0 +1,47 @@ +# -*- coding: utf8 -*- +import socket +__author__ = 'MR.wen' +import TickerConfig +from email.header import Header +from email.mime.text import MIMEText +import smtplib + + +def sendEmail(msg): + """ + 邮件通知 + :param str: email content + :return: + """ + try: + if TickerConfig.EMAIL_CONF["IS_MAIL"]: + sender = TickerConfig.EMAIL_CONF["email"] + receiver = TickerConfig.EMAIL_CONF["notice_email_list"] + subject = '恭喜,您已订票成功' + username = TickerConfig.EMAIL_CONF["username"] + password = TickerConfig.EMAIL_CONF["password"] + host = TickerConfig.EMAIL_CONF["host"] + s = "{0}".format(msg) + + msg = MIMEText(s, 'plain', 'utf-8') # 中文需参数‘utf-8’,单字节字符不需要 + msg['Subject'] = Header(subject, 'utf-8') + msg['From'] = sender + msg['To'] = receiver + + try: + smtp = smtplib.SMTP_SSL(host) + smtp.connect(host) + except socket.error: + smtp = smtplib.SMTP() + smtp.connect(host) + smtp.connect(host) + smtp.login(username, password) + smtp.sendmail(sender, receiver.split(","), msg.as_string()) + smtp.quit() + print(u"邮件已通知, 请查收") + except Exception as e: + print(u"邮件配置有误{}".format(e)) + + +if __name__ == '__main__': + sendEmail(1) \ No newline at end of file diff --git a/src/12306/config/getCookie.py b/src/12306/config/getCookie.py new file mode 100644 index 0000000..fee16a4 --- /dev/null +++ b/src/12306/config/getCookie.py @@ -0,0 +1,195 @@ +import json +import random +import re +import time +import os +import TickerConfig +from config.urlConf import urls + + +def getDrvicesID(session): + """ + :return: + """ + print("cookie获取中") + if TickerConfig.COOKIE_TYPE is 1: + from selenium import webdriver + cookies = [] + # 解决放镜像里 DevToolsActivePort file doesn't exist的问题 + options = webdriver.ChromeOptions() + if os.name != 'nt' and TickerConfig.CHROME_CHROME_PATH: + options = webdriver.ChromeOptions() + options.binary_location = TickerConfig.CHROME_CHROME_PATH + options.add_argument( + '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36') + options.add_argument("--no-sandbox") + options.add_argument("--headless") + driver = webdriver.Chrome(executable_path=TickerConfig.CHROME_PATH,chrome_options=options) + driver.get("https://www.12306.cn/index/index.html") + time.sleep(10) + for c in driver.get_cookies(): + cookie = dict() + print() + if c.get("name") == "RAIL_DEVICEID" or c.get("name") == "RAIL_EXPIRATION": + cookie[c.get("name")] = c.get("value") + cookies.append(cookie) + print(f"获取cookie: {cookies}") + if cookies: + session.httpClint.set_cookies(cookies) + session.cookies = cookies + print("cookie获取完成") + elif TickerConfig.COOKIE_TYPE is 2: + request_device_id(session) + elif TickerConfig.COOKIE_TYPE is 3: + # RAIL_DEVICEID,RAIL_EXPIRATION的值打开12306官网可以获取headers-Cookies + if not TickerConfig.RAIL_DEVICEID or not TickerConfig.RAIL_EXPIRATION: + print("警告!!: RAIL_DEVICEID,RAIL_EXPIRATION的值为空,请手动打开12306官网可以获取headers-Cookies中的RAIL_DEVICEID,RAIL_EXPIRATION,填入配置文件中") + cookies = [{ + "RAIL_DEVICEID": TickerConfig.RAIL_DEVICEID, + "RAIL_EXPIRATION": TickerConfig.RAIL_EXPIRATION, + }] + session.httpClint.set_cookies(cookies) + session.cookies = cookies + + +def request_device_id(session): + """ + 获取加密后的浏览器特征 ID + :return: + """ + params = {"algID": request_alg_id(session), "timestamp": int(time.time() * 1000)} + params = dict(params, **_get_hash_code_params()) + response = session.httpClint.send(urls.get("getDevicesId"), params=params) + if response.find('callbackFunction') >= 0: + result = response[18:-2] + try: + result = json.loads(result) + session.httpClint.set_cookies([{ + 'RAIL_EXPIRATION': result.get('exp'), + 'RAIL_DEVICEID': result.get('dfp'), + }]) + session.cookies = [{ + 'RAIL_EXPIRATION': result.get('exp'), + 'RAIL_DEVICEID': result.get('dfp'), + }] + except: + return False + + +def request_alg_id(session): + response = session.httpClint.send(urls.get("GetJS")) + result = re.search(r'algID\\x3d(.*?)\\x26', response) + try: + return result.group(1) + except (IndexError, AttributeError) as e: + pass + return "" + + +def _get_hash_code_params(): + from collections import OrderedDict + data = { + 'adblock': '0', + 'browserLanguage': 'en-US', + 'cookieEnabled': '1', + 'custID': '133', + 'doNotTrack': 'unknown', + 'flashVersion': '0', + 'javaEnabled': '0', + 'jsFonts': 'c227b88b01f5c513710d4b9f16a5ce52', + 'localCode': '3232236206', + 'mimeTypes': '52d67b2a5aa5e031084733d5006cc664', + 'os': 'MacIntel', + 'platform': 'WEB', + 'plugins': 'd22ca0b81584fbea62237b14bd04c866', + 'scrAvailSize': str(random.randint(500, 1000)) + 'x1920', + 'srcScreenSize': '24xx1080x1920', + 'storeDb': 'i1l1o1s1', + 'timeZone': '-8', + 'touchSupport': '99115dfb07133750ba677d055874de87', + 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.' + str( + random.randint( + 5000, 7000)) + '.0 Safari/537.36', + 'webSmartID': 'f4e3b7b14cc647e30a6267028ad54c56', + } + data_trans = { + 'browserVersion': 'd435', + 'touchSupport': 'wNLf', + 'systemLanguage': 'e6OK', + 'scrWidth': 'ssI5', + 'openDatabase': 'V8vl', + 'scrAvailSize': 'TeRS', + 'hasLiedResolution': '3neK', + 'hasLiedOs': 'ci5c', + 'timeZone': 'q5aJ', + 'userAgent': '0aew', + 'userLanguage': 'hLzX', + 'jsFonts': 'EOQP', + 'scrAvailHeight': '88tV', + 'browserName': '-UVA', + 'cookieCode': 'VySQ', + 'online': '9vyE', + 'scrAvailWidth': 'E-lJ', + 'flashVersion': 'dzuS', + 'scrDeviceXDPI': '3jCe', + 'srcScreenSize': 'tOHY', + 'storeDb': 'Fvje', + 'doNotTrack': 'VEek', + 'mimeTypes': 'jp76', + 'sessionStorage': 'HVia', + 'cookieEnabled': 'VPIf', + 'os': 'hAqN', + 'hasLiedLanguages': 'j5po', + 'hasLiedBrowser': '2xC5', + 'webSmartID': 'E3gR', + 'appcodeName': 'qT7b', + 'javaEnabled': 'yD16', + 'plugins': 'ks0Q', + 'appMinorVersion': 'qBVW', + 'cpuClass': 'Md7A', + 'indexedDb': '3sw-', + 'adblock': 'FMQw', + 'localCode': 'lEnu', + 'browserLanguage': 'q4f3', + 'scrHeight': '5Jwy', + 'localStorage': 'XM7l', + 'historyList': 'kU5z', + 'scrColorDepth': "qmyu" + } + data = OrderedDict(data) + d = '' + params = {} + for key, item in data.items(): + d += key + item + key = data_trans[key] if key in data_trans else key + params[key] = item + d_len = len(d) + d_f = int(d_len / 3) if d_len % 3 == 0 else int(d_len / 3) + 1 + if d_len >= 3: + d = d[d_f:2 * d_f] + d[2 * d_f:d_len] + d[0: d_f] + d_len = len(d) + d_f = int(d_len / 3) if d_len % 3 == 0 else int(d_len / 3) + 1 + if d_len >= 3: + d = d[2 * d_f:d_len] + d[0: d_f] + d[1 * d_f: 2 * d_f] + + d = _encode_data_str_v2(d) + d = _encode_data_str_v2(d) + d = _encode_data_str_v2(d) + data_str = _encode_string(d) + params['hashCode'] = data_str + return params + + +def _encode_data_str_v2(d): + b = len(d) + if b % 2 == 0: + return d[b // 2: b] + d[0:b // 2] + else: + return d[b // 2 + 1:b] + d[b // 2] + d[0:b // 2] + + +def _encode_string(str): + import hashlib + import base64 + result = base64.b64encode(hashlib.sha256(str.encode()).digest()).decode() + return result.replace('+', '-').replace('/', '_').replace('=', '') diff --git a/src/12306/config/logger.py b/src/12306/config/logger.py new file mode 100644 index 0000000..7687876 --- /dev/null +++ b/src/12306/config/logger.py @@ -0,0 +1,61 @@ +#coding: utf-8 + +import os +import time +import logging + +from config import configCommon + +logger = None +loggerHandler = None +dateStr = '' #默认拥有日期后缀 +suffix = '' #除了日期外的后缀 + +def setSuffix(s): + global suffix + suffix = s + +def getTodayDateStr(): + return time.strftime("%Y-%m-%d", time.localtime(configCommon.getNowTimestamp())) + +def setDateStr(s): + global dateStr + dateStr = s + +def isAnotherDay(s): + global dateStr + return dateStr != s + +def getLogFile(): + global dateStr, suffix + rtn = os.path.join(configCommon.getLogDir(), dateStr) + if suffix: + rtn += "_" + suffix + return rtn + ".log" + +def log(msg, func = "info"): + global logger + if not logger: + logger = logging.getLogger() + logger.setLevel(logging.INFO) + + todayStr = getTodayDateStr() + if isAnotherDay(todayStr): + setDateStr(todayStr) + logger.removeHandler(loggerHandler) + + fh = logging.FileHandler(getLogFile()) + fm = logging.Formatter(u'[%(asctime)s][%(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)') + fh.setFormatter(fm) + + logger.addHandler(fh) + + levels = { + "debug": logger.debug, + "info": logger.info, + "warning": logger.warning, + "error": logger.error, + "critical": logger.critical + } + + levels[func](msg) \ No newline at end of file diff --git a/src/12306/config/pushbearConf.py b/src/12306/config/pushbearConf.py new file mode 100644 index 0000000..01e1073 --- /dev/null +++ b/src/12306/config/pushbearConf.py @@ -0,0 +1,36 @@ +# -*- coding: utf8 -*- +import TickerConfig +from config.urlConf import urls +from myUrllib.httpUtils import HTTPClient + +PUSH_BEAR_API_PATH = "https://pushbear.ftqq.com/sub" + + +def sendPushBear(msg): + """ + pushBear微信通知 + :param str: 通知内容 content + :return: + """ + if TickerConfig.PUSHBEAR_CONF["is_pushbear"] and TickerConfig.PUSHBEAR_CONF["send_key"].strip() != "": + try: + sendPushBearUrls = urls.get("Pushbear") + data = { + "sendkey": TickerConfig.PUSHBEAR_CONF["send_key"].strip(), + "text": "易行购票成功通知", + "desp": msg + } + httpClint = HTTPClient(0) + sendPushBeaRsp = httpClint.send(sendPushBearUrls, data=data) + if sendPushBeaRsp.get("code") is 0: + print(u"已下发 pushbear 微信通知, 请查收") + else: + print(sendPushBeaRsp) + except Exception as e: + print(u"pushbear 配置有误 {}".format(e)) + else: + pass + + +if __name__ == '__main__': + sendPushBear(1) diff --git a/src/12306/config/serverchanConf.py b/src/12306/config/serverchanConf.py new file mode 100644 index 0000000..f9078fd --- /dev/null +++ b/src/12306/config/serverchanConf.py @@ -0,0 +1,36 @@ +# -*- coding: utf8 -*- +import TickerConfig +from config.urlConf import urls +from myUrllib.httpUtils import HTTPClient + +PUSH_SERVER_CHAN_PATH = "https://sc.ftqq.com" + + +def sendServerChan(msg): + """ + pushBear微信通知 + :param str: 通知内容 content + :return: + """ + if ( + TickerConfig.SERVER_CHAN_CONF["is_server_chan"] + and TickerConfig.SERVER_CHAN_CONF["secret"].strip() != "" + ): + try: + secret = TickerConfig.SERVER_CHAN_CONF["secret"].strip() + sendServerChanUrls = urls.get("ServerChan") + sendServerChanUrls["req_url"] += f'{secret}.send' + + params = {"text": "易行购票成功通知", "desp": msg} + httpClint = HTTPClient(0) + sendServerChanRsp = httpClint.send(sendServerChanUrls, params=params) + if sendServerChanRsp.get("errno") == 0: + print(u"已下发 Server酱 微信通知, 请查收") + else: + print(sendServerChanRsp) + except Exception as e: + print(u"Server酱 配置有误 {}".format(e)) + + +if __name__ == "__main__": + sendServerChan(1) diff --git a/src/12306/config/urlConf.py b/src/12306/config/urlConf.py new file mode 100644 index 0000000..d74398e --- /dev/null +++ b/src/12306/config/urlConf.py @@ -0,0 +1,582 @@ +# coding=utf-8 +import random +import TickerConfig +import time + +urls = { + "auth": { # 登录接口 + "req_url": "/passport/web/auth/uamtk", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": True, + "is_json": True, + "is_cdn": True, + }, + "uamtk-static": { # 登录接口 + "req_url": "/passport/web/auth/uamtk-static", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 3, + "s_time": 0.1, + "is_logger": True, + "is_json": True, + "is_cdn": True, + }, + "login": { # 登录接口 + "req_url": "/passport/web/login", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.5, + "is_logger": True, + "is_cdn": True, + "is_json": True, + + }, + "left_ticket_init": { # 登录接口 + "req_url": "/otn/leftTicket/init", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + + }, + "getCodeImg": { # 登录验证码 + "req_url": "/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&{0}", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": False, + "is_json": False, + "is_cdn": True, + "not_decode": True, + }, + "getCodeImg1": { # 登录验证码 + "req_url": "/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&{0}&callback=jQuery19108016482864806321_1554298927290&_=1554298927293", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": False, + }, + "codeCheck": { # 验证码校验 + "req_url": "/passport/captcha/captcha-check", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": False, + }, + "codeCheck1": { # 验证码校验 + "req_url": "/passport/captcha/captcha-check?callback=jQuery19108016482864806321_1554298927290&answer={0}&rand=sjrand&login_site=E&_={1}", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/resources/login.html", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": False, + }, + "loginInit": { # 登录页面 + "req_url": "/otn/login/init", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/index/init", + "Host": "kyfw.12306.cn", + "re_try": 1, + "re_time": 1, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "loginInitCdn": { # 登录页面 + "req_url": "/otn/login/init", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/index/init", + "Host": "kyfw.12306.cn", + "re_try": 1, + "re_time": 1, + "s_time": 0.1, + "is_logger": False, + "is_test_cdn": True, + "is_cdn": True, + "is_json": False, + }, + "loginInitCdn1": { # 登录页面 + "req_url": "/otn/resources/login.html", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/view/index.html", + "Host": "kyfw.12306.cn", + "re_try": 1, + "re_time": 1, + "s_time": 0.1, + "is_logger": False, + "is_test_cdn": False, + "is_cdn": True, + "is_json": False, + }, + "getDevicesId": { # 获取用户信息 + "req_url": "/otn/HttpZF/logdevice", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 1, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": False, + }, + "getUserInfo": { # 获取用户信息 + "req_url": "/otn/index/initMy12306", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 1, + "s_time": 0.01, + "is_cdn": True, + "is_logger": False, + "is_json": False, + }, + "userLogin": { # 用户登录 + "req_url": "/otn/login/userLogin", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "uamauthclient": { # 登录 + "req_url": "/otn/uamauthclient", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 1, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "initdc_url": { # 生成订单页面 + "req_url": "/otn/confirmPassenger/initDc", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.1, + "s_time": 1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "GetJS": { # 订单页面js + "req_url": "/otn/HttpZF/GetJS", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.1, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "odxmfwg": { # 订单页面js + "req_url": "/otn/dynamicJs/odxmfwg", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.1, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "get_passengerDTOs": { # 获取乘车人 + "req_url": "/otn/confirmPassenger/getPassengerDTOs", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.1, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "select_url": { # 查询余票 + "req_url": "/otn/{3}?leftTicketDTO.train_date={0}&leftTicketDTO.from_station={1}&leftTicketDTO.to_station={2}&purpose_codes=ADULT", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 1, + "re_time": 0.01, + "s_time": 0.01, + "is_logger": False, + "is_json": True, + "is_cdn": True, + }, + "check_user_url": { # 检查用户登录 + "req_url": "/otn/login/checkUser", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 1, + "re_time": 1, + "s_time": 1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "submit_station_url": { # 提交订单 + "req_url": "/otn/leftTicket/submitOrderRequest", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "checkOrderInfoUrl": { # 检查订单信息规范 + "req_url": "/otn/confirmPassenger/checkOrderInfo", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "getQueueCountUrl": { # 剩余余票数 + "req_url": "/otn/confirmPassenger/getQueueCount", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "checkQueueOrderUrl": { # 订单队列排队 + "req_url": "/otn/confirmPassenger/confirmSingleForQueue", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "checkRandCodeAnsyn": { # 暂时没用到 + "req_url": "/otn/passcodeNew/checkRandCodeAnsyn", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "codeImgByOrder": { # 订单页面验证码 + "req_url": "/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp&{}", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "queryOrderWaitTimeUrl": { # 订单等待页面 + "req_url": "/otn/confirmPassenger/queryOrderWaitTime?random={0}&tourFlag=dc&_json_att=", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "queryMyOrderNoCompleteUrl": { # 订单查询页面 + "req_url": "/otn/queryOrder/queryMyOrderNoComplete", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "initNoCompleteUrl": { # 获取订单列表 + "req_url": "/otn/queryOrder/initNoComplete", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": False, + "is_cdn": True, + "is_json": False, + }, + "cancelNoCompleteMyOrder": { # 取消订单 + "req_url": "/otn/queryOrder/cancelNoCompleteMyOrder", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "autoSubmitOrderRequest": { # 快速自动提交订单 + "req_url": "/otn/confirmPassenger/autoSubmitOrderRequest", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "getQueueCountAsync": { # 快速获取订单数据 + "req_url": "/otn/confirmPassenger/getQueueCountAsync", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "Content-Type": 1, + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "confirmSingleForQueueAsys": { # 快速订单排队 + "req_url": "/otn/confirmPassenger/confirmSingleForQueueAsys", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Content-Type": 1, + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_cdn": True, + "is_json": True, + }, + "Pushbear": { # push通知 + "req_url": "/sub", + "req_type": "post", + "Referer": "", + "Content-Type": 1, + "Host": "pushbear.ftqq.com", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": False, + "is_json": True, + }, + "ServerChan": { # Server酱 push通知 + "req_url": "/", + "req_type": "get", + "Referer": "", + "Content-Type": 1, + "Host": "sc.ftqq.com", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.1, + "is_logger": True, + "is_json": True, + }, + "loginHtml": { # 登录接口2 + "req_url": "/otn/resources/login.html", + "req_type": "get", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.3, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "loginConf": { # 登录接口2 + "req_url": "/otn/login/conf", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.3, + "s_time": 0.1, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "loginAysnSuggest": { # 登录接口2 + "req_url": "/otn/login/loginAysnSuggest", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.3, + "is_cdn": True, + "s_time": 0.1, + "is_logger": True, + "is_json": True, + }, + + + + # 候补订单接口 + + "chechFace": { # 人脸识别 + "req_url": "/otn/afterNate/chechFace", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "getSuccessRate": { # 成功信息 + "req_url": "/otn/afterNate/getSuccessRate", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "SubmitOrderRequestRsp": { # 提交候补订单准备 + "req_url": "/otn/afterNate/submitOrderRequest", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "confirmHB": { # 设置订单信息 + "req_url": "/otn/afterNate/confirmHB", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "queryQueue": { # 排队 + "req_url": "/otn/afterNate/queryQueue", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + "passengerInitApi": { # 排队 + "req_url": "/otn/afterNate/passengerInitApi", + "req_type": "post", + "Referer": "https://kyfw.12306.cn/otn/leftTicket/init", + "Host": "kyfw.12306.cn", + "re_try": 10, + "re_time": 0.01, + "s_time": 0.01, + "is_cdn": True, + "is_logger": True, + "is_json": True, + }, + + "autoVerifyImage": { # 云打码接口 + "req_url": TickerConfig.REQ_URL, + "req_type": "post", + "Referer": "", + "Host": TickerConfig.HOST, + "re_try": 6, + "re_time": 10, + "s_time": 0.001, + "is_logger": True, + "is_json": True, + "httpType": TickerConfig.HTTP_TYPE + }, +} \ No newline at end of file diff --git a/src/12306/docker-compose.yml b/src/12306/docker-compose.yml new file mode 100644 index 0000000..502059c --- /dev/null +++ b/src/12306/docker-compose.yml @@ -0,0 +1,32 @@ +version: "3" + +services: + #抢票服务 + ticket: + build: + context: . + dockerfile: ./Dockerfile37 + image: ticket:v1.2.004 + environment: + - PYTHONUNBUFFERED=1 + - CAPTCHALOCAL=1 + container_name: ticket + depends_on: + - captcha + networks: + - 12306network + restart: on-failure + #打码服务器 + captcha: + image: yinaoxiong/12306_code_server:amd64 #请根据需要修改image + environment: + - WORKERS=1 #gunicorn works 默认为1可以根据服务器配置自行调整 + - PYTHONUNBUFFERED=1 + container_name: captcha + networks: + - 12306network + restart: unless-stopped +networks: + 12306network: + driver: bridge + diff --git a/src/12306/docker_install_centos.sh b/src/12306/docker_install_centos.sh new file mode 100644 index 0000000..c43814e --- /dev/null +++ b/src/12306/docker_install_centos.sh @@ -0,0 +1,45 @@ +#!/bin/bash +#author: MonsterTan +#date: 2019-01-15 +#this is a script that can install automatically docker software by centos7 + + + +function checkSudo (){ + if [ $UID -ne 0 ];then + echo -e 'it must be root!' + exit 1 + fi +} + +checkSudo + +## something required system utils +yum install -y yum-utils device-mapper-persistent-data lvm2 + + +## add repo source info +sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo + + +sudo yum mackecache fast +sudo yum -y install docker-ce +sudo systemctl start docker + + +str=successed! +if [ $? -eq 0 ];then + echo -e "\033[32msuccessed!\033[0m" +else + echo -e "\033[31msomething wrong, please check!\033[0m" +fi + +echo -e "\033[31mstart to install docker-compose\033[0m" + +result=`ls /usr/bin/ | grep ^pip$` +if [ ${#result} -eq 0 ];then + echo -e "\033[31mpip must be necessary, it should be installed firstly\033[0m" +fi + +sudo pip install docker-compose + diff --git a/src/12306/filter_cdn_list b/src/12306/filter_cdn_list new file mode 100644 index 0000000..5deddfa --- /dev/null +++ b/src/12306/filter_cdn_list @@ -0,0 +1,559 @@ +111.161.122.240 +112.90.135.96 +60.9.0.19 +61.162.100.102 +222.186.141.146 +221.235.187.129 +58.221.78.231 +113.16.212.251 +112.47.27.131 +112.123.33.18 +183.134.42.18 +116.77.75.133 +112.90.135.97 +58.221.78.42 +61.162.100.103 +111.161.122.67 +60.9.0.20 +113.16.212.48 +112.47.56.174 +112.28.196.75 +183.134.42.19 +116.77.75.137 +112.90.135.98 +113.16.212.49 +36.250.248.220 +60.9.0.21 +116.199.127.56 +221.235.187.130 +112.47.27.172 +112.90.135.99 +183.134.42.190 +60.9.0.22 +222.186.141.165 +116.77.75.138 +36.102.230.136 +112.47.56.117 +183.134.42.191 +60.9.0.23 +116.77.75.145 +36.102.230.137 +222.186.141.166 +58.221.78.46 +61.162.100.107 +116.77.75.144 +113.207.77.252 +60.9.0.252 +222.186.141.178 +183.134.42.20 +61.167.54.55 +58.221.78.47 +221.180.208.54 +116.77.75.169 +61.162.100.252 +222.186.141.186 +60.9.0.254 +113.207.79.17 +183.134.42.247 +61.167.54.57 +111.161.22.17 +116.77.75.146 +58.221.78.48 +61.162.100.41 +111.6.176.208 +113.207.79.34 +36.250.248.222 +36.102.230.19 +183.134.53.153 +116.77.75.147 +61.162.100.44 +111.6.176.209 +113.207.79.42 +183.134.53.155 +116.77.75.170 +36.102.230.20 +120.221.64.161 +222.218.87.252 +111.6.176.248 +113.207.79.37 +120.221.64.169 +112.47.56.118 +111.6.176.25 +113.194.59.80 +124.236.28.100 +113.207.81.126 +111.6.176.94 +111.6.176.95 +113.194.59.199 +221.235.187.220 +124.236.28.252 +221.235.187.244 +111.6.176.97 +124.236.28.67 +113.194.59.81 +120.221.64.53 +36.250.248.252 +120.221.64.54 +124.236.28.247 +36.250.248.254 +120.221.64.55 +124.236.28.69 +116.77.75.183 +36.250.248.27 +221.235.187.66 +183.134.53.223 +124.236.28.68 +113.207.81.78 +58.20.179.253 +27.195.145.121 +221.235.187.90 +113.207.81.81 +27.195.145.123 +221.235.187.98 +123.128.14.254 +183.134.53.248 +111.161.22.62 +123.128.14.69 +124.236.28.93 +117.169.93.249 +183.146.22.135 +125.39.1.134 +36.102.230.254 +124.236.28.92 +117.169.93.85 +27.195.145.249 +125.39.1.191 +124.236.28.94 +42.81.144.179 +222.218.87.28 +27.195.145.52 +124.236.28.95 +36.250.248.56 +222.218.87.29 +42.81.144.180 +27.195.145.62 +36.159.115.250 +36.159.115.88 +36.159.115.89 +183.146.22.137 +110.242.21.24 +124.236.28.98 +117.169.93.86 +123.128.14.70 +110.242.21.23 +124.236.28.99 +117.23.2.252 +123.128.14.72 +112.28.196.54 +110.242.21.254 +117.149.154.185 +58.20.179.74 +150.138.111.251 +117.23.2.28 +110.242.21.243 +117.149.154.186 +58.20.179.73 +150.138.111.31 +110.242.21.41 +117.23.2.29 +111.47.220.251 +150.138.111.32 +110.242.21.71 +106.41.0.37 +111.47.220.66 +110.242.21.70 +150.138.111.33 +111.47.220.67 +106.41.0.44 +150.138.167.234 +150.138.167.50 +106.41.0.45 +222.186.145.51 +150.138.167.52 +111.62.194.30 +106.41.0.46 +122.228.237.248 +42.81.144.31 +150.138.169.120 +222.186.145.54 +59.56.30.51 +106.41.0.47 +42.81.144.39 +111.62.194.31 +222.44.151.24 +150.138.169.121 +112.28.196.251 +106.41.0.61 +111.62.194.254 +123.138.157.85 +106.120.178.19 +150.138.167.51 +150.138.169.123 +112.28.196.249 +106.41.0.62 +120.253.100.20 +114.112.172.58 +123.138.157.122 +150.138.169.124 +183.146.22.145 +112.28.196.53 +120.253.100.21 +222.44.151.191 +183.146.22.146 +125.77.147.254 +112.28.196.74 +120.253.100.22 +222.44.151.25 +222.186.145.52 +120.253.100.23 +61.151.238.197 +120.253.100.30 +61.151.238.222 +61.151.238.229 +117.149.155.148 +117.149.155.147 +183.146.22.171 +150.138.169.238 +60.210.23.26 +125.77.147.68 +221.235.187.119 +125.77.147.69 +115.157.63.19 +117.149.155.76 +115.157.63.49 +122.224.186.221 +183.201.225.249 +119.52.120.138 +60.28.100.155 +125.77.147.80 +122.70.142.148 +122.224.186.222 +119.52.120.139 +60.28.100.156 +122.70.142.147 +125.77.147.82 +122.224.186.225 +60.28.100.157 +119.52.120.140 +125.77.147.88 +114.112.172.57 +122.224.186.226 +60.28.100.158 +150.138.214.84 +119.52.120.144 +58.216.21.250 +60.28.100.248 +119.52.120.145 +150.138.214.124 +60.210.23.116 +183.66.109.254 +117.180.229.254 +150.138.214.85 +119.52.120.146 +61.147.226.46 +115.157.63.50 +122.224.186.253 +58.216.22.17 +150.138.214.86 +222.186.145.53 +117.180.229.142 +58.216.22.20 +183.222.97.164 +61.147.226.48 +58.216.22.22 +183.222.97.165 +122.224.186.223 +183.66.109.44 +58.216.22.56 +183.222.97.166 +60.210.23.29 +221.235.187.67 +183.66.109.45 +115.157.63.51 +183.222.97.254 +183.146.22.142 +183.146.22.139 +120.226.55.144 +221.235.187.121 +153.99.235.112 +120.226.55.151 +120.226.55.254 +112.240.60.213 +36.25.241.75 +122.225.83.25 +153.99.235.91 +112.240.60.214 +122.225.83.28 +115.157.63.52 +36.25.241.76 +121.22.247.202 +114.112.172.59 +122.228.237.74 +36.25.241.77 +112.240.60.215 +121.22.247.204 +223.111.18.161 +122.228.237.75 +112.240.60.216 +121.22.247.254 +218.26.75.149 +223.111.18.162 +122.228.237.76 +112.240.60.217 +115.157.63.62 +218.26.75.150 +223.111.18.163 +122.225.83.26 +122.228.239.233 +112.240.60.222 +223.111.18.217 +218.26.75.151 +222.186.145.251 +122.228.239.234 +112.240.60.236 +218.26.75.152 +116.207.132.183 +122.228.239.235 +61.147.227.53 +159.226.225.149 +218.26.75.153 +116.207.132.184 +122.228.239.236 +116.207.132.253 +218.26.75.206 +113.207.10.204 +122.228.239.238 +218.26.75.236 +113.207.10.218 +122.228.239.243 +122.228.239.244 +122.228.239.246 +139.209.49.140 +183.131.124.38 +159.226.225.154 +139.209.49.138 +121.22.247.203 +139.209.49.144 +123.53.139.253 +139.209.49.151 +125.74.58.134 +139.209.49.152 +123.53.139.36 +125.74.58.135 +125.74.58.136 +139.209.49.153 +123.184.108.251 +210.38.3.23 +183.131.124.40 +123.184.108.60 +123.184.108.61 +210.38.3.24 +159.226.225.139 +183.131.124.58 +125.74.58.254 +210.38.3.42 +159.226.225.140 +61.54.7.158 +124.95.148.254 +183.131.124.59 +61.54.7.174 +210.38.3.49 +124.95.148.30 +101.69.146.234 +210.38.3.50 +61.54.7.179 +124.95.148.29 +14.204.185.100 +210.38.3.60 +61.54.7.243 +60.220.196.220 +124.95.148.31 +14.204.185.101 +60.220.196.221 +59.83.232.18 +14.204.185.102 +59.83.232.50 +61.147.210.193 +122.70.142.252 +14.204.185.123 +61.147.210.195 +14.204.185.254 +223.111.198.252 +61.147.226.185 +101.69.146.33 +223.111.198.65 +113.207.70.194 +61.147.210.242 +113.207.70.207 +101.69.146.35 +60.210.23.23 +61.147.226.47 +113.207.70.208 +101.69.146.34 +60.210.23.25 +61.147.226.49 +183.131.168.148 +60.210.23.27 +61.147.227.102 +113.207.72.102 +60.213.21.117 +58.220.71.253 +61.147.227.126 +58.220.71.51 +60.213.21.118 +14.204.185.91 +58.220.71.52 +113.207.70.209 +60.213.21.156 +113.207.77.117 +60.213.21.214 +60.220.196.250 +58.220.71.62 +116.199.127.50 +60.213.21.244 +58.220.71.63 +118.123.233.254 +116.199.127.54 +218.29.198.43 +58.220.71.64 +60.213.21.243 +118.123.233.30 +218.29.198.62 +116.77.73.164 +103.254.189.230 +58.220.71.65 +60.213.21.245 +118.123.233.31 +223.86.219.254 +183.214.132.120 +60.213.21.252 +223.86.219.65 +183.214.132.16 +116.199.127.55 +223.86.219.66 +183.214.132.17 +60.255.143.93 +61.149.9.150 +60.255.143.94 +60.255.143.95 +60.255.143.96 +36.250.233.185 +106.40.140.224 +36.250.233.208 +61.147.228.201 +36.250.233.209 +183.214.140.204 +123.53.139.37 +222.24.122.86 +61.147.228.60 +36.250.233.210 +106.40.140.254 +183.214.140.238 +36.250.233.214 +36.250.233.228 +58.221.78.186 +36.250.248.218 +218.12.228.246 +112.90.135.244 +222.24.122.89 +36.250.248.217 +221.235.187.106 +218.12.228.38 +36.250.233.254 +112.47.20.250 +218.12.228.39 +112.90.135.92 +117.27.245.227 +112.90.135.93 +117.27.245.254 +117.27.245.52 +112.90.135.94 +117.27.245.97 +112.90.135.95 +117.27.245.54 +218.60.185.251 +113.5.80.33 +125.77.130.247 +218.60.185.46 +125.77.130.251 +118.203.202.206 +118.203.202.207 +218.60.185.47 +218.60.185.48 +118.203.202.208 +118.203.202.209 +118.203.202.222 +221.180.192.100 +125.77.130.46 +125.77.130.47 +112.47.20.68 +125.77.130.48 +163.177.132.27 +112.47.27.132 +125.77.130.49 +112.47.20.89 +61.147.228.89 +112.47.20.79 +106.120.178.253 +221.180.192.254 +221.230.141.170 +221.180.192.61 +106.120.178.20 +163.177.132.30 +183.216.176.74 +221.230.141.172 +183.216.176.75 +221.230.141.174 +110.19.204.219 +110.19.204.220 +219.138.27.108 +110.19.204.221 +219.138.27.249 +103.254.189.229 +106.120.178.22 +219.138.27.30 +219.138.27.31 +113.16.208.251 +222.186.141.132 +113.16.208.77 +113.16.208.78 +222.186.141.141 +110.19.204.254 +222.186.141.142 +221.180.208.252 +222.186.141.143 +117.161.19.126 +221.180.208.46 +222.186.141.145 +60.9.0.18 +117.161.19.19 +221.180.208.47 +117.161.19.22 +113.142.80.223 +183.134.42.153 +183.134.42.154 +183.134.42.155 +115.223.24.254 +183.134.42.156 +111.161.122.100 +183.134.42.157 +61.136.167.17 +183.134.42.158 +61.136.167.18 +183.134.42.159 +113.142.80.69 +183.134.42.17 +113.142.80.71 +61.136.167.19 +113.142.80.72 +115.223.24.80 +111.161.122.133 +115.223.24.81 +111.161.122.134 +115.223.24.82 +111.161.122.135 +114.112.172.56 +222.74.113.196 +222.74.113.219 +61.167.54.236 +61.167.54.242 diff --git a/src/12306/init/__init__.py b/src/12306/init/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/init/login.py b/src/12306/init/login.py new file mode 100644 index 0000000..8576f6a --- /dev/null +++ b/src/12306/init/login.py @@ -0,0 +1,136 @@ +# -*- coding=utf-8 -*- +import copy +import time +from collections import OrderedDict +from time import sleep +import TickerConfig +from inter.GetPassCodeNewOrderAndLogin import getPassCodeNewOrderAndLogin1 +from inter.GetRandCode import getRandCode +from inter.LoginAysnSuggest import loginAysnSuggest +from inter.LoginConf import loginConf +from myException.UserPasswordException import UserPasswordException + + +class GoLogin: + def __init__(self, session, is_auto_code, auto_code_type): + self.session = session + self.randCode = "" + self.is_auto_code = is_auto_code + self.auto_code_type = auto_code_type + + def auth(self): + """ + :return: + """ + self.session.httpClint.send(self.session.urls["loginInitCdn1"]) + uamtkStaticUrl = self.session.urls["uamtk-static"] + uamtkStaticData = {"appid": "otn"} + return self.session.httpClint.send(uamtkStaticUrl, uamtkStaticData) + + def codeCheck(self): + """ + 验证码校验 + :return: + """ + codeCheckUrl = copy.deepcopy(self.session.urls["codeCheck1"]) + codeCheckUrl["req_url"] = codeCheckUrl["req_url"].format(self.randCode, int(time.time() * 1000)) + fresult = self.session.httpClint.send(codeCheckUrl) + if not isinstance(fresult, str): + print("登录失败") + return + fresult = eval(fresult.split("(")[1].split(")")[0]) + if "result_code" in fresult and fresult["result_code"] == "4": + print(u"验证码通过,开始登录..") + return True + else: + if "result_message" in fresult: + print(fresult["result_message"]) + sleep(1) + self.session.httpClint.del_cookies() + + def baseLogin(self, user, passwd): + """ + 登录过程 + :param user: + :param passwd: + :return: 权限校验码 + """ + logurl = self.session.urls["login"] + + loginData = OrderedDict() + loginData["username"] = user, + loginData["password"] = passwd, + loginData["appid"] = "otn", + loginData["answer"] = self.randCode, + + tresult = self.session.httpClint.send(logurl, loginData) + if 'result_code' in tresult and tresult["result_code"] == 0: + print(u"登录成功") + tk = self.auth() + if "newapptk" in tk and tk["newapptk"]: + return tk["newapptk"] + else: + return False + elif 'result_message' in tresult and tresult['result_message']: + messages = tresult['result_message'] + if messages.find(u"密码输入错误") is not -1: + raise UserPasswordException("{0}".format(messages)) + else: + print(u"登录失败: {0}".format(messages)) + print(u"尝试重新登陆") + return False + else: + return False + + def getUserName(self, uamtk): + """ + 登录成功后,显示用户名 + :return: + """ + if not uamtk: + return u"权限校验码不能为空" + else: + uamauthclientUrl = self.session.urls["uamauthclient"] + data = {"tk": uamtk} + uamauthclientResult = self.session.httpClint.send(uamauthclientUrl, data) + if uamauthclientResult: + if "result_code" in uamauthclientResult and uamauthclientResult["result_code"] == 0: + print(u"欢迎 {} 登录".format(uamauthclientResult["username"])) + return True + else: + return False + else: + self.session.httpClint.send(uamauthclientUrl, data) + url = self.session.urls["getUserInfo"] + self.session.httpClint.send(url) + + def go_login(self): + """ + 登陆 + :param user: 账户名 + :param passwd: 密码 + :return: + """ + user, passwd = TickerConfig.USER, TickerConfig.PWD + if not user or not passwd: + raise UserPasswordException(u"温馨提示: 用户名或者密码为空,请仔细检查") + login_num = 0 + while True: + if loginConf(self.session): + + result = getPassCodeNewOrderAndLogin1(session=self.session, imgType="login") + if not result: + continue + self.randCode = getRandCode(self.is_auto_code, self.auto_code_type, result) + print(self.randCode) + login_num += 1 + self.auth() + if self.codeCheck(): + uamtk = self.baseLogin(user, passwd) + if uamtk: + self.getUserName(uamtk) + break + else: + loginAysnSuggest(self.session, username=user, password=passwd) + login_num += 1 + break \ No newline at end of file diff --git a/src/12306/init/select_ticket_info.py b/src/12306/init/select_ticket_info.py new file mode 100644 index 0000000..1dc0142 --- /dev/null +++ b/src/12306/init/select_ticket_info.py @@ -0,0 +1,252 @@ +# -*- coding=utf-8 -*- +import datetime +import random +import os +import socket +import sys +import threading +import time +import TickerConfig +import wrapcache +from agency.cdn_utils import CDNProxy, open_cdn_file +from config import urlConf, configCommon +from config.TicketEnmu import ticket +from config.configCommon import seat_conf_2, seat_conf +from config.getCookie import getDrvicesID +from init.login import GoLogin +from inter.AutoSubmitOrderRequest import autoSubmitOrderRequest +from inter.ChechFace import chechFace +from inter.CheckUser import checkUser +from inter.GetPassengerDTOs import getPassengerDTOs +from inter.LiftTicketInit import liftTicketInit +from inter.Query import query +from inter.SubmitOrderRequest import submitOrderRequest +from myException.PassengerUserException import PassengerUserException +from myException.UserPasswordException import UserPasswordException +from myException.ticketConfigException import ticketConfigException +from myException.ticketIsExitsException import ticketIsExitsException +from myException.ticketNumOutException import ticketNumOutException +from myUrllib.httpUtils import HTTPClient + + +class select: + """ + 快速提交车票通道 + """ + def __init__(self): + self.cdn_list = open_cdn_file("filter_cdn_list") + self.get_ticket_info() + self._station_seat = [seat_conf[x] for x in TickerConfig.SET_TYPE] + self.auto_code_type = TickerConfig.AUTO_CODE_TYPE + self.httpClint = HTTPClient(TickerConfig.IS_PROXY, self.cdn_list) + self.httpClint.cdn = self.cdn_list[random.randint(0, 4)] + self.urls = urlConf.urls + self.login = GoLogin(self, TickerConfig.IS_AUTO_CODE, self.auto_code_type) + self.cookies = "" + self.queryUrl = "leftTicket/queryO" + self.passengerTicketStrList = "" + self.passengerTicketStrByAfterLate = "" + self.oldPassengerStr = "" + self.set_type = "" + self.flag = True + + @staticmethod + def get_ticket_info(): + """ + 获取配置信息 + :return: + """ + + print(u"*" * 50) + print(f"检查当前版本为: {TickerConfig.RE_VERSION}") + version = sys.version.split(" ")[0] + print(u"检查当前python版本为:{},目前版本只支持3.6以上".format(version)) + if version < "3.6.0": + raise Exception + print(u"12306刷票小助手,最后更新于2019.09.18,请勿作为商业用途,交流群号:" + u" 1群:286271084(已满)\n" + u" 2群:649992274(已满)\n" + u" 3群:632501142(已满)\n" + u" 4群: 606340519(已满)\n" + u" 5群: 948526733(已满)\n" + u" 7群: 660689659(已满)\n" + u" 8群: 620629239(已满)\n" + u" 6群: 608792930(未满)\n" + u" 9群: 693035807(未满)\n" + ) + print( + f"当前配置:\n出发站:{TickerConfig.FROM_STATION}\n到达站:{TickerConfig.TO_STATION}\n车次: {','.join(TickerConfig.STATION_TRAINS) or '所有车次'}\n乘车日期:{','.join(TickerConfig.STATION_DATES)}\n坐席:{','.join(TickerConfig.SET_TYPE)}\n是否有票优先提交:{TickerConfig.IS_MORE_TICKET}\n乘车人:{TickerConfig.TICKET_PEOPLES}\n" \ + f"刷新间隔: 随机(1-3S)\n僵尸票关小黑屋时长: {TickerConfig.TICKET_BLACK_LIST_TIME}\n下单接口: {TickerConfig.ORDER_TYPE}\n下单模式: {TickerConfig.ORDER_MODEL}\n预售踩点时间:{TickerConfig.OPEN_TIME}") + print(u"*" * 50) + + def station_table(self, from_station, to_station): + """ + 读取车站信息 + :param station: + :return: + """ + path = os.path.join(os.path.dirname(__file__), '../station_name.txt') + try: + with open(path, encoding="utf-8") as result: + info = result.read().split('=')[1].strip("'").split('@') + except Exception: + with open(path) as result: + info = result.read().split('=')[1].strip("'").split('@') + del info[0] + station_name = {} + for i in range(0, len(info)): + n_info = info[i].split('|') + station_name[n_info[1]] = n_info[2] + try: + from_station = station_name[from_station.encode("utf8")] + to_station = station_name[to_station.encode("utf8")] + except KeyError: + from_station = station_name[from_station] + to_station = station_name[to_station] + return from_station, to_station + + def call_login(self, auth=False): + """ + 登录回调方法 + :return: + """ + if auth: + return self.login.auth() + else: + configCommon.checkSleepTime(self) # 防止网上启动晚上到点休眠 + self.login.go_login() + + def main(self): + l = liftTicketInit(self) + l.reqLiftTicketInit() + getDrvicesID(self) + self.call_login() + check_user = checkUser(self) + t = threading.Thread(target=check_user.sendCheckUser) + t.setDaemon(True) + t.start() + from_station, to_station = self.station_table(TickerConfig.FROM_STATION, TickerConfig.TO_STATION) + num = 0 + s = getPassengerDTOs(selectObj=self, ticket_peoples=TickerConfig.TICKET_PEOPLES) + passenger = s.sendGetPassengerDTOs() + wrapcache.set("user_info", passenger, timeout=9999999) + + now = datetime.datetime.now() + if TickerConfig.ORDER_MODEL is 1: + print(f"预售还未开始,阻塞中,预售时间为{TickerConfig.OPEN_TIME}, 当前时间为: {now.strftime('%H:%M:%S')}") + sleep_time_s = 0.1 + sleep_time_t = 0.3 + # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 + while now.strftime("%H:%M:%S") < TickerConfig.OPEN_TIME: + now = datetime.datetime.now() + time.sleep(0.0001) + print(f"预售开始,开启时间为: {now.strftime('%H:%M:%S')}") + else: + sleep_time_s = TickerConfig.MIN_TIME + sleep_time_t = TickerConfig.MAX_TIME + + while 1: + try: + num += 1 + now = datetime.datetime.now() # 感谢群里大佬提供整点代码 + configCommon.checkSleepTime(self) # 晚上到点休眠 + q = query(selectObj=self, + from_station=from_station, + to_station=to_station, + from_station_h=TickerConfig.FROM_STATION, + to_station_h=TickerConfig.TO_STATION, + _station_seat=self._station_seat, + station_trains=TickerConfig.STATION_TRAINS, + station_dates=TickerConfig.STATION_DATES, + ticke_peoples_num=len(TickerConfig.TICKET_PEOPLES), + ) + queryResult = q.sendQuery() + # 查询接口 + if queryResult.get("status"): + train_no = queryResult.get("train_no", "") + train_date = queryResult.get("train_date", "") + stationTrainCode = queryResult.get("stationTrainCode", "") + secretStr = queryResult.get("secretStr", "") + secretList = queryResult.get("secretList", "") + seat = queryResult.get("seat", "") + leftTicket = queryResult.get("leftTicket", "") + query_from_station_name = queryResult.get("query_from_station_name", "") + query_to_station_name = queryResult.get("query_to_station_name", "") + is_more_ticket_num = queryResult.get("is_more_ticket_num", len(TickerConfig.TICKET_PEOPLES)) + if wrapcache.get(train_no): + print(ticket.QUEUE_WARNING_MSG.format(train_no)) + else: + # 获取联系人 + s = getPassengerDTOs(selectObj=self, ticket_peoples=TickerConfig.TICKET_PEOPLES, + set_type="" if isinstance(seat, list) else seat_conf_2[seat], + # 候补订单需要设置多个坐席 + is_more_ticket_num=is_more_ticket_num) + getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr(secretStr, secretList) + if getPassengerDTOsResult.get("status", False): + self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "") + self.passengerTicketStrByAfterLate = getPassengerDTOsResult.get( + "passengerTicketStrByAfterLate", "") + self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "") + self.set_type = getPassengerDTOsResult.get("set_type", "") + # 提交订单 + # 订单分为两种,一种为抢单,一种为候补订单 + if secretStr: # 正常下单 + if TickerConfig.ORDER_TYPE == 1: # 快速下单 + a = autoSubmitOrderRequest(selectObj=self, + secretStr=secretStr, + train_date=train_date, + passengerTicketStr=self.passengerTicketStrList, + oldPassengerStr=self.oldPassengerStr, + train_no=train_no, + stationTrainCode=stationTrainCode, + leftTicket=leftTicket, + set_type=self.set_type, + query_from_station_name=query_from_station_name, + query_to_station_name=query_to_station_name, + ) + a.sendAutoSubmitOrderRequest() + elif TickerConfig.ORDER_TYPE == 2: # 普通下单 + sor = submitOrderRequest(self, secretStr, from_station, to_station, train_no, + self.set_type, + self.passengerTicketStrList, self.oldPassengerStr, train_date, + TickerConfig.TICKET_PEOPLES) + sor.sendSubmitOrderRequest() + elif secretList: # 候补订单 + c = chechFace(self, secretList, train_no) + c.sendChechFace() + else: + random_time = round(random.uniform(sleep_time_s, sleep_time_t), 2) + nateMsg = ' 无候补机会' if TickerConfig.ORDER_TYPE == 2 else "" + print(f"正在第{num}次查询 停留时间:{random_time} 乘车日期: {','.join(TickerConfig.STATION_DATES)} 车次:{','.join(TickerConfig.STATION_TRAINS) or '所有车次'} 下单无票{nateMsg} 耗时:{(datetime.datetime.now() - now).microseconds / 1000} {queryResult.get('cdn')}") + time.sleep(random_time) + except PassengerUserException as e: + print(e) + break + except ticketConfigException as e: + print(e) + break + except ticketIsExitsException as e: + print(e) + break + except ticketNumOutException as e: + print(e) + break + except UserPasswordException as e: + print(e) + break + except ValueError as e: + if e == "No JSON object could be decoded": + print(u"12306接口无响应,正在重试") + else: + print(e) + except KeyError as e: + print(e) + except TypeError as e: + print(u"12306接口无响应,正在重试 {0}".format(e)) + except socket.error as e: + print(e) + + +if __name__ == '__main__': + s = select() + cdn = s.station_table("长沙", "深圳") diff --git a/src/12306/inter/AutoSubmitOrderRequest.py b/src/12306/inter/AutoSubmitOrderRequest.py new file mode 100644 index 0000000..8cabef5 --- /dev/null +++ b/src/12306/inter/AutoSubmitOrderRequest.py @@ -0,0 +1,124 @@ +# coding=utf-8 +import urllib +from collections import OrderedDict + +from config.TicketEnmu import ticket +from inter.CheckRandCodeAnsyn import checkRandCodeAnsyn +from inter.GetQueueCountAsync import getQueueCountAsync +from inter.GetRandCode import getRandCode +import TickerConfig + + +class autoSubmitOrderRequest: + """ + 快读提交订单通道 + """ + def __init__(self, selectObj, + secretStr, + train_date, + query_from_station_name, + query_to_station_name, + passengerTicketStr, + oldPassengerStr, + train_no, + stationTrainCode, + leftTicket, + set_type,): + self.set_type = set_type + try: + self.secretStr = urllib.unquote(secretStr) + except AttributeError: + self.secretStr = urllib.parse.unquote(secretStr) + self.train_date = train_date + self.query_from_station_name = query_from_station_name + self.query_to_station_name = query_to_station_name + self.passengerTicketStr = passengerTicketStr.rstrip("_{0}".format(self.set_type)) + self.oldPassengerStr = oldPassengerStr + self.session = selectObj + self.train_no = train_no + self.stationTrainCode = stationTrainCode + self.leftTicket = leftTicket + + def data_par(self): + """ + 参数结构 + 自动提交代码接口-autoSubmitOrderRequest + - 字段说明 + - secretStr 车票代码 + - train_date 乘车日期 + - tour_flag 乘车类型 + - purpose_codes 学生还是成人 + - query_from_station_name 起始车站 + - query_to_station_name 结束车站 + - cancel_flag 默认2,我也不知道干嘛的 + - bed_level_order_num 000000000000000000000000000000 + - passengerTicketStr 乘客乘车代码 + - oldPassengerStr 乘客编号代码 + :return: + """ + data = OrderedDict() + data["secretStr"] = self.secretStr + data["train_date"] = self.train_date + data["tour_flag"] = "dc" + data["purpose_codes"] = "ADULT" + data["query_from_station_name"] = TickerConfig.FROM_STATION + data["query_to_station_name"] = TickerConfig.TO_STATION + data["cancel_flag"] = 2 + data["bed_level_order_num"] = "000000000000000000000000000000" + data["passengerTicketStr"] = self.passengerTicketStr + data["oldPassengerStr"] = self.oldPassengerStr + return data + + def sendAutoSubmitOrderRequest(self): + """ + 请求下单接口 + :return: + """ + urls = self.session.urls["autoSubmitOrderRequest"] + data = self.data_par() + autoSubmitOrderRequestResult = self.session.httpClint.send(urls, data) + if autoSubmitOrderRequestResult and \ + autoSubmitOrderRequestResult.get("status", False) and\ + autoSubmitOrderRequestResult.get("httpstatus", False) == 200: + requestResultData = autoSubmitOrderRequestResult.get("data", {}) + if requestResultData: + result = requestResultData.get("result", "") + ifShowPassCode = requestResultData.get("ifShowPassCode", "N") + ifShowPassCodeTime = int(requestResultData.get("ifShowPassCodeTime", "1000")) / float(1000) + print(ticket.AUTO_SUBMIT_ORDER_REQUEST_C) + g = getQueueCountAsync(session=self.session, + train_no=self.train_no, + stationTrainCode=self.stationTrainCode, + fromStationTelecode=self.query_from_station_name, + toStationTelecode=self.query_to_station_name, + leftTicket=self.leftTicket, + set_type=self.set_type, + users=len(TickerConfig.TICKET_PEOPLES), + station_dates=self.train_date, + passengerTicketStr=self.passengerTicketStr, + oldPassengerStr=self.oldPassengerStr, + result=result, + ifShowPassCodeTime=ifShowPassCodeTime, + ) + if ifShowPassCode == "Y": # 如果需要验证码 + print(u"需要验证码") + print(u"正在使用自动识别验证码功能") + for i in range(3): + randCode = getRandCode(is_auto_code=True, auto_code_type=2) + checkcode = checkRandCodeAnsyn(self.session, randCode, "") + if checkcode == 'TRUE': + print(u"验证码通过,正在提交订单") + data['randCode'] = randCode + break + else: + print (u"验证码有误, {0}次尝试重试".format(i + 1)) + print(u"验证码超过限定次数3次,放弃此次订票机会!") + g.sendGetQueueCountAsync() + else: + print(ticket.AUTO_SUBMIT_ORDER_REQUEST_F) + if autoSubmitOrderRequestResult.get("messages", ""): + print("".join(autoSubmitOrderRequestResult.get("messages", ""))) + elif autoSubmitOrderRequestResult.get("validateMessages", ""): + print("".join(autoSubmitOrderRequestResult.get("validateMessages", ""))) + + diff --git a/src/12306/inter/ChechFace.py b/src/12306/inter/ChechFace.py new file mode 100644 index 0000000..89cb529 --- /dev/null +++ b/src/12306/inter/ChechFace.py @@ -0,0 +1,68 @@ +import datetime +import urllib +from collections import OrderedDict +from config.urlConf import urls +import TickerConfig +from inter.GetSuccessRate import getSuccessRate +from myException.ticketConfigException import ticketConfigException +import wrapcache + + +class chechFace: + def __init__(self, selectObj, secretList, train_no): + """ + 人脸识别 + """ + self.secretList = secretList + self.session = selectObj + self.train_no = train_no + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O| + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["secretList"] = f"{self.secretList}#{ticker}|" + data["_json_att"] = "" + return data + + def sendChechFace(self): + chechFaceRsp = self.session.httpClint.send(urls.get("chechFace"), self.data_apr()) + if not chechFaceRsp.get("status"): + print("".join(chechFaceRsp.get("messages")) or chechFaceRsp.get("validateMessages")) + wrapcache.set(key=f"hb{self.train_no}", value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + return + data = chechFaceRsp["data"] + if not data.get("face_flag"): + print("".join(chechFaceRsp.get("messages")) or chechFaceRsp.get("validateMessages")) + if data.get("face_check_code") == "14": + """ + 未通过人脸核验 + """ + raise ticketConfigException("通过人证一致性核验的用户及激活的“铁路畅行”会员可以提交候补需求,请您按照操作说明在铁路12306app.上完成人证核验") + elif data.get("face_check_code") in ["12", "02"]: + """ + 系统忙,请稍后再试! + """ + print("系统忙,请稍后再试!") + wrapcache.set(key=f"hb{self.train_no}", value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + elif data.get("face_check_code") in ["03", "13"]: + """ + 证件信息审核失败,请检查所填写的身份信息内容与原证件是否一致。 + """ + raise ticketConfigException("证件信息审核失败,请检查所填写的身份信息内容与原证件是否一致。") + elif data.get("face_check_code") in ["01", "11"]: + """ + 证件信息正在审核中,请您耐心等待,审核通过后可继续完成候补操作。 + """ + print("证件信息正在审核中,请您耐心等待,审核通过后可继续完成候补操作。") + wrapcache.set(key=f"hb{self.train_no}", value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + g = getSuccessRate(self.session, self.secretList) + g.sendSuccessRate() diff --git a/src/12306/inter/CheckOrderInfo.py b/src/12306/inter/CheckOrderInfo.py new file mode 100644 index 0000000..4a20ef4 --- /dev/null +++ b/src/12306/inter/CheckOrderInfo.py @@ -0,0 +1,74 @@ +# coding=utf-8 +from collections import OrderedDict +from inter.GetQueueCount import getQueueCount +from inter.GetRepeatSubmitToken import getRepeatSubmitToken + + +class checkOrderInfo: + + def __init__(self, session, train_no, set_type, passengerTicketStrList, oldPassengerStr, station_dates, ticket_peoples): + self.train_no = train_no + self.set_type = set_type + self.passengerTicketStrList = passengerTicketStrList + self.oldPassengerStr = oldPassengerStr + self.station_dates = station_dates + self.ticket_peoples = ticket_peoples + self.RepeatSubmitToken = getRepeatSubmitToken(session) + self.getTicketInfoForPassengerForm = self.RepeatSubmitToken.sendGetRepeatSubmitToken() + self.ticketInfoForPassengerForm = self.getTicketInfoForPassengerForm.get("ticketInfoForPassengerForm", "") + self.token = self.getTicketInfoForPassengerForm.get("token", "") + self.session = self.getTicketInfoForPassengerForm.get("session", "") + + def data_par(self): + """ + 参数结构 + :return: + """ + data = OrderedDict() + data['bed_level_order_num'] = "000000000000000000000000000000" + data['passengerTicketStr'] = self.passengerTicketStrList.rstrip("_{0}".format(self.set_type)) + data['oldPassengerStr'] = self.oldPassengerStr + data['tour_flag'] = 'dc' + data['randCode'] = "" + data['cancel_flag'] = 2 + data['_json_att'] = "" + data['REPEAT_SUBMIT_TOKEN'] = self.token + return data + + def sendCheckOrderInfo(self): + """ + 检查支付订单,需要提交REPEAT_SUBMIT_TOKEN + passengerTicketStr : 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N) + oldPassengersStr: 乘客名,证件类型,证件号,乘客类型 + :return: + """ + CheckOrderInfoUrls = self.session.urls["checkOrderInfoUrl"] + data = self.data_par() + checkOrderInfoRep = self.session.httpClint.send(CheckOrderInfoUrls, data) + data = checkOrderInfoRep.get("data", {}) + if data and data.get("submitStatus", False): + print (u'车票提交通过,正在尝试排队') + ifShowPassCodeTime = int(checkOrderInfoRep["data"]["ifShowPassCodeTime"]) / float(1000) + if "ifShowPassCode" in checkOrderInfoRep["data"] and checkOrderInfoRep["data"]["ifShowPassCode"] == "Y": + is_need_code = True + elif "ifShowPassCode" in checkOrderInfoRep["data"] and checkOrderInfoRep['data']['submitStatus'] is True: + is_need_code = False + else: + is_need_code = False + QueueCount = getQueueCount(self.session, + is_need_code, + ifShowPassCodeTime, + self.set_type, + self.station_dates, + self.train_no, + self.ticket_peoples, + self.ticketInfoForPassengerForm, + self.token, + self.oldPassengerStr, + self.passengerTicketStrList, + ) + QueueCount.sendGetQueueCount() + elif "errMsg" in data and data["errMsg"]: + print(checkOrderInfoRep['data']["errMsg"]) + elif 'messages' in checkOrderInfoRep and checkOrderInfoRep['messages']: + print (checkOrderInfoRep['messages'][0]) \ No newline at end of file diff --git a/src/12306/inter/CheckRandCodeAnsyn.py b/src/12306/inter/CheckRandCodeAnsyn.py new file mode 100644 index 0000000..d541288 --- /dev/null +++ b/src/12306/inter/CheckRandCodeAnsyn.py @@ -0,0 +1,27 @@ +# coding=utf-8 +class checkRandCodeAnsyn: + def __init__(self, session, randCode, token): + self.session = session + self.randCode = randCode + self.token = token + + def data_par(self): + """ + :return: + """ + data = { + "randCode": self.randCode, + "rand": "randp", + "_json_att": "", + "REPEAT_SUBMIT_TOKEN": self.token + } + return data + + def sendCheckRandCodeAnsyn(self): + """ + 下单验证码识别 + :return: + """ + checkRandCodeAnsynUrl = self.session.urls["checkRandCodeAnsyn"] + fresult = self.session.httpClint.send(checkRandCodeAnsynUrl, self.data_par()) # 校验验证码是否正确 + return fresult['data']['msg'] \ No newline at end of file diff --git a/src/12306/inter/CheckUser.py b/src/12306/inter/CheckUser.py new file mode 100644 index 0000000..9b1a0ea --- /dev/null +++ b/src/12306/inter/CheckUser.py @@ -0,0 +1,39 @@ +# coding=utf-8 +import datetime +import random +import time +import wrapcache +from config import configCommon +from config.TicketEnmu import ticket + + +class checkUser: + def __init__(self, session): + self.session = session + + def sendCheckUser(self): + """ + 检查用户登录, 检查间隔为2分钟 + :return: + """ + CHENK_TIME = 1 + while 1: + time.sleep(3) # 防止cpu占用过高 + configCommon.checkSleepTime(self.session) # 修复晚上查询线程休眠时,检查登录线程为休眠,造成快豆迅速消耗 + if wrapcache.get("user_time") is None: + check_user_url = self.session.urls["check_user_url"] + data = {"_json_att": ""} + check_user = self.session.httpClint.send(check_user_url, data) + if check_user.get("data", False): + check_user_flag = check_user["data"]["flag"] + if check_user_flag is True: + wrapcache.set("user_time", datetime.datetime.now(), timeout=random.randint(60, 80) * CHENK_TIME) + else: + if check_user['messages']: + print(ticket.LOGIN_SESSION_FAIL.format(check_user['messages'])) + self.session.call_login() + wrapcache.set("user_time", datetime.datetime.now(), timeout=random.randint(60, 80) * CHENK_TIME) + else: + print(ticket.LOGIN_SESSION_FAIL.format(check_user['messages'])) + self.session.call_login() + wrapcache.set("user_time", datetime.datetime.now(), timeout=random.randint(60, 80) * CHENK_TIME) diff --git a/src/12306/inter/ConfirmHB.py b/src/12306/inter/ConfirmHB.py new file mode 100644 index 0000000..210ce45 --- /dev/null +++ b/src/12306/inter/ConfirmHB.py @@ -0,0 +1,48 @@ +from collections import OrderedDict +from config.urlConf import urls +import TickerConfig +from inter.GetQueueCount import queryQueueByAfterNate + + +class confirmHB: + def __init__(self, secretList, session, tickerNo, jzdhDate): + """ + 人脸识别 + """ + self.secretList = secretList + self.session = session + self.passengerTicketStrByAfterLate = session.passengerTicketStrByAfterLate + self.tickerNo = tickerNo + self.jzdhDate = jzdhDate + + def data_apr(self): + """ + passengerInfo 1#XXXX#1#***************77X#bf6ae40d3655ae7eff005ee21d95876b38ab97a8031b464bc2f74a067e3ec957; + jzParam 2019-08-31#19#00 + hbTrain 5l000G177230,O# + lkParam + :return: + """ + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["passengerInfo"] = self.passengerTicketStrByAfterLate + data["jzParam"] = self.jzdhDate + data["hbTrain"] = f"{self.tickerNo},{ticker}#" + data["lkParam"] = "" + return data + + def sendChechFace(self): + ChechFaceRsp = self.session.httpClint.send(urls.get("confirmHB"), self.data_apr()) + if not ChechFaceRsp.get("status"): + print("".join(ChechFaceRsp.get("messages")) or ChechFaceRsp.get("validateMessages")) + return + data = ChechFaceRsp.get("data") + if not data.get("flag"): + print(f"错误信息:{data.get('msg')}") + return + queue = queryQueueByAfterNate(self.session) + queue.sendQueryQueueByAfterNate() + + + + diff --git a/src/12306/inter/ConfirmSingleForQueue.py b/src/12306/inter/ConfirmSingleForQueue.py new file mode 100644 index 0000000..ba6a28e --- /dev/null +++ b/src/12306/inter/ConfirmSingleForQueue.py @@ -0,0 +1,94 @@ +# coding=utf-8 +import datetime +import time + +from inter.CheckRandCodeAnsyn import checkRandCodeAnsyn +from inter.GetPassengerDTOs import getPassengerDTOs +from inter.GetRandCode import getRandCode +from inter.QueryOrderWaitTime import queryOrderWaitTime + + +class confirmSingleForQueue: + def __init__(self, session, ifShowPassCodeTime, is_node_code, token, set_type, ticket_peoples, ticketInfoForPassengerForm, + oldPassengerStr, passengerTicketStrList): + self.session = session + self.ifShowPassCodeTime = ifShowPassCodeTime + self.is_node_code = is_node_code + self.token = token + self.set_type = set_type + self.ticket_peoples = ticket_peoples + self.ticketInfoForPassengerForm = ticketInfoForPassengerForm + self.passengerTicketStrList = passengerTicketStrList + self.oldPassengerStr = oldPassengerStr + + def data_par(self): + """ + 模拟提交订单是确认按钮,参数获取方法还是get_ticketInfoForPassengerForm 中获取 + :return: + """ + if not self.passengerTicketStrList and not self.oldPassengerStr: + s = getPassengerDTOs(session=self.session, ticket_peoples=self.ticket_peoples, set_type=self.set_type) + getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr() + if getPassengerDTOsResult.get("status", False): + self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "") + self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "") + data = { + "passengerTicketStr": self.passengerTicketStrList.rstrip("_{0}".format(self.set_type)), + "oldPassengerStr": "".join(self.oldPassengerStr), + "purpose_codes": self.ticketInfoForPassengerForm["purpose_codes"], + "key_check_isChange": self.ticketInfoForPassengerForm["key_check_isChange"], + "leftTicketStr": self.ticketInfoForPassengerForm["leftTicketStr"], + "train_location": self.ticketInfoForPassengerForm["train_location"], + "seatDetailType": "", # 开始需要选择座位,但是目前12306不支持自动选择作为,那这个参数为默认 + "roomType": "00", # 好像是根据一个id来判断选中的,两种 第一种是00,第二种是10,但是我在12306的页面没找到该id,目前写死是00,不知道会出什么错 + "dwAll": "N", + "whatsSelect": 1, + "_json_at": "", + "randCode": "", + "choose_seats": "", + "REPEAT_SUBMIT_TOKEN": self.token, + } + return data + + def sendConfirmSingleForQueue(self): + """ + # 模拟查询当前的列车排队人数的方法 + # 返回信息组成的提示字符串 + :return: + """ + data = self.data_par() + checkQueueOrderUrl = self.session.urls["checkQueueOrderUrl"] + try: + if self.is_node_code: + print(u"正在使用自动识别验证码功能") + for i in range(3): + randCode = getRandCode(is_auto_code=True, auto_code_type=2) + checkcode = checkRandCodeAnsyn(self.session, randCode, self.token) + if checkcode == 'TRUE': + print(u"验证码通过,正在提交订单") + data['randCode'] = randCode + break + else: + print (u"验证码有误, {0}次尝试重试".format(i + 1)) + print(u"验证码超过限定次数3次,放弃此次订票机会!") + else: + print(u"不需要验证码") + time.sleep(self.ifShowPassCodeTime) + checkQueueOrderResult = self.session.httpClint.send(checkQueueOrderUrl, data) + if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]: + c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {} + if 'submitStatus' in c_data and c_data['submitStatus'] is True: + qow = queryOrderWaitTime(self.session) + qow.sendQueryOrderWaitTime() + else: + if 'errMsg' in c_data and c_data['errMsg']: + print(u"提交订单失败,{0}".format(c_data['errMsg'])) + else: + print(c_data) + print(u'订票失败!很抱歉,请重试提交预订功能!') + elif "messages" in checkQueueOrderResult and checkQueueOrderResult["messages"]: + print(u"提交订单失败,错误信息: " + checkQueueOrderResult["messages"]) + else: + print(u"提交订单中,请耐心等待:" + checkQueueOrderResult["message"]) + except ValueError: + print(u"接口 {} 无响应".format(checkQueueOrderUrl)) \ No newline at end of file diff --git a/src/12306/inter/ConfirmSingleForQueueAsys.py b/src/12306/inter/ConfirmSingleForQueueAsys.py new file mode 100644 index 0000000..194fa2b --- /dev/null +++ b/src/12306/inter/ConfirmSingleForQueueAsys.py @@ -0,0 +1,72 @@ +# coding=utf-8 +import json +import urllib +from collections import OrderedDict + +from inter.QueryOrderWaitTime import queryOrderWaitTime + + +class confirmSingleForQueueAsys: + """ + 订单快读排队 + """ + def __init__(self, + session, + passengerTicketStr, + oldPassengerStr, + result, + randCode="", + ): + self.session = session + self.passengerTicketStr = passengerTicketStr + self.oldPassengerStr = oldPassengerStr + self.result = result if isinstance(result, str) else str(result) + self.randCode = randCode + + def data_par(self): + """ + 字段说明 + passengerTicketStr 乘客乘车代码 + oldPassengerStr 乘客编号代码 + randCode 填空 + purpose_codes 学生还是成人 + key_check_isChange autoSubmitOrderRequest返回的result字段做切割即可 + leftTicketStr autoSubmitOrderRequest返回的result字段做切割即可 + train_location autoSubmitOrderRequest返回的result字段做切割即可 + choose_seats + seatDetailType + _json_att + :return: + """ + results = self.result.split("#") + key_check_isChange = results[1] + leftTicketStr = results[2] + train_location = results[0] + data = OrderedDict() + data["passengerTicketStr"] = self.passengerTicketStr + data["oldPassengerStr"] = self.oldPassengerStr + data["randCode"] = self.randCode + data["purpose_codes"] = "ADULT" + data["key_check_isChange"] = key_check_isChange + data["leftTicketStr"] = leftTicketStr + data["train_location"] = train_location + data["choose_seats"] = "" + data["seatDetailType"] = "" + data["_json_att"] = "" + return data + + def sendConfirmSingleForQueueAsys(self): + """ + 请求订单快读排队接口 + :return: + """ + urls = self.session.urls["confirmSingleForQueueAsys"] + data = self.data_par() + confirmSingleForQueueAsysResult = self.session.httpClint.send(urls, data) + if confirmSingleForQueueAsysResult.get("status", False) and confirmSingleForQueueAsysResult.get("data", False): + queueData = confirmSingleForQueueAsysResult.get("data", {}) + if queueData.get("submitStatus", False): + qwt = queryOrderWaitTime(session=self.session) + qwt.sendQueryOrderWaitTime() + else: + print(queueData.get("errMsg", "")) diff --git a/src/12306/inter/GetPassCodeNewOrderAndLogin.py b/src/12306/inter/GetPassCodeNewOrderAndLogin.py new file mode 100644 index 0000000..98d84be --- /dev/null +++ b/src/12306/inter/GetPassCodeNewOrderAndLogin.py @@ -0,0 +1,78 @@ +# coding=utf-8 +import base64 +import copy +import random + + +def getPassCodeNewOrderAndLogin(session, imgType): + """ + 下载验证码 + :param session: + :param imgType: 下载验证码类型,login=登录验证码,其余为订单验证码 + :return: + """ + if imgType == "login": + codeImgUrl = copy.deepcopy(session.urls["getCodeImg"]) + codeImgUrl["req_url"] = codeImgUrl["req_url"].format(random.random()) + else: + codeImgUrl = copy.deepcopy(session.urls["codeImgByOrder"]) + codeImgUrl["req_url"] = codeImgUrl["req_url"].format(random.random()) + print(u"下载验证码...") + img_path = './tkcode.png' + result = session.httpClint.send(codeImgUrl) + try: + if isinstance(result, dict): + print(u"下载验证码失败, 请手动检查是否ip被封,或者重试,请求地址:https://kyfw.12306.cn{}".format(codeImgUrl.get("req_url"))) + return False + else: + print(u"下载验证码成功") + try: + with open(img_path, 'wb', encoding="utf-8") as img: + img.write(result) + except Exception: + with open(img_path, 'wb') as img: + img.write(result) + return result + except OSError: + print(u"验证码下载失败,可能ip被封,确认请手动请求: {0}".format(codeImgUrl)) + + +def getPassCodeNewOrderAndLogin1(session, imgType): + """ + 获取验证码2 + :param session: + :param imgType: + :return: + """ + if imgType == "login": + codeImgUrl = copy.deepcopy(session.urls["getCodeImg1"]) + codeImgUrl["req_url"] = codeImgUrl["req_url"].format(random.random()) + else: + codeImgUrl = copy.deepcopy(session.urls["codeImgByOrder"]) + codeImgUrl["req_url"] = codeImgUrl["req_url"].format(random.random()) + print(u"下载验证码...") + img_path = './tkcode.png' + codeImgUrlRsp = session.httpClint.send(codeImgUrl) + if not isinstance(codeImgUrlRsp, str): + print("验证码获取失败") + return + result = eval(codeImgUrlRsp.split("(")[1].split(")")[0]).get("image") + try: + if isinstance(result, dict): + print(u"下载验证码失败, 请手动检查是否ip被封,或者重试,请求地址:https://kyfw.12306.cn{}".format(codeImgUrl.get("req_url"))) + return False + else: + print(u"下载验证码成功") + try: + with open(img_path, 'wb', encoding="utf-8") as img: + img.write(result) + except Exception: + with open(img_path, 'wb') as img: + img.write(base64.b64decode(result)) + return result + except OSError: + print(u"验证码下载失败,可能ip被封或者文件写入没权限") + + +if __name__ == '__main__': + pass diff --git a/src/12306/inter/GetPassengerDTOs.py b/src/12306/inter/GetPassengerDTOs.py new file mode 100644 index 0000000..ba4bb59 --- /dev/null +++ b/src/12306/inter/GetPassengerDTOs.py @@ -0,0 +1,123 @@ +# coding=utf-8 +import json + +from config.TicketEnmu import ticket +from myException.PassengerUserException import PassengerUserException +import wrapcache +import TickerConfig + + +class getPassengerDTOs: + """ + 获取乘客信息 + :return: + """ + def __init__(self, selectObj, ticket_peoples=None, set_type=None, is_more_ticket_num=None): + """ + :param session: 登录实例 + :param ticket_peoples: 乘客 + :param set_type: 坐席 + """ + if ticket_peoples is None: + ticket_peoples = [] + self.session = selectObj + self.ticket_peoples = ticket_peoples + self.is_more_ticket_num = is_more_ticket_num + self.set_type = set_type + + def sendGetPassengerDTOs(self): + getPassengerDTOsResult = self.session.httpClint.send(self.session.urls["get_passengerDTOs"], json.dumps({"_json_att": ""})) + if getPassengerDTOsResult.get("data", False) and getPassengerDTOsResult["data"].get("normal_passengers", False): + normal_passengers = getPassengerDTOsResult['data']['normal_passengers'] + _normal_passenger = [normal_passengers[i] for i in range(len(normal_passengers)) if + normal_passengers[i]["passenger_name"] in self.ticket_peoples] + return _normal_passenger if _normal_passenger else [normal_passengers[0]] # 如果配置乘车人没有在账号,则默认返回第一个用户 + else: + if getPassengerDTOsResult.get("data", False) and getPassengerDTOsResult['data'].get("exMsg", False): + print(getPassengerDTOsResult['data'].get("exMsg", False)) + elif getPassengerDTOsResult.get('messages', False): + print(getPassengerDTOsResult.get('messages', False)) + else: + print(u"警告:您的账号可能买票有问题,获取不到联系人,请测试是否能正常下单,在捡漏或者购票!!!") + print(u"警告:您的账号可能买票有问题,获取不到联系人,请测试是否能正常下单,在捡漏或者购票!!!") + print(u"警告:您的账号可能买票有问题,获取不到联系人,请测试是否能正常下单,在捡漏或者购票!!!") + # raise PassengerUserException(ticket.DTO_NOT_FOUND) + + def getPassengerTicketStr(self, set_type): + """ + 获取getPassengerTicketStr 提交对应的代号码 + :param str: 坐席 + :return: + """ + passengerTicketStr = { + '一等座': 'M', + '特等座': 'P', + '二等座': 'O', + '商务座': 9, + '硬座': 1, + '无座': 1, + '软座': 2, + '软卧': 4, + '硬卧': 3, + } + return str(passengerTicketStr[set_type.replace(' ', '')]) + + def getPassengerTicketStrListAndOldPassengerStr(self, secretStr, secretList): + """ + 获取提交车次人内容格式 + passengerTicketStr O,0,1,文贤平,1,43052419950223XXXX,15618715583,N_O,0,1,梁敏,1,43052719920118XXXX,,N + oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1 + ps: 如果is_more_ticket打开了的话,那就是读取联系人列表里面前符合车次数量的前几个联系人 + :return: + """ + passengerTicketStrList = [] + oldPassengerStr = [] + tickers = [] + set_type = "" + if wrapcache.get("user_info"): # 如果缓存中有联系人方式,则读取缓存中的联系人 + user_info = wrapcache.get("user_info") + print(u"使用缓存中查找的联系人信息") + else: + user_info = self.sendGetPassengerDTOs() + wrapcache.set("user_info", user_info, timeout=9999999) + if not user_info: + raise PassengerUserException(ticket.DTO_NOT_IN_LIST) + if len(user_info) < self.is_more_ticket_num: # 如果乘车人填错了导致没有这个乘车人的话,可能乘车人数会小于自动乘车人 + self.is_more_ticket_num = len(user_info) + if secretStr: + set_type = self.getPassengerTicketStr(self.set_type) + if self.is_more_ticket_num is 1: + passengerTicketStrList.append( + '0,' + user_info[0]['passenger_type'] + "," + user_info[0][ + "passenger_name"] + "," + + user_info[0]['passenger_id_type_code'] + "," + user_info[0]['passenger_id_no'] + "," + + user_info[0]['mobile_no'] + ',N,' + user_info[0]["allEncStr"]) + oldPassengerStr.append( + user_info[0]['passenger_name'] + "," + user_info[0]['passenger_id_type_code'] + "," + + user_info[0]['passenger_id_no'] + "," + user_info[0]['passenger_type'] + '_') + else: + for i in range(self.is_more_ticket_num): + passengerTicketStrList.append( + '0,' + user_info[i]['passenger_type'] + "," + user_info[i][ + "passenger_name"] + "," + user_info[i]['passenger_id_type_code'] + "," + user_info[i][ + 'passenger_id_no'] + "," + user_info[i]['mobile_no'] + ',N,' + user_info[i]["allEncStr"] + '_' + set_type) + oldPassengerStr.append( + user_info[i]['passenger_name'] + "," + user_info[i]['passenger_id_type_code'] + "," + + user_info[i]['passenger_id_no'] + "," + user_info[i]['passenger_type'] + '_') + elif secretList: + """ + 候补订单有多少个联系人,就候补多少个联系人了,没有优先提交之说 + 1#XXXX#1#***************77X#bf6ae40d3655ae7eff005ee21d95876b38ab97a8031b464bc2f74a067e3ec957; + """ + for user in user_info: + tickers.append(f"1#{user['passenger_name']}#1#{user['passenger_id_no']}#{user['allEncStr']};") + + return { + "passengerTicketStrList": set_type + "," + ",".join(passengerTicketStrList), + "passengerTicketStrByAfterLate": "".join(tickers), + "oldPassengerStr": "".join(oldPassengerStr), + "code": ticket.SUCCESS_CODE, + "set_type": set_type, + "status": True, + "user_info": user_info, + } diff --git a/src/12306/inter/GetQueueCount.py b/src/12306/inter/GetQueueCount.py new file mode 100644 index 0000000..deb0fdc --- /dev/null +++ b/src/12306/inter/GetQueueCount.py @@ -0,0 +1,149 @@ +# coding=utf-8 +import datetime +import sys +import time +from collections import OrderedDict +import wrapcache + +import TickerConfig +from config.TicketEnmu import ticket +from config.emailConf import sendEmail +from config.serverchanConf import sendServerChan +from config.urlConf import urls +from inter.ConfirmSingleForQueue import confirmSingleForQueue +from myException.ticketIsExitsException import ticketIsExitsException + + +def conversion_int(str): + return int(str) + + +class getQueueCount: + def __init__(self, session, is_need_code, ifShowPassCodeTime, set_type, station_dates, train_no, ticket_peoples, + ticketInfoForPassengerForm, token, oldPassengerStr, passengerTicketStrList): + self.station_dates = station_dates + self.session = session + self.is_need_code = is_need_code + self.ifShowPassCodeTime = ifShowPassCodeTime + self.set_type = set_type + self.train_no = train_no + self.ticket_peoples = ticket_peoples + self.ticket_black_list = {} + self.ticketInfoForPassengerForm = ticketInfoForPassengerForm + self.token = token + self.oldPassengerStr = oldPassengerStr + self.passengerTicketStrList = passengerTicketStrList + + def data_par(self): + """ + 参数结构 + 自动提交代码接口-autoSubmitOrderRequest + - 字段说明 + - secretStr 车票代码 + - train_date 乘车日期 + - tour_flag 乘车类型 + - purpose_codes 学生还是成人 + - query_from_station_name 起始车站 + - query_to_station_name 结束车站 + - cancel_flag 默认2,我也不知道干嘛的 + - bed_level_order_num 000000000000000000000000000000 + - passengerTicketStr 乘客乘车代码 + - oldPassengerStr 乘客编号代码 + :return: + """ + + if sys.version_info.major is 2: + new_train_date = filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" ")) + else: + new_train_date = list(filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" "))) + data = OrderedDict() + data['train_date'] = "{0} {1} {2} {3} 00:00:00 GMT+0800 (中国标准时间)".format( + new_train_date[0], + new_train_date[1], + new_train_date[2] if len(new_train_date[2]) is 2 else f"0{new_train_date[2]}", + new_train_date[4], + ), + data['train_no'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO']['train_no'], + data['stationTrainCode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO'][ + 'station_train_code'], + data['seatType'] = self.set_type, + data['fromStationTelecode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO'][ + 'from_station'], + data['toStationTelecode'] = self.ticketInfoForPassengerForm['queryLeftTicketRequestDTO']['to_station'], + data['leftTicket'] = self.ticketInfoForPassengerForm['leftTicketStr'], + data['purpose_codes'] = self.ticketInfoForPassengerForm['purpose_codes'], + data['train_location'] = self.ticketInfoForPassengerForm['train_location'], + data['REPEAT_SUBMIT_TOKEN'] = self.token, + return data + + def sendGetQueueCount(self): + """ + # 模拟查询当前的列车排队人数的方法 + # 返回信息组成的提示字符串 + :return: + """ + getQueueCountResult = self.session.httpClint.send(self.session.urls["getQueueCountUrl"], self.data_par()) + if "status" in getQueueCountResult and getQueueCountResult["status"] is True: + if "countT" in getQueueCountResult["data"]: + ticket = getQueueCountResult["data"]["ticket"] + ticket_split = sum(map(conversion_int, ticket.split(","))) if ticket.find(",") != -1 else ticket + countT = getQueueCountResult["data"]["countT"] + if int(ticket_split) is 0: + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + print(f"排队失败,当前余票数还剩: {ticket_split} 张") + return + print(u"排队成功, 你排在: {1}位, 当前余票还剩余: {0} 张".format(ticket_split, countT)) + csf = confirmSingleForQueue(self.session, self.ifShowPassCodeTime, self.is_need_code, self.token, + self.set_type, self.ticket_peoples, self.ticketInfoForPassengerForm, + self.oldPassengerStr, self.passengerTicketStrList) + csf.sendConfirmSingleForQueue() + # else: + # print(u"当前排队人数: {1} 当前余票还剩余:{0} 张,继续排队中".format(ticket_split, countT)) + else: + print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountResult, self.train_no)) + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + elif "messages" in getQueueCountResult and getQueueCountResult["messages"]: + print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountResult["messages"][0], self.train_no)) + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + else: + if "validateMessages" in getQueueCountResult and getQueueCountResult["validateMessages"]: + print(str(getQueueCountResult["validateMessages"])) + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + else: + print(u"未知错误 {0}".format("".join(getQueueCountResult))) + + +class queryQueueByAfterNate: + def __init__(self, session): + """ + 候补排队 + :param session: + """ + self.session = session + + def sendQueryQueueByAfterNate(self): + for i in range(10): + queryQueueByAfterNateRsp = self.session.httpClint.send(urls.get("queryQueue")) + if not queryQueueByAfterNateRsp.get("status"): + print("".join(queryQueueByAfterNateRsp.get("messages")) or queryQueueByAfterNateRsp.get("validateMessages")) + time.sleep(1) + else: + sendEmail(ticket.WAIT_ORDER_SUCCESS) + sendServerChan(ticket.WAIT_ORDER_SUCCESS) + raise ticketIsExitsException(ticket.WAIT_AFTER_NATE_SUCCESS) + + +if __name__ == '__main__': + new_train_date = list(filter(None, str(time.asctime(time.strptime("2019-10-07", "%Y-%m-%d"))).split(" "))) + print(new_train_date) + train_date = "{0} {1} {2} {3} 00:00:00 GMT+0800 (中国标准时间)".format( + new_train_date[0], + new_train_date[1], + new_train_date[2] if len(new_train_date[2]) is 2 else f"0{new_train_date[2]}", + new_train_date[4], + ) + print(train_date) \ No newline at end of file diff --git a/src/12306/inter/GetQueueCountAsync.py b/src/12306/inter/GetQueueCountAsync.py new file mode 100644 index 0000000..132e27f --- /dev/null +++ b/src/12306/inter/GetQueueCountAsync.py @@ -0,0 +1,126 @@ +import TickerConfig + +[]# coding=utf-8 +import datetime +import sys +import time +from collections import OrderedDict + +import wrapcache + +from inter.ConfirmSingleForQueueAsys import confirmSingleForQueueAsys + + +class getQueueCountAsync: + """ + 排队 + """ + def __init__(self, + session, + train_no, + stationTrainCode, + fromStationTelecode, + toStationTelecode, + leftTicket, + set_type, + users, + station_dates, + passengerTicketStr, + oldPassengerStr, + result, + ifShowPassCodeTime): + self.train_no = train_no + self.session = session + self.stationTrainCode = stationTrainCode + self.fromStationTelecode = fromStationTelecode + self.toStationTelecode = toStationTelecode + self.set_type = set_type + self.leftTicket = leftTicket + self.users = users + self.station_dates = station_dates + self.passengerTicketStr = passengerTicketStr + self.oldPassengerStr = oldPassengerStr + self.result = result + self.ifShowPassCodeTime=ifShowPassCodeTime + + def data_par(self): + """ + - 字段说明 + - train_date 时间 + - train_no 列车编号,查询代码里面返回 + - stationTrainCode 列车编号 + - seatType 对应坐席 + - fromStationTelecode 起始城市 + - toStationTelecode 到达城市 + - leftTicket 查询代码里面返回 + - purpose_codes 学生还是成人 + - _json_att 没啥卵用,还是带上吧 + :return: + """ + if sys.version_info.major is 2: + new_train_date = filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" ")) + else: + new_train_date = list(filter(None, str(time.asctime(time.strptime(self.station_dates, "%Y-%m-%d"))).split(" "))) + data = OrderedDict() + data['train_date'] = "{0} {1} {2} {3} 00:00:00 GMT+0800 (中国标准时间)".format( + new_train_date[0], + new_train_date[1], + new_train_date[2] if len(new_train_date[2]) is 2 else f"0{new_train_date[2]}", + new_train_date[4], + time.strftime("%H:%M:%S", time.localtime(time.time())) + ), + data["train_no"] = self.train_no + data["stationTrainCode"] = self.stationTrainCode + data["seatType"] = self.set_type + data["fromStationTelecode"] = self.fromStationTelecode + data["toStationTelecode"] = self.toStationTelecode + data["leftTicket"] = self.leftTicket + data["purpose_codes"] = "ADULT" + data["_json_att"] = "" + return data + + def conversion_int(self, str): + return int(str) + + def sendGetQueueCountAsync(self): + """ + 请求排队接口 + :return: + """ + urls = self.session.urls["getQueueCountAsync"] + data = self.data_par() + getQueueCountAsyncResult = self.session.httpClint.send(urls, data) + if getQueueCountAsyncResult.get("status", False) and getQueueCountAsyncResult.get("data", False): + if "status" in getQueueCountAsyncResult and getQueueCountAsyncResult["status"] is True: + if "countT" in getQueueCountAsyncResult["data"]: + ticket_data = getQueueCountAsyncResult["data"]["ticket"] + ticket_split = sum(map(self.conversion_int, ticket_data.split(","))) if ticket_data.find( + ",") != -1 else ticket_data + if int(ticket_split) is 0: + # 增加余票数为0时,将车次加入小黑屋 + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + print(f"排队失败,当前余票数为{ticket_split}张") + return + print(u"排队成功, 当前余票还剩余: {0} 张".format(ticket_split)) + c = confirmSingleForQueueAsys(session=self.session, + passengerTicketStr=self.passengerTicketStr, + oldPassengerStr=self.oldPassengerStr, + result=self.result,) + print(u"验证码提交安全期,等待{}MS".format(self.ifShowPassCodeTime)) + time.sleep(self.ifShowPassCodeTime) + c.sendConfirmSingleForQueueAsys() + else: + print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountAsyncResult, self.train_no)) + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + elif "messages" in getQueueCountAsyncResult and getQueueCountAsyncResult["messages"]: + print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountAsyncResult["messages"][0], self.train_no)) + wrapcache.set(key=self.train_no, value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + else: + if "validateMessages" in getQueueCountAsyncResult and getQueueCountAsyncResult["validateMessages"]: + print(str(getQueueCountAsyncResult["validateMessages"])) + + + diff --git a/src/12306/inter/GetRandCode.py b/src/12306/inter/GetRandCode.py new file mode 100644 index 0000000..4d4034f --- /dev/null +++ b/src/12306/inter/GetRandCode.py @@ -0,0 +1,98 @@ +# coding=utf-8 +from PIL import Image + +from config.urlConf import urls +from myUrllib.httpUtils import HTTPClient +from verify.localVerifyCode import Verify +import TickerConfig +import os + + +if TickerConfig.AUTO_CODE_TYPE == 2: + v = Verify() + + +def getRandCode(is_auto_code, auto_code_type, result): + """ + 识别验证码 + :return: 坐标 + """ + try: + if is_auto_code: + if auto_code_type == 1: + print(u"打码兔已关闭, 如需使用自动识别,请使用如果平台 auto_code_type == 2") + return + elif auto_code_type == 2: + Result = v.verify(result) + return codexy(Ofset=Result, is_raw_input=False) + elif auto_code_type == 3: + print("您已设置使用云打码,但是服务器资源有限,请尽快改为本地打码" if "CAPTCHALOCAL" not in os.environ else "已设置本地打码服务器") + http = HTTPClient(0) + Result = http.send(urls.get("autoVerifyImage"), {"imageFile": result}) + if Result and Result.get("code") is 0: + return codexy(Ofset=Result.get("data"), is_raw_input=False) + else: + img = Image.open('./tkcode.png') + img.show() + return codexy() + except Exception as e: + print(e) + + +def codexy(Ofset=None, is_raw_input=True): + """ + 获取验证码 + :return: str + """ + if is_raw_input: + print(u""" + ***************** + | 1 | 2 | 3 | 4 | + ***************** + | 5 | 6 | 7 | 8 | + ***************** + """) + print(u"验证码分为8个,对应上面数字,例如第一和第二张,输入1, 2 如果开启cdn查询的话,会冲掉提示,直接鼠标点击命令行获取焦点,输入即可,不要输入空格") + print(u"如果是linux无图形界面,请使用自动打码,is_auto_code: True") + print(u"如果没有弹出验证码,请手动双击根目录下的tkcode.png文件") + Ofset = input(u"输入对应的验证码: ") + if isinstance(Ofset, list): + select = Ofset + else: + Ofset = Ofset.replace(",", ",") + select = Ofset.split(',') + post = [] + offsetsX = 0 # 选择的答案的left值,通过浏览器点击8个小图的中点得到的,这样基本没问题 + offsetsY = 0 # 选择的答案的top值 + for ofset in select: + if ofset == '1': + offsetsY = 77 + offsetsX = 40 + elif ofset == '2': + offsetsY = 77 + offsetsX = 112 + elif ofset == '3': + offsetsY = 77 + offsetsX = 184 + elif ofset == '4': + offsetsY = 77 + offsetsX = 256 + elif ofset == '5': + offsetsY = 149 + offsetsX = 40 + elif ofset == '6': + offsetsY = 149 + offsetsX = 112 + elif ofset == '7': + offsetsY = 149 + offsetsX = 184 + elif ofset == '8': + offsetsY = 149 + offsetsX = 256 + else: + pass + post.append(offsetsX) + post.append(offsetsY) + randCode = str(post).replace(']', '').replace('[', '').replace("'", '').replace(' ', '') + print(u"验证码识别坐标为{0}".format(randCode)) + return randCode diff --git a/src/12306/inter/GetRepeatSubmitToken.py b/src/12306/inter/GetRepeatSubmitToken.py new file mode 100644 index 0000000..0d49cb4 --- /dev/null +++ b/src/12306/inter/GetRepeatSubmitToken.py @@ -0,0 +1,36 @@ +# coding=utf-8 +import json +import re + + +class getRepeatSubmitToken: + def __init__(self, session): + self.session = session + + def sendGetRepeatSubmitToken(self): + """ + 获取提交车票请求token + :return: token + """ + initdc_url = self.session.urls["initdc_url"] + initdc_result = self.session.httpClint.send(initdc_url, ) + token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'") + ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?') + order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?') + token = re.search(token_name, initdc_result).group(1) + re_tfpf = re.findall(ticketInfoForPassengerForm_name, initdc_result) + re_orp = re.findall(order_request_params_name, initdc_result) + if re_tfpf: + ticketInfoForPassengerForm = json.loads(re_tfpf[0].replace("'", '"')) + else: + ticketInfoForPassengerForm = "" + if re_orp: + order_request_params = json.loads(re_orp[0].replace("'", '"')) + else: + order_request_params = "" + return { + "token": token, + "ticketInfoForPassengerForm": ticketInfoForPassengerForm, + "order_request_params": order_request_params, + "session": self.session + } \ No newline at end of file diff --git a/src/12306/inter/GetSuccessRate.py b/src/12306/inter/GetSuccessRate.py new file mode 100644 index 0000000..e5500f4 --- /dev/null +++ b/src/12306/inter/GetSuccessRate.py @@ -0,0 +1,41 @@ +from collections import OrderedDict + + +from config.urlConf import urls +import TickerConfig +from inter.SubmitOrderRequest import submitOrderRequestByAfterNate + + +class getSuccessRate: + def __init__(self, session, secretList): + """ + 获取成功信息 + """ + self.secretList = secretList + self.session = session + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["successSecret"] = f"{self.secretList}#{ticker}" + data["_json_att"] = "" + return data + + def sendSuccessRate(self): + successRateRsp = self.session.httpClint.send(urls.get("getSuccessRate"), self.data_apr()) + if not successRateRsp.get("status"): + print("".join(successRateRsp.get("messages")) or successRateRsp.get("validateMessages")) + return + flag = successRateRsp.get("data", {}).get("flag")[0] + train_no = flag.get("train_no") + print(f"准备提交候补订单,{flag.get('info')}") + submit = submitOrderRequestByAfterNate(self.session, self.secretList, train_no) + submit.sendSubmitOrderRequest() + diff --git a/src/12306/inter/LiftTicketInit.py b/src/12306/inter/LiftTicketInit.py new file mode 100644 index 0000000..fa61f18 --- /dev/null +++ b/src/12306/inter/LiftTicketInit.py @@ -0,0 +1,24 @@ +# coding=utf-8 +import re + + +class liftTicketInit: + def __init__(self, session): + self.session = session + + def reqLiftTicketInit(self): + """ + 请求抢票页面 + :return: + """ + urls = self.session.urls["left_ticket_init"] + # 获取初始化的结果 + result = self.session.httpClint.send(urls) + # 用正则表达式查出CLeftTicketUrl的值 + matchObj = re.search('var CLeftTicketUrl = \'(.*)\'', result, re.M|re.I); + if matchObj: + # 如果有值,替换queryUrl + self.session.queryUrl = matchObj.group(1) + return { + "status": True + } diff --git a/src/12306/inter/LoginAysnSuggest.py b/src/12306/inter/LoginAysnSuggest.py new file mode 100644 index 0000000..e58d7a9 --- /dev/null +++ b/src/12306/inter/LoginAysnSuggest.py @@ -0,0 +1,20 @@ +# coding=utf-8 +from config.urlConf import urls + + +def loginAysnSuggest(session, username, password): + """ + 登录接口 + ps: 不需要验证码 + :return: + """ + loginAysnSuggestUrls = urls.get("loginAysnSuggest") + data = { + "loginUserDTO.user_name": username, + "userDTO.password": password + } + loginAysnSuggestRsp = session.httpClint.send(urls=loginAysnSuggestUrls, data=data) + if loginAysnSuggestRsp and loginAysnSuggestRsp.get("httpstatus") is 200 and loginAysnSuggestRsp.get("data", {}).get("loginCheck") == "Y": + print(u"登录成功") + else: + print(u"登录失败, {0} {1}".format("".join(loginAysnSuggestRsp.get("messages")), loginAysnSuggestRsp.get("validateMessages"))) diff --git a/src/12306/inter/LoginConf.py b/src/12306/inter/LoginConf.py new file mode 100644 index 0000000..7138aac --- /dev/null +++ b/src/12306/inter/LoginConf.py @@ -0,0 +1,22 @@ +# coding=utf-8 +from config.urlConf import urls + + +def loginConf(session): + """ + 判断登录是否需要验证码 + :param session: + :return: + """ + loginConfUrl = urls.get("loginConf") + loginConfRsp = session.httpClint.send(urls=loginConfUrl, data={}) + if loginConfRsp and loginConfRsp.get("data", {}).get("is_login_passCode") == "N": + print(u"不需要验证码") + return False + else: + print(u"需要验证码") + return True + + +if __name__ == '__main__': + pass \ No newline at end of file diff --git a/src/12306/inter/PassengerInitApi.py b/src/12306/inter/PassengerInitApi.py new file mode 100644 index 0000000..50237c3 --- /dev/null +++ b/src/12306/inter/PassengerInitApi.py @@ -0,0 +1,37 @@ +import datetime +import wrapcache +import TickerConfig +from config.urlConf import urls +from inter.ConfirmHB import confirmHB + + +class passengerInitApi: + def __init__(self, session, secretList, tickerNo): + """ + 获取候补信息 + """ + self.secretList = secretList + self.tickerNo = tickerNo + self.session = session + + def sendPassengerInitApi(self): + passengerInitApiRsp = self.session.httpClint.send(urls.get("passengerInitApi")) + if not passengerInitApiRsp.get("status"): + print("".join(passengerInitApiRsp.get("messages")) or passengerInitApiRsp.get("validateMessages")) + return + data = passengerInitApiRsp.get("data", {}) + jzdhDateE = data.get("jzdhDateE") + if not data.get("jzdhHourE"): + wrapcache.set(key=f"hb{self.tickerNo}", value=datetime.datetime.now(), + timeout=TickerConfig.TICKET_BLACK_LIST_TIME * 60) + print(f"获取当前候补日期失败,原因: {data.get('jzdhHourE')}") + return + jzdhHourE = data.get("jzdhHourE").replace(":", "#") + jzdhDate = f"{jzdhDateE}#{jzdhHourE}" + print(f"当前候补日期为:{jzdhDateE} {jzdhHourE}") + confirm = confirmHB(self.secretList, self.session, self.tickerNo, jzdhDate) + confirm.sendChechFace() + + + + diff --git a/src/12306/inter/Query.py b/src/12306/inter/Query.py new file mode 100644 index 0000000..26c04ae --- /dev/null +++ b/src/12306/inter/Query.py @@ -0,0 +1,189 @@ +# coding=utf-8 +import copy +import random +import wrapcache +from config import urlConf +from config.TicketEnmu import ticket +from myUrllib.httpUtils import HTTPClient +from config.configCommon import seat_conf_2 +import TickerConfig + + +class query: + """ + 查询接口 + """ + + def __init__(self, selectObj, from_station, to_station, from_station_h, to_station_h, _station_seat, station_trains, + ticke_peoples_num, station_dates=None, ): + self.session = selectObj + self.httpClint = HTTPClient(TickerConfig.IS_PROXY) + self.httpClint.set_cookies(self.session.cookies) + self.urls = urlConf.urls + self.from_station = from_station + self.to_station = to_station + self.from_station_h = from_station_h + self.to_station_h = to_station_h + self.station_trains = station_trains + self._station_seat = _station_seat if isinstance(_station_seat, list) else list(_station_seat) + self.station_dates = station_dates if isinstance(station_dates, list) else list(station_dates) + self.ticket_black_list = dict() + self.ticke_peoples_num = ticke_peoples_num + + def station_seat(self, index): + """ + 获取车票对应坐席 + :return: + """ + seat = {'商务座': 32, + '一等座': 31, + '二等座': 30, + '特等座': 25, + '软卧': 23, + '硬卧': 28, + '硬座': 29, + '无座': 26, + '动卧': 33, + } + return seat[index] + + def check_is_need_train(self, ticket_info): + """ + 判断车次是否为想要的车次,如果ticket_info为空,那么就不校验车次,直接返回True + :param ticket_info: + :return: + """ + if self.station_dates and self.station_trains: + return ticket_info[3] in self.station_trains + else: + return True + + def sendQuery(self): + """ + 查询 + :return: + """ + if TickerConfig.IS_CDN == 1 and self.session.cdn_list: + self.httpClint.cdn = self.session.cdn_list[random.randint(4, len(self.session.cdn_list) - 1)] + for station_date in self.station_dates: + select_url = copy.copy(self.urls["select_url"]) + select_url["req_url"] = select_url["req_url"].format(station_date, self.from_station, self.to_station, + self.session.queryUrl) + station_ticket = self.httpClint.send(select_url) + value = station_ticket.get("data", "") + if not value: + print(u'{0}-{1} 车次坐席查询为空,查询url: https://kyfw.12306.cn{2}, 可以手动查询是否有票'.format( + self.from_station_h, + self.to_station_h, + select_url["req_url"])) + else: + result = value.get('result', []) + if result: + for i in value['result']: + ticket_info = i.split('|') + if self.session.flag: + print(f"车次:{ticket_info[3]} 出发站:{self.from_station_h} 到达站:{self.to_station_h} 历时:{ticket_info[10]}" + f" 商务/特等座:{ticket_info[32] or '--'}" + f" 一等座:{ticket_info[31] or '--'}" + f" 二等座:{ticket_info[30] or '--'}" + f" 动卧:{ticket_info[33] or '--'}" + f" 硬卧:{ticket_info[28] or '--'}" + f" 软座:{ticket_info[23] or '--'}" + f" 硬座:{ticket_info[29] or '--'}" + f" 无座:{ticket_info[26] or '--'}" + f" {ticket_info[1] or '--'}") + if ticket_info[1] == "预订" and self.check_is_need_train(ticket_info): # 筛选未在开始时间内的车次 + for j in self._station_seat: + is_ticket_pass = ticket_info[j] + if ticket_info[11] == "Y": + if is_ticket_pass != '' and is_ticket_pass != '无' and is_ticket_pass != '*': # 过滤有效目标车次 + secretStr = ticket_info[0] + train_no = ticket_info[2] + query_from_station_name = ticket_info[6] + query_to_station_name = ticket_info[7] + train_location = ticket_info[15] + stationTrainCode = ticket_info[3] + leftTicket = ticket_info[12] + start_time = ticket_info[8] + arrival_time = ticket_info[9] + distance_time = ticket_info[10] + print(start_time, arrival_time, distance_time) + seat = j + try: + ticket_num = int(ticket_info[j]) + except ValueError: + ticket_num = "有" + print(u'车次: {0} 始发车站: {1} 终点站: {2} {3}: {4}'.format(ticket_info[3], + self.from_station_h, + self.to_station_h, + seat_conf_2[j], + ticket_num)) + if seat_conf_2[j] == "无座" and ticket_info[3][0] in ["G", "D", "C"]: + seat = 30 # GD开头的无座直接强制改为二等座车次 + if wrapcache.get(train_no): + print(ticket.QUERY_IN_BLACK_LIST.format(train_no)) + continue + else: + if ticket_num != "有" and self.ticke_peoples_num > ticket_num: + if TickerConfig.IS_MORE_TICKET: + print( + u"余票数小于乘车人数,当前余票数: {}, 删减人车人数到: {}".format(ticket_num, ticket_num)) + is_more_ticket_num = ticket_num + else: + print(u"余票数小于乘车人数,当前设置不提交,放弃此次提交机会") + continue + else: + print(u"设置乘车人数为: {}".format(self.ticke_peoples_num)) + is_more_ticket_num = self.ticke_peoples_num + print(ticket.QUERY_C) + return { + "secretStr": secretStr, + "train_no": train_no, + "stationTrainCode": stationTrainCode, + "train_date": station_date, + "query_from_station_name": query_from_station_name, + "query_to_station_name": query_to_station_name, + "seat": seat, + "leftTicket": leftTicket, + "train_location": train_location, + "code": ticket.SUCCESS_CODE, + "is_more_ticket_num": is_more_ticket_num, + "cdn": self.httpClint.cdn, + "status": True, + } + elif is_ticket_pass == '无' and ticket_info[37] == "1" and TickerConfig.TICKET_TYPE is 2: + """ + is_ticket_pass如果有别的显示,但是可以候补,可以提issues提出来,附上query log,我将添加上 + 判断车次是否可以候补 + 目前的候补机制是只要一有候补位置,立马提交候补 + """ + # 如果最后一位为1,则是可以候补的,不知道这些正确嘛? + nate = list(ticket_info[38]) + if wrapcache.get(f"hb{ticket_info[2]}"): + continue + for set_type in TickerConfig.SET_TYPE: + if TickerConfig.PASSENGER_TICKER_STR[set_type] not in nate: + if ticket_info[3][0] in ["G", "D", "C"] and set_type in ["一等座", "特等座", "二等座", "商务座", "无座"]: + return { + "secretList": ticket_info[0], + "seat": [set_type], + "train_no": ticket_info[2], + "status": True, + "cdn": self.httpClint.cdn, + } + elif ticket_info[3][0] in ["T", "Z", "K"] and set_type in ["硬卧", "硬座", "无座", "软座", "软卧"]: + return { + "secretList": ticket_info[0], + "seat": [set_type], + "train_no": ticket_info[2], + "status": True, + "cdn": self.httpClint.cdn, + } + else: + print(u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)) + self.session.flag = False + return {"code": ticket.FAIL_CODE, "status": False, "cdn": self.httpClint.cdn, } + + +if __name__ == "__main__": + q = query() diff --git a/src/12306/inter/QueryOrderWaitTime.py b/src/12306/inter/QueryOrderWaitTime.py new file mode 100644 index 0000000..ca63c18 --- /dev/null +++ b/src/12306/inter/QueryOrderWaitTime.py @@ -0,0 +1,125 @@ +# coding=utf-8 +import copy +import time + +from config.TicketEnmu import ticket +from config.emailConf import sendEmail +from config.serverchanConf import sendServerChan +from myException.ticketIsExitsException import ticketIsExitsException +from myException.ticketNumOutException import ticketNumOutException + + +class queryOrderWaitTime: + """ + 排队 + """ + + def __init__(self, session): + self.session = session + + def sendQueryOrderWaitTime(self): + """ + 排队获取订单等待信息,每隔3秒请求一次,最高请求次数为20次! + :return: + """ + num = 1 + while True: + num += 1 + if num > ticket.OUT_NUM: + print(ticket.WAIT_OUT_NUM) + order_id = self.queryMyOrderNoComplete() # 排队失败,自动取消排队订单 + if order_id: + self.cancelNoCompleteMyOrder(order_id) + break + try: + queryOrderWaitTimeUrl = copy.deepcopy(self.session.urls["queryOrderWaitTimeUrl"]) + queryOrderWaitTimeUrl["req_url"] = queryOrderWaitTimeUrl["req_url"].format(int(round(time.time() * 1000))) + queryOrderWaitTimeResult = self.session.httpClint.send(queryOrderWaitTimeUrl) + except ValueError: + queryOrderWaitTimeResult = {} + if queryOrderWaitTimeResult: + if queryOrderWaitTimeResult.get("status", False): + data = queryOrderWaitTimeResult.get("data", False) + if data and data.get("orderId", ""): + sendEmail(ticket.WAIT_ORDER_SUCCESS.format( + data.get("orderId", ""))) + sendServerChan(ticket.WAIT_ORDER_SUCCESS.format( + data.get("orderId", ""))) + raise ticketIsExitsException(ticket.WAIT_ORDER_SUCCESS.format( + data.get("orderId"))) + elif data.get("msg", False): + print(data.get("msg", "")) + break + elif data.get("waitTime", False): + print(ticket.WAIT_ORDER_CONTINUE.format(0 - data.get("waitTime", False))) + else: + pass + elif queryOrderWaitTimeResult.get("messages", False): + print(ticket.WAIT_ORDER_FAIL.format(queryOrderWaitTimeResult.get("messages", ""))) + else: + print(ticket.WAIT_ORDER_NUM.format(num + 1)) + else: + pass + time.sleep(2) + else: + print(ticketNumOutException(ticket.WAIT_ORDER_SUB_FAIL)) + + def queryMyOrderNoComplete(self): + """ + 获取订单列表信息 + :return: + """ + self.initNoComplete() + queryMyOrderNoCompleteUrl = self.session.urls["queryMyOrderNoCompleteUrl"] + data = {"_json_att": ""} + try: + queryMyOrderNoCompleteResult = self.session.httpClint.send(queryMyOrderNoCompleteUrl, data) + except ValueError: + queryMyOrderNoCompleteResult = {} + if queryMyOrderNoCompleteResult: + if queryMyOrderNoCompleteResult.get("data", False) and queryMyOrderNoCompleteResult["data"].get("orderDBList", False): + return queryMyOrderNoCompleteResult["data"] + elif queryMyOrderNoCompleteResult.get("data", False) and queryMyOrderNoCompleteResult["data"].get("orderCacheDTO", False): + if queryMyOrderNoCompleteResult["data"]["orderCacheDTO"].get("message", False): + print(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) + raise ticketNumOutException( + queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) + else: + if queryMyOrderNoCompleteResult.get("message", False): + print(queryMyOrderNoCompleteResult.get("message", False)) + return False + else: + return False + else: + return False + + def initNoComplete(self): + """ + 获取订单前需要进入订单列表页,获取订单列表页session + :return: + """ + initNoCompleteUrl = self.session.urls["initNoCompleteUrl"] + data = {"_json_att": ""} + self.session.httpClint.send(initNoCompleteUrl, data) + + def cancelNoCompleteMyOrder(self, sequence_no): + """ + 取消订单 + :param sequence_no: 订单编号 + :return: + """ + cancelNoCompleteMyOrderUrl = self.session.urls["cancelNoCompleteMyOrder"] + cancelNoCompleteMyOrderData = { + "sequence_no": sequence_no, + "cancel_flag": "cancel_order", + "_json_att": "" + } + cancelNoCompleteMyOrderResult = self.session.httpClint.send(cancelNoCompleteMyOrderUrl, + cancelNoCompleteMyOrderData) + if cancelNoCompleteMyOrderResult.get("data", False) and cancelNoCompleteMyOrderResult["data"].get("existError", "N"): + print(ticket.CANCEL_ORDER_SUCCESS.format(sequence_no)) + time.sleep(2) + return True + else: + print(ticket.CANCEL_ORDER_FAIL.format(sequence_no)) + return False diff --git a/src/12306/inter/SubmitOrderRequest.py b/src/12306/inter/SubmitOrderRequest.py new file mode 100644 index 0000000..ec64d76 --- /dev/null +++ b/src/12306/inter/SubmitOrderRequest.py @@ -0,0 +1,111 @@ +# coding=utf-8 +import datetime +import urllib +from collections import OrderedDict +import TickerConfig +from config.urlConf import urls +from inter.CheckOrderInfo import checkOrderInfo +from inter.ConfirmHB import confirmHB +from inter.PassengerInitApi import passengerInitApi +from myException.ticketIsExitsException import ticketIsExitsException + + +def time(): + """ + 获取日期 + :return: + """ + today = datetime.date.today() + return today.strftime('%Y-%m-%d') + + +class submitOrderRequest: + def __init__(self, selectObj, secretStr, from_station, to_station, train_no, set_type, + passengerTicketStrList, oldPassengerStr, train_date, ticke_peoples): + self.session = selectObj + # self.secretStr = secretStr + try: + self.secretStr = urllib.unquote(secretStr) + except AttributeError: + self.secretStr = urllib.parse.unquote(secretStr) + self.from_station = from_station + self.to_station = to_station + self.to_station = to_station + self.train_no = train_no + self.set_type = set_type + self.passengerTicketStrList = passengerTicketStrList + self.oldPassengerStr = oldPassengerStr + self.train_date = train_date + self.ticke_peoples = ticke_peoples + + def data_apr(self): + """ + :return: + """ + data = [('secretStr', self.secretStr), # 字符串加密 + ('train_date', self.train_date), # 出发时间 + ('back_train_date', time()), # 返程时间 + ('tour_flag', 'dc'), # 旅途类型 + ('purpose_codes', 'ADULT'), # 成人票还是学生票 + ('query_from_station_name', TickerConfig.FROM_STATION), # 起始车站 + ('query_to_station_name', TickerConfig.TO_STATION), # 终点车站 + ('undefined', ''), + ] + return data + + def sendSubmitOrderRequest(self): + """ + 提交车次 + 预定的请求参数,注意参数顺序 + 注意这里为了防止secretStr被urllib.parse过度编码,在这里进行一次解码 + 否则调用HttpTester类的post方法将会将secretStr编码成为无效码,造成提交预定请求失败 + :param secretStr: 提交车次加密 + :return: + """ + submit_station_url = self.session.urls["submit_station_url"] + submitResult = self.session.httpClint.send(submit_station_url, self.data_apr()) + if 'data' in submitResult and submitResult['data']: + if submitResult['data'] == 'N': + coi = checkOrderInfo(self.session, self.train_no, self.set_type, self.passengerTicketStrList, + self.oldPassengerStr, + self.train_date, self.ticke_peoples) + coi.sendCheckOrderInfo() + else: + print (u'出票失败') + elif 'messages' in submitResult and submitResult['messages']: + raise ticketIsExitsException(submitResult['messages'][0]) + + +class submitOrderRequestByAfterNate: + def __init__(self, session, secretList, tickerNo): + """ + 提交候补订单 + :param secretList: + :param session: + """ + self.secretList = secretList + self.session = session + self.tickerNo = tickerNo + + def data_apr(self): + """ + secretList 9vqa9%2B%2F%2Fsdozmm22hpSeDTGqRUwSuA2D0r%2BmU%2BLZj7MK7CDuf5Ep1xpxl4Dyxfmoah%2BaB9TZSesU%0AkxBbo5oNgR1vqMfvq66VP0T7tpQtH%2BbVGBz1FolZG8jDD%2FHqnz%2FnvdBP416Og6WGS14O%2F3iBSwT8%0AkRPsNF0Vq0U082g0tlJtP%2BPn7TzW3z7TDCceMJIjFcfEOA%2BW%2BuK%2Bpy6jCQMv0TmlkXf5aKcGnE02%0APuv4I8nF%2BOWjWzv9CrJyiCZiWaXd%2Bi7p69V3a9dhF787UgS660%2BqKRFB4RLwAfic3MkAlfpGWhMY%0ACfARVQ%3D%3D#O| + _json_att + 候补一次只能补一个座位,默认取TICKET_TYPE第一个 + :return: + """ + + ticker = TickerConfig.PASSENGER_TICKER_STR.get(TickerConfig.SET_TYPE[0]) + data = OrderedDict() + data["secretList"] = f"{self.secretList}#{ticker}|" + data["_json_att"] = "" + return data + + def sendSubmitOrderRequest(self, ): + submitOrderRequestRsp = self.session.httpClint.send(urls.get("SubmitOrderRequestRsp"), self.data_apr()) + if not submitOrderRequestRsp.get("status") or not submitOrderRequestRsp.get("data", {}).get("flag"): + print("".join(submitOrderRequestRsp.get("messages")) or submitOrderRequestRsp.get("validateMessages")) + return + pApi = passengerInitApi(self.session, self.secretList, self.tickerNo) + pApi.sendPassengerInitApi() + diff --git a/src/12306/inter/__init__.py b/src/12306/inter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/model.v2.0.h5 b/src/12306/model.v2.0.h5 new file mode 100644 index 0000000..25611fe Binary files /dev/null and b/src/12306/model.v2.0.h5 differ diff --git a/src/12306/myException/PassengerUserException.py b/src/12306/myException/PassengerUserException.py new file mode 100644 index 0000000..2eafa33 --- /dev/null +++ b/src/12306/myException/PassengerUserException.py @@ -0,0 +1,2 @@ +class PassengerUserException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myException/UserPasswordException.py b/src/12306/myException/UserPasswordException.py new file mode 100644 index 0000000..290b47f --- /dev/null +++ b/src/12306/myException/UserPasswordException.py @@ -0,0 +1,2 @@ +class UserPasswordException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myException/__init__.py b/src/12306/myException/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/myException/balanceException.py b/src/12306/myException/balanceException.py new file mode 100644 index 0000000..2f878d0 --- /dev/null +++ b/src/12306/myException/balanceException.py @@ -0,0 +1,2 @@ +class balanceException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myException/ticketConfigException.py b/src/12306/myException/ticketConfigException.py new file mode 100644 index 0000000..c652bca --- /dev/null +++ b/src/12306/myException/ticketConfigException.py @@ -0,0 +1,2 @@ +class ticketConfigException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myException/ticketIsExitsException.py b/src/12306/myException/ticketIsExitsException.py new file mode 100644 index 0000000..7f722fd --- /dev/null +++ b/src/12306/myException/ticketIsExitsException.py @@ -0,0 +1,2 @@ +class ticketIsExitsException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myException/ticketNumOutException.py b/src/12306/myException/ticketNumOutException.py new file mode 100644 index 0000000..ada7699 --- /dev/null +++ b/src/12306/myException/ticketNumOutException.py @@ -0,0 +1,2 @@ +class ticketNumOutException(Exception): + pass \ No newline at end of file diff --git a/src/12306/myUrllib/MySocketUtils.py b/src/12306/myUrllib/MySocketUtils.py new file mode 100644 index 0000000..b61b69e --- /dev/null +++ b/src/12306/myUrllib/MySocketUtils.py @@ -0,0 +1,202 @@ +# coding=utf-8 +import json +import socket +import re +# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# s.connect(('183.232.189.31', 80)) +# get_str = 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \ +# 'Host: %s\r\n' \ +# 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \ +# '\r\nAccept: */*\r\n' \ +# '\r\n' +# post_str = "POST {0} HTTP/1.1\r\n" \ +# "Host: kyfw.12306.cn\r\n" \ +# "Connection: close\r\n"\ +# "Origin: https://kyfw.12306.cn\r\n" \ +# "X-Requested-With: XMLHttpRequest\r\n" \ +# "Referer: https://kyfw.12306.cn/otn/leftTicket/init\r\n" \ +# "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n" \ +# "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" \ +# "Accept: application/json, text/javascript, */*; q=0.01\r\n" \ +# "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5\r\n" \ +# "Content-Length: 9\r\n"\ +# "Cookie: _passport_session=a459aba69761497eb31de76c27795e999613; _passport_ct=9116b2cb0bf443e1a01d22ac8c1ae449t5007; route=9036359bb8a8a461c164a04f8f50b252; BIGipServerpool_passport=200081930.50215.0000; BIGipServerotn=484704778.64545.0000\r\n\n"\ +# "appid=otn\r\n" +# # s.sendall(get_str.format("https://kyfw.12306.cn/otn/resources/login.html")) +# s.sendall(post_str.format("https://kyfw.12306.cn/passport/web/auth/uamtk")) +from config.urlConf import urls + + +def default_get_data(): + """ + get请求默认组装字符串 + 需要拼接的字符串 + -- url 发送请求的全连接 + :return: + """ + return 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \ + 'Host: kyfw.12306.cn\r\n' \ + "Referer: {1}\r\n" \ + 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \ + '\r\nAccept: */*\r\n' \ + "Cookie: {2}\r\n\n"\ + '\r\n' + # return 'GET {0} HTTP/1.1\r\nConnection: close\r\n' \ + # 'Host: kyfw.12306.cn\r\n' \ + # 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36' \ + # '\r\nAccept: */*\r\n' \ + # '\r\n' + + +def default_post_data(): + """ + post请求默认组装字符串 + 需要拼接的字符串 + -- url 发送请求的全连接 + -- Referer 请求页面来源 + -- Content-Length: body 长度 + -- Cookie 页面请求的身份认证 + -- appid 接口请求报文 + :return: + """ + return "POST https://kyfw.12306.cn{0} HTTP/1.1\r\n" \ + "Host: kyfw.12306.cn\r\n" \ + "Connection: close\r\n"\ + "Origin: https://kyfw.12306.cn\r\n" \ + "X-Requested-With: XMLHttpRequest\r\n" \ + "Referer: {3}\r\n" \ + "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n" \ + "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" \ + "Accept: application/json, text/javascript, */*; q=0.01\r\n" \ + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5\r\n" \ + "Content-Length: {2}\r\n"\ + "Cookie: {4}\r\n\n"\ + "{1}\r\n"\ + # "\r\n" + + +class socketUtils: + def __init__(self, host, port=80): + self.host = host + self.port = port + self.s = self.connect_socket(self.host, self.port) + + def connect_socket(self, host, port): + """ + 连接socket + :param host: + :param port: + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((host if isinstance(host, str) else str(host), + port if isinstance(port, int) else int(port))) + return s + + def close_s(self): + self.s.close() + + # def send(self, urls, Cookie=None, data=None): + # """ + # 发送请求 + # :param urls: + # :param data: + # :param cookie: + # :return: + # """ + # url = urls.get("req_url", "") + # Referer = urls.get("Referer", "") + # if urls.get("req_type", "get") == "post": + # Content_Length = len(data) + # Cookie = "tk=pnidlCoFy2B7wxO_X_pESbrkZFSq3OtVA_xzXwuba2a0; JSESSIONID=C6144324BFCE36AC5082E543E934E8B3; current_captcha_type=Z; _jc_save_fromDate=2018-08-03; _jc_save_fromStation=%u6DF1%u5733%2CSZQ; _jc_save_toDate=2018-08-03; _jc_save_toStation=%u957F%u6C99%2CCSQ; _jc_save_wfdc_flag=dc; ten_key=b5L6aMWfnzBm8CgQe8pcAKQsmVBS2PYH; BIGipServerpool_passport=166527498.50215.0000; BIGipServerotn=165937674.50210.0000; route=c5c62a339e7744272a54643b3be5bf64; RAIL_DEVICEID=fC-yepiUqNjsBiRvtLBXW4JqQmabCfB9QxI3FifJZK9YDRsImhJLSz4sAQ4HiGF7uQAFdFyISg6jA7KAhtpEldJV9ZMNsn6Dzm_psA5CBDwSNfiORf42w-LIRvkeGvdKFtegZwWGlkA2fVuEWKu-1xAYdCXRnsMD; RAIL_EXPIRATION=1533420302032; _jc_save_detail=true" + # if data: + # send_value = default_post_data().format(url, + # data, + # Content_Length, + # Referer, + # Cookie + # ) + # print("send_value: " + send_value) + # self.s.sendall(send_value) + # else: + # self.s.sendall(default_get_data().format(url, + # Referer, + # Cookie)) + # total_data = "" + # while 1: + # data = self.s.recv(1024) + # total_data += data + # if not data: + # break + # self.close_s() + # print(total_data) + # return self.recv_data(total_data) + + def recv_data(self, r_data): + cookie = self.get_cookie(r_data) + status_code = self.get_status_code(r_data) + r_body = self.get_rep_body(r_data) + return { + "cookie": cookie, + "status_code": status_code, + "r_body": r_body + } + + @staticmethod + def get_cookie(recv_data): + """ + 提取cookie + :param recv_data: + :return: + """ + if not isinstance(recv_data, str): + recv_data = str(recv_data) + cookies_re = re.compile(r"Set-Cookie: (\S+);") + cookies = re.findall(cookies_re, recv_data) + return "; ".join(cookies) + + @staticmethod + def get_status_code(recv_data): + """ + 获取状态码 + :return: + """ + if not isinstance(recv_data, str): + recv_data = str(recv_data) + http_code_re = re.compile(r"HTTP/1.1 (\S+) ") + status_code = re.search(http_code_re, recv_data).group(1) + return status_code + + @staticmethod + def get_rep_body(recv_data): + """ + 获取返回值 + :param recv_data: + :return: + """ + if not isinstance(recv_data, str): + recv_data = str(recv_data) + if recv_data.find("{") != -1 and recv_data.find("}") != -1: + data = json.loads(recv_data.split("\n")[-1]) + return data + else: + print(recv_data) + + +if __name__ == "__main__": + so = socketUtils('183.232.189.31', 80) + train_date = "2018-08-03" + from_station = "SZQ" + to_station = "CSQ" + urls["select_url"]["req_url"] = "https://kyfw.12306.cn" + urls["select_url"]["req_url"].format(train_date, from_station, to_station) + result = so.send(urls=urls["select_url"]) + print(result) + + so = socketUtils('183.232.189.31', 80) + + data = "secretStr=Vgo534nDZiCH8NCvyEPcGepzJoRCjvYr34gKFv5CW1K1XtM6mtKHoiFPjUYvaVKoe06SMhUUpT%2FK%0AxIEIsBD4zHgJPpVyKiTPx80y6OCWhNgcKjib2LLMXMJfgTgh0RKPISjkDjVFmO9p905O%2FegDeKjp%0A1fhIeqCuYraHjNhI0PjQY39BAY4AHLzW0iGgDq8b%2FtpyOY8Td2XfIWNZJCWzgyPkNXOk0HUguB2G%0AKh2T8nlko6zb5ra%2B%2BA%3D%3D&train_date=2018-08-03&back_train_date=2018-08-03&tour_flag=dc&purpose_codes=ADULT&query_from_station_name=深圳&query_to_station_name=长沙&undefined" + result1 = so.send(urls=urls["submit_station_url"], data=data) + print(result1) + # so = socketUtils('183.232.189.31', 80) + # result = so.send(url="https://kyfw.12306.cn/passport/web/login", s_data="") + # print(result) \ No newline at end of file diff --git a/src/12306/myUrllib/__init__.py b/src/12306/myUrllib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/myUrllib/httpUtils.py b/src/12306/myUrllib/httpUtils.py new file mode 100644 index 0000000..77b2318 --- /dev/null +++ b/src/12306/myUrllib/httpUtils.py @@ -0,0 +1,204 @@ +# -*- coding: utf8 -*- +import json +import random +import socket +from collections import OrderedDict +from time import sleep +import requests +from fake_useragent import UserAgent +import TickerConfig +from agency.agency_tools import proxy +from config import logger + + +def _set_header_default(): + header_dict = OrderedDict() + # header_dict["Accept"] = "application/json, text/plain, */*" + header_dict["Accept-Encoding"] = "gzip, deflate" + header_dict[ + "User-Agent"] = _set_user_agent() + header_dict["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8" + header_dict["Origin"] = "https://kyfw.12306.cn" + header_dict["Connection"] = "keep-alive" + return header_dict + + +def _set_user_agent(): + # try: + # user_agent = UserAgent(verify_ssl=False).random + # return user_agent + # except: + # print("请求头设置失败,使用默认请求头") + # return 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.' + str( + # random.randint(5000, 7000)) + '.0 Safari/537.36' + return "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + + +class HTTPClient(object): + + def __init__(self, is_proxy, cdnList=None): + """ + cdnList试试切换不包括查询的cdn,防止查询cdn污染登陆和下单cdn + :param method: + :param headers: Must be a dict. Such as headers={'Content_Type':'text/html'} + """ + self.initS() + self._cdn = None + self.cdnList = cdnList + self._proxies = None + if is_proxy is 1: + self.proxy = proxy() + self._proxies = self.proxy.setProxy() + # print(u"设置当前代理ip为 {}, 请注意代理ip是否可用!!!!!请注意代理ip是否可用!!!!!请注意代理ip是否可用!!!!!".format(self._proxies)) + + def initS(self): + self._s = requests.Session() + self._s.headers.update(_set_header_default()) + return self + + def set_cookies(self, kwargs): + """ + 设置cookies + :param kwargs: + :return: + """ + for kwarg in kwargs: + for k, v in kwarg.items(): + self._s.cookies.set(k, v) + + def get_cookies(self): + """ + 获取cookies + :return: + """ + return self._s.cookies.values() + + def del_cookies(self): + """ + 删除所有的key + :return: + """ + self._s.cookies.clear() + + def del_cookies_by_key(self, key): + """ + 删除指定key的session + :return: + """ + self._s.cookies.set(key, None) + + def setHeaders(self, headers): + self._s.headers.update(headers) + return self + + def resetHeaders(self): + self._s.headers.clear() + self._s.headers.update(_set_header_default()) + + def getHeadersHost(self): + return self._s.headers["Host"] + + def setHeadersHost(self, host): + self._s.headers.update({"Host": host}) + return self + + def setHeadersUserAgent(self): + self._s.headers.update({"User-Agent": _set_user_agent()}) + + def getHeadersUserAgent(self): + return self._s.headers["User-Agent"] + + def getHeadersReferer(self): + return self._s.headers["Referer"] + + def setHeadersReferer(self, referer): + self._s.headers.update({"Referer": referer}) + return self + + @property + def cdn(self): + return self._cdn + + @cdn.setter + def cdn(self, cdn): + self._cdn = cdn + + def send(self, urls, data=None, **kwargs): + """send request to url.If response 200,return response, else return None.""" + allow_redirects = False + is_logger = urls.get("is_logger", False) + req_url = urls.get("req_url", "") + re_try = urls.get("re_try", 0) + s_time = urls.get("s_time", 0) + is_cdn = urls.get("is_cdn", False) + is_test_cdn = urls.get("is_test_cdn", False) + error_data = {"code": 99999, "message": u"重试次数达到上限"} + if data: + method = "post" + self.setHeaders({"Content-Length": "{0}".format(len(data))}) + else: + method = "get" + self.resetHeaders() + if TickerConfig.RANDOM_AGENT is 1: + self.setHeadersUserAgent() + self.setHeadersReferer(urls["Referer"]) + if is_logger: + logger.log( + u"url: {0}\n入参: {1}\n请求方式: {2}\n".format(req_url, data, method)) + self.setHeadersHost(urls["Host"]) + if is_test_cdn: + url_host = self._cdn + elif is_cdn: + if self._cdn: + # print(u"当前请求cdn为{}".format(self._cdn)) + url_host = self._cdn + else: + url_host = urls["Host"] + else: + url_host = urls["Host"] + http = urls.get("httpType") or "https" + for i in range(re_try): + try: + # sleep(urls["s_time"]) if "s_time" in urls else sleep(0.001) + sleep(s_time) + try: + requests.packages.urllib3.disable_warnings() + except: + pass + response = self._s.request(method=method, + timeout=5, + proxies=self._proxies, + url=http + "://" + url_host + req_url, + data=data, + allow_redirects=allow_redirects, + verify=False, + **kwargs) + if response.status_code == 200 or response.status_code == 302: + if urls.get("not_decode", False): + return response.content + if response.content: + if is_logger: + logger.log( + u"出参:{0}".format(response.content.decode())) + if urls["is_json"]: + return json.loads( + response.content.decode() if isinstance(response.content, bytes) else response.content) + else: + return response.content.decode("utf8", "ignore") if isinstance(response.content, + bytes) else response.content + else: + print(f"url: {urls['req_url']}返回参数为空, 接口状态码: {response.status_code}") + + logger.log( + u"url: {} 返回参数为空".format(urls["req_url"])) + if self.cdnList: + # 如果下单或者登陆出现cdn 302的情况,立马切换cdn + url_host = self.cdnList.pop(random.randint(0, 4)) + continue + else: + sleep(urls["re_time"]) + except (requests.exceptions.Timeout, requests.exceptions.ReadTimeout, requests.exceptions.ConnectionError): + pass + except socket.error: + pass + return error_data diff --git a/src/12306/requirements-docker37.txt b/src/12306/requirements-docker37.txt new file mode 100644 index 0000000..fc6babf --- /dev/null +++ b/src/12306/requirements-docker37.txt @@ -0,0 +1,7 @@ +bs4==0.0.1 +requests==2.18.4 +Pillow +wrapcache==1.0.8 +ntplib==0.3.3 +selenium==3.11.0 +fake-useragent==0.1.11 \ No newline at end of file diff --git a/src/12306/requirements.txt b/src/12306/requirements.txt new file mode 100644 index 0000000..d4c2d62 --- /dev/null +++ b/src/12306/requirements.txt @@ -0,0 +1,15 @@ +beautifulsoup4==4.5.3 +bs4==0.0.1 +requests==2.18.4 +Pillow +wrapcache==1.0.8 +ntplib==0.3.3 +sklearn +opencv-python +keras==2.2.4 +tensorflow==1.14.0 +matplotlib>=3.0.2 +numpy>=1.14.6 +scipy>=1.1.0 +selenium==3.11.0 +fake-useragent==0.1.11 \ No newline at end of file diff --git a/src/12306/run.py b/src/12306/run.py new file mode 100644 index 0000000..8046362 --- /dev/null +++ b/src/12306/run.py @@ -0,0 +1,31 @@ +# -*- coding=utf-8 -*- +import argparse +import sys + + +def parser_arguments(argv): + """ + 不应该在这里定义,先放在这里 + :param argv: + :return: + """ + parser = argparse.ArgumentParser() + parser.add_argument("operate", type=str, help="r: 运行抢票程序, c: 过滤cdn, t: 测试邮箱和server酱,server酱需要打开开关") + + return parser.parse_args(argv) + + +if __name__ == '__main__': + args = parser_arguments(sys.argv[1:]) + if args.operate == "r": + from init import select_ticket_info + select_ticket_info.select().main() + elif args.operate == "t": + from config.emailConf import sendEmail + from config.serverchanConf import sendServerChan + sendEmail(u"订票小助手测试一下") + sendServerChan("订票小助手测试一下") + elif args.operate == "c": + from agency.cdn_utils import filterCdn + filterCdn() + diff --git a/src/12306/station_name.txt b/src/12306/station_name.txt new file mode 100644 index 0000000..3a282a7 --- /dev/null +++ b/src/12306/station_name.txt @@ -0,0 +1 @@ +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@gzn|广州南|IZQ|guangzhounan|gzn|5@cqb|重庆北|CUW|chongqingbei|cqb|6@cqi|重庆|CQW|chongqing|cq|7@cqn|重庆南|CRW|chongqingnan|cqn|8@cqx|重庆西|CXW|chongqingxi|cqx|9@gzd|广州东|GGQ|guangzhoudong|gzd|10@sha|上海|SHH|shanghai|sh|11@shn|上海南|SNH|shanghainan|shn|12@shq|上海虹桥|AOH|shanghaihongqiao|shhq|13@shx|上海西|SXH|shanghaixi|shx|14@tjb|天津北|TBP|tianjinbei|tjb|15@tji|天津|TJP|tianjin|tj|16@tjn|天津南|TIP|tianjinnan|tjn|17@tjx|天津西|TXP|tianjinxi|tjx|18@xgl|香港西九龙|XJA|hkwestkowloon|xgxjl|19@cch|长春|CCT|changchun|cc|20@ccn|长春南|CET|changchunnan|ccn|21@ccx|长春西|CRT|changchunxi|ccx|22@cdd|成都东|ICW|chengdudong|cdd|23@cdn|成都南|CNW|chengdunan|cdn|24@cdu|成都|CDW|chengdu|cd|25@cdx|成都西|CMW|chengduxi|cdx|26@csh|长沙|CSQ|changsha|cs|27@csn|长沙南|CWQ|changshanan|csn|28@dmh|大明湖|JAK|daminghu|dmh|29@fzh|福州|FZS|fuzhou|fz|30@fzn|福州南|FYS|fuzhounan|fzn|31@gya|贵阳|GIW|guiyang|gy|32@gzh|广州|GZQ|guangzhou|gz|33@gzx|广州西|GXQ|guangzhouxi|gzx|34@heb|哈尔滨|HBB|haerbin|heb|35@hed|哈尔滨东|VBB|haerbindong|hebd|36@hex|哈尔滨西|VAB|haerbinxi|hebx|37@hfe|合肥|HFH|hefei|hf|38@hhd|呼和浩特东|NDC|huhehaotedong|hhhtd|39@hht|呼和浩特|HHC|huhehaote|hhht|40@hkd|海口东|HMQ|haikoudong|hkd|42@hko|海口|VUQ|haikou|hk|43@hzd|杭州东|HGH|hangzhoudong|hzd|44@hzh|杭州|HZH|hangzhou|hz|45@hzn|杭州南|XHH|hangzhounan|hzn|46@jna|济南|JNK|jinan|jn|47@jna|济 南|EEI|jinan|jn|48@jnx|济南西|JGK|jinanxi|jnx|49@jnx|济 南西|EII|jinanxi|jnx|50@kmi|昆明|KMM|kunming|km|51@kmx|昆明西|KXM|kunmingxi|kmx|52@lsa|拉萨|LSO|lasa|ls|53@lzd|兰州东|LVJ|lanzhoudong|lzd|54@lzh|兰州|LZJ|lanzhou|lz|55@lzx|兰州西|LAJ|lanzhouxi|lzx|56@nch|南昌|NCG|nanchang|nc|57@nji|南京|NJH|nanjing|nj|58@njn|南京南|NKH|nanjingnan|njn|59@nni|南宁|NNZ|nanning|nn|60@sjb|石家庄北|VVP|shijiazhuangbei|sjzb|61@sjz|石家庄|SJP|shijiazhuang|sjz|62@ssd|蜀山东|HTH|shushandong|ssd|63@sya|沈阳|SYT|shenyang|sy|64@syb|沈阳北|SBT|shenyangbei|syb|65@syd|沈阳东|SDT|shenyangdong|syd|66@syn|沈阳南|SOT|shenyangnan|syn|67@tyb|太原北|TBV|taiyuanbei|tyb|68@tyd|太原东|TDV|taiyuandong|tyd|69@tyu|太原|TYV|taiyuan|ty|70@wha|武汉|WHN|wuhan|wh|71@wjx|王家营西|KNM|wangjiayingxi|wjyx|72@wlq|乌鲁木齐|WAR|wulumuqi|wlmq|73@xab|西安北|EAY|xianbei|xab|74@xan|西安|XAY|xian|xa|75@xan|西安南|CAY|xiannan|xan|76@xni|西宁|XNO|xining|xn|77@ych|银川|YIJ|yinchuan|yc|78@zzh|郑州|ZZF|zhengzhou|zz|79@aes|阿尔山|ART|aershan|aes|80@aka|安康|AKY|ankang|ak|81@aks|阿克苏|ASR|akesu|aks|82@alh|阿里河|AHX|alihe|alh|83@alk|阿拉山口|AKR|alashankou|alsk|84@api|安平|APT|anping|ap|85@aqi|安庆|AQH|anqing|aq|86@ash|安顺|ASW|anshun|as|87@ash|鞍山|AST|anshan|as|88@aya|安阳|AYF|anyang|ay|89@ban|北安|BAB|beian|ba|90@bbu|蚌埠|BBH|bengbu|bb|91@bch|白城|BCT|baicheng|bc|92@bha|北海|BHZ|beihai|bh|93@bhe|白河|BEL|baihe|bh|94@bji|白涧|BAP|baijian|bj|95@bji|宝鸡|BJY|baoji|bj|96@bji|滨江|BJB|binjiang|bj|97@bkt|博克图|BKX|boketu|bkt|98@bse|百色|BIZ|baise|bs|99@bss|白山市|HJL|baishanshi|bss|100@bta|北台|BTT|beitai|bt|101@btd|包头东|BDC|baotoudong|btd|102@bto|包头|BTC|baotou|bt|103@bts|北屯市|BXR|beitunshi|bts|104@bxi|本溪|BXT|benxi|bx|105@byb|白云鄂博|BEC|baiyunebo|byeb|106@byx|白银西|BXJ|baiyinxi|byx|107@bzh|亳州|BZH|bozhou|bz|108@cbi|赤壁|CBN|chibi|cb|109@cde|常德|VGQ|changde|cd|110@cde|承德|CDP|chengde|cd|111@cdi|长甸|CDT|changdian|cd|112@cfn|赤峰南|CFD|chifengnan|cfn|113@cli|茶陵|CDG|chaling|cl|114@cna|苍南|CEH|cangnan|cn|115@cpi|昌平|CPP|changping|cp|116@cre|崇仁|CRG|chongren|cr|117@ctu|昌图|CTT|changtu|ct|118@ctz|长汀镇|CDB|changtingzhen|ctz|119@cxi|曹县|CXK|caoxian|cx|120@cxn|楚雄南|COM|chuxiongnan|cxn|121@cxt|陈相屯|CXT|chenxiangtun|cxt|122@czb|长治北|CBF|changzhibei|czb|123@czh|池州|IYH|chizhou|cz|124@czh|长征|CZJ|changzheng|cz|125@czh|常州|CZH|changzhou|cz|126@czh|郴州|CZQ|chenzhou|cz|127@czh|长治|CZF|changzhi|cz|128@czh|沧州|COP|cangzhou|cz|129@czu|崇左|CZZ|chongzuo|cz|130@dab|大安北|RNT|daanbei|dab|131@dch|大成|DCT|dacheng|dc|132@ddo|丹东|DUT|dandong|dd|133@dfh|东方红|DFB|dongfanghong|dfh|134@dgd|东莞东|DMQ|dongguandong|dgd|135@dhs|大虎山|DHD|dahushan|dhs|136@dhu|敦煌|DHJ|dunhuang|dh|137@dhu|敦化|DHL|dunhua|dh|138@dhu|德惠|DHT|dehui|dh|139@djc|东京城|DJB|dongjingcheng|djc|140@dji|大涧|DFP|dajian|dj|141@djy|都江堰|DDW|dujiangyan|djy|142@dlb|大连北|DFT|dalianbei|dlb|143@dli|大理|DKM|dali|dl|144@dli|大连|DLT|dalian|dl|145@dna|定南|DNG|dingnan|dn|146@dqi|大庆|DZX|daqing|dq|147@dsh|东胜|DOC|dongsheng|ds|148@dsq|大石桥|DQT|dashiqiao|dsq|149@dto|大同|DTV|datong|dt|150@dyi|东营|DPK|dongying|dy|151@dys|大杨树|DUX|dayangshu|dys|152@dyu|都匀|RYW|duyun|dy|153@dzh|邓州|DOF|dengzhou|dz|154@dzh|达州|RXW|dazhou|dz|155@dzh|德州|DZP|dezhou|dz|156@ejn|额济纳|EJC|ejina|ejn|157@eli|二连|RLC|erlian|el|158@esh|恩施|ESN|enshi|es|159@fdi|福鼎|FES|fuding|fd|160@fhc|凤凰机场|FJQ|fenghuangjichang|fhjc|161@fld|风陵渡|FLV|fenglingdu|fld|162@fli|涪陵|FLW|fuling|fl|163@flj|富拉尔基|FRX|fulaerji|flej|164@fsb|抚顺北|FET|fushunbei|fsb|165@fsh|佛山|FSQ|foshan|fs|166@fxn|阜新南|FXD|fuxinnan|fxn|167@fya|阜阳|FYH|fuyang|fy|168@gem|格尔木|GRO|geermu|gem|169@gha|广汉|GHW|guanghan|gh|170@gji|古交|GJV|gujiao|gj|171@glb|桂林北|GBZ|guilinbei|glb|172@gli|古莲|GRX|gulian|gl|173@gli|桂林|GLZ|guilin|gl|174@gsh|固始|GXN|gushi|gs|175@gsh|广水|GSN|guangshui|gs|176@gta|干塘|GNJ|gantang|gt|177@gyu|广元|GYW|guangyuan|gy|178@gzb|广州北|GBQ|guangzhoubei|gzb|179@gzh|赣州|GZG|ganzhou|gz|180@gzl|公主岭|GLT|gongzhuling|gzl|181@gzn|公主岭南|GBT|gongzhulingnan|gzln|182@han|淮安|AUH|huaian|ha|183@hbe|淮北|HRH|huaibei|hb|184@hbe|鹤北|HMB|hebei|hb|185@hbi|淮滨|HVN|huaibin|hb|186@hbi|河边|HBV|hebian|hb|187@hch|潢川|KCN|huangchuan|hc|188@hch|韩城|HCY|hancheng|hc|189@hda|邯郸|HDP|handan|hd|190@hdz|横道河子|HDB|hengdaohezi|hdhz|191@hga|鹤岗|HGB|hegang|hg|192@hgt|皇姑屯|HTT|huanggutun|hgt|193@hgu|红果|HEM|hongguo|hg|194@hhe|黑河|HJB|heihe|hh|195@hhu|怀化|HHQ|huaihua|hh|196@hko|汉口|HKN|hankou|hk|197@hld|葫芦岛|HLD|huludao|hld|198@hle|海拉尔|HRX|hailaer|hle|199@hll|霍林郭勒|HWD|huolinguole|hlgl|200@hlu|海伦|HLB|hailun|hl|201@hma|侯马|HMV|houma|hm|202@hmi|哈密|HMR|hami|hm|203@hna|淮南|HAH|huainan|hn|204@hna|桦南|HNB|huanan|hn|205@hnx|海宁西|EUH|hainingxi|hnx|206@hqi|鹤庆|HQM|heqing|hq|207@hrb|怀柔北|HBP|huairoubei|hrb|208@hro|怀柔|HRP|huairou|hr|209@hsd|黄石东|OSN|huangshidong|hsd|210@hsh|华山|HSY|huashan|hs|211@hsh|黄山|HKH|huangshan|hs|212@hsh|黄石|HSN|huangshi|hs|213@hsh|衡水|HSP|hengshui|hs|214@hya|衡阳|HYQ|hengyang|hy|215@hze|菏泽|HIK|heze|hz|216@hzh|贺州|HXZ|hezhou|hz|217@hzh|汉中|HOY|hanzhong|hz|218@hzh|惠州|HCQ|huizhou|hz|219@jan|吉安|VAG|jian|ja|220@jan|集安|JAL|jian|ja|221@jbc|江边村|JBG|jiangbiancun|jbc|222@jch|晋城|JCF|jincheng|jc|223@jcj|金城江|JJZ|jinchengjiang|jcj|224@jdz|景德镇|JCG|jingdezhen|jdz|225@jfe|嘉峰|JFF|jiafeng|jf|226@jgq|加格达奇|JGX|jiagedaqi|jgdq|227@jgs|井冈山|JGG|jinggangshan|jgs|228@jhe|蛟河|JHL|jiaohe|jh|229@jhn|金华南|RNH|jinhuanan|jhn|230@jhu|金华|JBH|jinhua|jh|231@jji|九江|JJG|jiujiang|jj|232@jli|吉林|JLL|jilin|jl|233@jme|荆门|JMN|jingmen|jm|234@jms|佳木斯|JMB|jiamusi|jms|235@jni|济宁|JIK|jining|jn|236@jnn|集宁南|JAC|jiningnan|jnn|237@jqu|酒泉|JQJ|jiuquan|jq|238@jsh|江山|JUH|jiangshan|js|239@jsh|吉首|JIQ|jishou|js|240@jta|九台|JTL|jiutai|jt|241@jts|镜铁山|JVJ|jingtieshan|jts|242@jxi|鸡西|JXB|jixi|jx|243@jxx|绩溪县|JRH|jixixian|jxx|244@jyg|嘉峪关|JGJ|jiayuguan|jyg|245@jyo|江油|JFW|jiangyou|jy|246@jzb|蓟州北|JKP|jizhoubei|jzb|247@jzh|锦州|JZD|jinzhou|jz|248@jzh|金州|JZT|jinzhou|jz|249@kel|库尔勒|KLR|kuerle|kel|250@kfe|开封|KFF|kaifeng|kf|251@kla|岢岚|KLV|kelan|kl|252@kli|凯里|KLW|kaili|kl|253@ksh|喀什|KSR|kashi|ks|254@ksn|昆山南|KNH|kunshannan|ksn|255@ktu|奎屯|KTR|kuitun|kt|256@kyu|开原|KYT|kaiyuan|ky|257@lan|六安|UAH|luan|la|258@lba|灵宝|LBF|lingbao|lb|259@lcg|芦潮港|UCH|luchaogang|lcg|260@lch|隆昌|LCW|longchang|lc|261@lch|陆川|LKZ|luchuan|lc|262@lch|利川|LCN|lichuan|lc|263@lch|潞城|UTP|lucheng|lc|264@lch|临川|LCG|linchuan|lc|265@lda|鹿道|LDL|ludao|ld|266@ldi|娄底|LDQ|loudi|ld|267@lfe|临汾|LFV|linfen|lf|268@lgz|良各庄|LGP|lianggezhuang|lgz|269@lhe|临河|LHC|linhe|lh|270@lhe|漯河|LON|luohe|lh|271@lhu|绿化|LWJ|lvhua|lh|272@lhu|隆化|UHP|longhua|lh|273@lji|丽江|LHM|lijiang|lj|274@lji|临江|LQL|linjiang|lj|275@lji|龙井|LJL|longjing|lj|276@lli|吕梁|LHV|lvliang|ll|277@lli|醴陵|LLG|liling|ll|278@lln|柳林南|LKV|liulinnan|lln|279@lpi|滦平|UPP|luanping|lp|280@lps|六盘水|UMW|liupanshui|lps|281@lqi|灵丘|LVV|lingqiu|lq|282@lsh|旅顺|LST|lvshun|ls|283@lxi|兰溪|LWH|lanxi|lx|284@lxi|陇西|LXJ|longxi|lx|285@lxi|澧县|LEQ|lixian|lx|286@lxi|临西|UEP|linxi|lx|287@lya|龙岩|LYS|longyan|ly|288@lya|耒阳|LYQ|leiyang|ly|289@lya|洛阳|LYF|luoyang|ly|290@lyd|连云港东|UKH|lianyungangdong|lygd|291@lyd|洛阳东|LDF|luoyangdong|lyd|292@lyi|临沂|LVK|linyi|ly|293@lym|洛阳龙门|LLF|luoyanglongmen|lylm|294@lyu|柳园|DHR|liuyuan|ly|295@lyu|凌源|LYD|lingyuan|ly|296@lyu|辽源|LYL|liaoyuan|ly|297@lzh|立志|LZX|lizhi|lz|298@lzh|柳州|LZZ|liuzhou|lz|299@lzh|辽中|LZD|liaozhong|lz|300@mch|麻城|MCN|macheng|mc|301@mdh|免渡河|MDX|mianduhe|mdh|302@mdj|牡丹江|MDB|mudanjiang|mdj|303@meg|莫尔道嘎|MRX|moerdaoga|medg|304@mgu|满归|MHX|mangui|mg|305@mgu|明光|MGH|mingguang|mg|306@mhe|漠河|MVX|mohe|mh|307@mmi|茂名|MDQ|maoming|mm|308@mmx|茂名西|MMZ|maomingxi|mmx|309@msh|密山|MSB|mishan|ms|310@msj|马三家|MJT|masanjia|msj|311@mwe|麻尾|VAW|mawei|mw|312@mya|绵阳|MYW|mianyang|my|313@mzh|梅州|MOQ|meizhou|mz|314@mzl|满洲里|MLX|manzhouli|mzl|315@nbd|宁波东|NVH|ningbodong|nbd|316@nbo|宁波|NGH|ningbo|nb|317@nch|南岔|NCB|nancha|nc|318@nch|南充|NCW|nanchong|nc|319@nda|南丹|NDZ|nandan|nd|320@ndm|南大庙|NMP|nandamiao|ndm|321@nfe|南芬|NFT|nanfen|nf|322@nhe|讷河|NHX|nehe|nh|323@nji|嫩江|NGX|nenjiang|nj|324@nji|内江|NJW|neijiang|nj|325@nto|南通|NUH|nantong|nt|326@nya|南阳|NFF|nanyang|ny|327@nzs|碾子山|NZX|nianzishan|nzs|328@pds|平顶山|PEN|pingdingshan|pds|329@pji|盘锦|PVD|panjin|pj|330@pli|平凉|PIJ|pingliang|pl|331@pln|平凉南|POJ|pingliangnan|pln|332@pqu|平泉|PQP|pingquan|pq|333@psh|坪石|PSQ|pingshi|ps|334@pxi|萍乡|PXG|pingxiang|px|335@pxi|凭祥|PXZ|pingxiang|px|336@pxx|郫县西|PCW|pixianxi|pxx|337@pzh|攀枝花|PRW|panzhihua|pzh|338@qch|蕲春|QRN|qichun|qc|339@qcs|青城山|QSW|qingchengshan|qcs|340@qda|青岛|QDK|qingdao|qd|341@qhc|清河城|QYP|qinghecheng|qhc|342@qji|曲靖|QJM|qujing|qj|343@qji|黔江|QNW|qianjiang|qj|344@qjz|前进镇|QEB|qianjinzhen|qjz|345@qqe|齐齐哈尔|QHX|qiqihaer|qqhe|346@qth|七台河|QTB|qitaihe|qth|347@qxi|沁县|QVV|qinxian|qx|348@qzd|泉州东|QRS|quanzhoudong|qzd|349@qzh|泉州|QYS|quanzhou|qz|350@qzh|衢州|QEH|quzhou|qz|351@ran|融安|RAZ|rongan|ra|352@rjg|汝箕沟|RQJ|rujigou|rjg|353@rji|瑞金|RJG|ruijin|rj|354@rzh|日照|RZK|rizhao|rz|355@scp|双城堡|SCB|shuangchengpu|scp|356@sfh|绥芬河|SFB|suifenhe|sfh|357@sgd|韶关东|SGQ|shaoguandong|sgd|358@shg|山海关|SHD|shanhaiguan|shg|359@shu|绥化|SHB|suihua|sh|360@sjf|三间房|SFX|sanjianfang|sjf|361@sjt|苏家屯|SXT|sujiatun|sjt|362@sla|舒兰|SLL|shulan|sl|363@smn|神木南|OMY|shenmunan|smn|364@smx|三门峡|SMF|sanmenxia|smx|365@sna|商南|ONY|shangnan|sn|366@sni|遂宁|NIW|suining|sn|367@spi|四平|SPT|siping|sp|368@sqi|商丘|SQF|shangqiu|sq|369@sra|上饶|SRG|shangrao|sr|370@ssh|韶山|SSQ|shaoshan|ss|371@sso|宿松|OAH|susong|ss|372@sto|汕头|OTQ|shantou|st|373@swu|邵武|SWS|shaowu|sw|374@sxi|涉县|OEP|shexian|sx|375@sya|三亚|SEQ|sanya|sy|376@sya|邵阳|SYQ|shaoyang|sy|378@sya|十堰|SNN|shiyan|sy|379@syq|三元区|SMS|sanyuanqu|syq|380@sys|双鸭山|SSB|shuangyashan|sys|381@syu|松原|VYT|songyuan|sy|382@szh|宿州|OXH|suzhou|sz|383@szh|苏州|SZH|suzhou|sz|384@szh|深圳|SZQ|shenzhen|sz|385@szh|随州|SZN|suizhou|sz|386@szh|朔州|SUV|shuozhou|sz|387@szx|深圳西|OSQ|shenzhenxi|szx|388@tba|塘豹|TBQ|tangbao|tb|389@teq|塔尔气|TVX|taerqi|teq|390@tgu|潼关|TGY|tongguan|tg|391@tgu|塘沽|TGP|tanggu|tg|392@the|塔河|TXX|tahe|th|393@thu|通化|THL|tonghua|th|394@tla|泰来|TLX|tailai|tl|395@tlf|吐鲁番|TFR|tulufan|tlf|396@tli|通辽|TLD|tongliao|tl|397@tli|铁岭|TLT|tieling|tl|398@tlz|陶赖昭|TPT|taolaizhao|tlz|399@tme|图们|TML|tumen|tm|400@tre|铜仁|RDQ|tongren|tr|401@tsb|唐山北|FUP|tangshanbei|tsb|402@tsf|田师府|TFT|tianshifu|tsf|403@tsh|泰山|TAK|taishan|ts|404@tsh|天水|TSJ|tianshui|ts|405@tsh|唐山|TSP|tangshan|ts|406@typ|通远堡|TYT|tongyuanpu|typ|407@tys|太阳升|TQT|taiyangsheng|tys|408@tzh|泰州|UTH|taizhou|tz|409@tzi|桐梓|TZW|tongzi|tz|410@tzx|通州西|TAP|tongzhouxi|tzx|411@wch|五常|WCB|wuchang|wc|412@wch|武昌|WCN|wuchang|wc|413@wfd|瓦房店|WDT|wafangdian|wfd|414@wha|威海|WKK|weihai|wh|415@whu|芜湖|WHH|wuhu|wh|416@whx|乌海西|WXC|wuhaixi|whx|417@wjt|吴家屯|WJT|wujiatun|wjt|418@wln|乌鲁木齐南|WMR|wulumuqinan|wlmqn|419@wlo|武隆|WLW|wulong|wl|420@wlt|乌兰浩特|WWT|wulanhaote|wlht|421@wna|渭南|WNY|weinan|wn|422@wsh|威舍|WSM|weishe|ws|423@wts|歪头山|WIT|waitoushan|wts|424@wwe|武威|WUJ|wuwei|ww|425@wwn|武威南|WWJ|wuweinan|wwn|426@wxi|无锡|WXH|wuxi|wx|427@wxi|乌西|WXR|wuxi|wx|428@wyl|乌伊岭|WPB|wuyiling|wyl|429@wys|武夷山|WAS|wuyishan|wys|430@wyu|万源|WYY|wanyuan|wy|431@wzh|万州|WYW|wanzhou|wz|432@wzh|梧州|WZZ|wuzhou|wz|433@wzh|温州|RZH|wenzhou|wz|434@wzn|温州南|VRH|wenzhounan|wzn|435@xch|西昌|ECW|xichang|xc|436@xch|许昌|XCF|xuchang|xc|437@xcn|西昌南|ENW|xichangnan|xcn|438@xlt|锡林浩特|XTC|xilinhaote|xlht|439@xmb|厦门北|XKS|xiamenbei|xmb|440@xme|厦门|XMS|xiamen|xm|441@xmq|厦门高崎|XBS|xiamengaoqi|xmgq|442@xwe|宣威|XWM|xuanwei|xw|443@xxi|新乡|XXF|xinxiang|xx|444@xya|信阳|XUN|xinyang|xy|445@xya|咸阳|XYY|xianyang|xy|446@xya|襄阳|XFN|xiangyang|xy|447@xyc|熊岳城|XYT|xiongyuecheng|xyc|448@xyu|新余|XUG|xinyu|xy|449@xzh|徐州|XCH|xuzhou|xz|450@yan|延安|YWY|yanan|ya|451@ybi|宜宾|YBW|yibin|yb|452@ybn|亚布力南|YWB|yabulinan|ybln|453@ybs|叶柏寿|YBD|yebaishou|ybs|454@ycd|宜昌东|HAN|yichangdong|ycd|455@ych|永川|YCW|yongchuan|yc|456@ych|盐城|AFH|yancheng|yc|457@ych|运城|YNV|yuncheng|yc|458@ych|伊春|YCB|yichun|yc|459@ych|宜昌|YCN|yichang|yc|460@yci|榆次|YCV|yuci|yc|461@ycu|杨村|YBP|yangcun|yc|462@ycx|宜春西|YCG|yichunxi|ycx|463@yes|伊尔施|YET|yiershi|yes|464@yga|燕岗|YGW|yangang|yg|465@yji|永济|YIV|yongji|yj|466@yji|延吉|YJL|yanji|yj|467@yko|营口|YKT|yingkou|yk|468@yks|牙克石|YKX|yakeshi|yks|469@yli|阎良|YNY|yanliang|yl|470@yli|玉林|YLZ|yulin|yl|471@yli|榆林|ALY|yulin|yl|472@ylw|亚龙湾|TWQ|yalongwan|ylw|473@ymp|一面坡|YPB|yimianpo|ymp|474@yni|伊宁|YMR|yining|yn|475@ypg|阳平关|YAY|yangpingguan|ypg|476@ypi|玉屏|YZW|yuping|yp|477@ypi|原平|YPV|yuanping|yp|478@yqi|延庆|YNP|yanqing|yq|479@yqq|阳泉曲|YYV|yangquanqu|yqq|480@yqu|玉泉|YQB|yuquan|yq|481@yqu|阳泉|AQP|yangquan|yq|482@ysh|营山|NUW|yingshan|ys|483@ysh|玉山|YNG|yushan|ys|484@ysh|燕山|AOP|yanshan|ys|485@ysh|榆树|YRT|yushu|ys|486@yta|鹰潭|YTG|yingtan|yt|487@yta|烟台|YAK|yantai|yt|488@yth|伊图里河|YEX|yitulihe|ytlh|489@ytx|玉田县|ATP|yutianxian|ytx|490@ywu|义乌|YWH|yiwu|yw|491@yxi|阳新|YON|yangxin|yx|492@yxi|义县|YXD|yixian|yx|493@yya|益阳|AEQ|yiyang|yy|494@yya|岳阳|YYQ|yueyang|yy|495@yzh|崖州|YUQ|yazhou|yz|496@yzh|扬州|YLH|yangzhou|yz|497@yzh|永州|AOQ|yongzhou|yz|498@zbo|淄博|ZBK|zibo|zb|499@zcd|镇城底|ZDV|zhenchengdi|zcd|500@zgo|自贡|ZGW|zigong|zg|501@zha|珠海|ZHQ|zhuhai|zh|502@zhb|珠海北|ZIQ|zhuhaibei|zhb|503@zji|湛江|ZJZ|zhanjiang|zj|504@zji|镇江|ZJH|zhenjiang|zj|505@zjj|张家界|DIQ|zhangjiajie|zjj|506@zjk|张家口|ZMP|zhangjiakou|zjk|507@zko|周口|ZKN|zhoukou|zk|508@zlt|扎兰屯|ZTX|zhalantun|zlt|509@zmd|驻马店|ZDN|zhumadian|zmd|510@zqi|肇庆|ZVQ|zhaoqing|zq|511@zsz|周水子|ZIT|zhoushuizi|zsz|512@zto|昭通|ZDW|zhaotong|zt|513@zwe|中卫|ZWJ|zhongwei|zw|514@zya|资阳|ZYW|ziyang|zy|515@zyx|遵义西|ZIW|zunyixi|zyx|516@zzh|资中|ZZW|zizhong|zz|517@zzh|枣庄|ZEK|zaozhuang|zz|518@zzh|株洲|ZZQ|zhuzhou|zz|519@zzx|枣庄西|ZFK|zaozhuangxi|zzx|520@aax|昂昂溪|AAX|angangxi|aax|521@ach|阿城|ACB|acheng|ac|522@ada|安达|ADX|anda|ad|523@ade|安德|ARW|ande|ad|524@adi|安定|ADP|anding|ad|525@adu|安多|ADO|anduo|ad|526@agu|安广|AGT|anguang|ag|527@aha|敖汉|YED|aohan|ah|528@ahe|艾河|AHP|aihe|ah|529@ahu|安化|PKQ|anhua|ah|530@ajc|艾家村|AJJ|aijiacun|ajc|531@aji|安家|AJB|anjia|aj|532@aji|阿金|AJD|ajin|aj|533@aji|安靖|PYW|anjing|aj|534@akt|阿克陶|AER|aketao|akt|535@aky|安口窑|AYY|ankouyao|aky|536@alg|敖力布告|ALD|aolibugao|albg|537@alo|安龙|AUZ|anlong|al|538@als|阿龙山|ASX|alongshan|als|539@alu|安陆|ALN|anlu|al|540@ame|阿木尔|JTX|amuer|ame|541@anz|阿南庄|AZM|ananzhuang|anz|542@asx|鞍山西|AXT|anshanxi|asx|543@ata|安塘|ATV|antang|at|544@atb|安亭北|ASH|antingbei|atb|545@ats|阿图什|ATR|atushi|ats|546@atu|安图|ATL|antu|at|547@axi|安溪|AXS|anxi|ax|548@bao|博鳌|BWQ|boao|ba|549@bbe|北碚|BPW|beibei|bb|550@bbg|白壁关|BGV|baibiguan|bbg|551@bbn|蚌埠南|BMH|bengbunan|bbn|552@bch|巴楚|BCR|bachu|bc|553@bch|板城|BUP|bancheng|bc|554@bdh|北戴河|BEP|beidaihe|bdh|555@bdi|保定|BDP|baoding|bd|556@bdi|宝坻|BPP|baodi|bd|557@bdl|八达岭|ILP|badaling|bdl|558@bdo|巴东|BNN|badong|bd|559@bfe|宝丰|BFF|baofeng|bf|560@bgu|柏果|BGM|baiguo|bg|561@bha|布海|BUT|buhai|bh|562@bhd|白河东|BIY|baihedong|bhd|563@bhs|宝华山|BWH|baohuashan|bhs|564@bhx|白河县|BEY|baihexian|bhx|565@bjg|白芨沟|BJJ|baijigou|bjg|566@bjg|碧鸡关|BJM|bijiguan|bjg|567@bji|北滘|IBQ|beijiao|bj|568@bji|碧江|BLQ|bijiang|bj|569@bjp|白鸡坡|BBM|baijipo|bjp|570@bjs|笔架山|BSB|bijiashan|bjs|571@bjt|八角台|BTD|bajiaotai|bjt|572@bka|保康|BKD|baokang|bk|573@bkp|白奎堡|BKB|baikuipu|bkp|574@bla|白狼|BAT|bailang|bl|575@bla|百浪|BRZ|bailang|bl|576@ble|博乐|BOR|bole|bl|577@bli|巴林|BLX|balin|bl|578@bli|宝林|BNB|baolin|bl|579@bli|北流|BOZ|beiliu|bl|580@bli|勃利|BLB|boli|bl|581@blk|布列开|BLR|buliekai|blk|582@bls|宝龙山|BND|baolongshan|bls|583@blx|百里峡|AAP|bailixia|blx|584@bmc|八面城|BMD|bamiancheng|bmc|585@bmq|班猫箐|BNM|banmaoqing|bmq|586@bmt|八面通|BMB|bamiantong|bmt|587@bmz|北马圈子|BRP|beimaquanzi|bmqz|588@bpn|北票南|RPD|beipiaonan|bpn|589@bqi|白旗|BQP|baiqi|bq|590@bql|宝泉岭|BQB|baoquanling|bql|591@bqu|白泉|BQL|baiquan|bq|592@bsh|巴山|BAY|bashan|bs|593@bsj|白水江|BSY|baishuijiang|bsj|594@bsp|白沙坡|BPM|baishapo|bsp|595@bss|白石山|BAL|baishishan|bss|596@bsz|白水镇|BUM|baishuizhen|bsz|597@btd|包头 东|FDC|baotoudong|btd|598@bti|坂田|BTQ|bantian|bt|599@bto|泊头|BZP|botou|bt|600@btu|北屯|BYP|beitun|bt|601@bxh|本溪湖|BHT|benxihu|bxh|602@bxi|博兴|BXK|boxing|bx|603@bxt|八仙筒|VXD|baxiantong|bxt|604@byg|白音察干|BYC|baiyinchagan|bycg|605@byh|背荫河|BYB|beiyinhe|byh|606@byi|北营|BIV|beiying|by|607@byl|巴彦高勒|BAC|bayangaole|bygl|608@byl|白音他拉|BID|baiyintala|bytl|609@byq|鲅鱼圈|BYT|bayuquan|byq|610@bys|白银市|BNJ|baiyinshi|bys|611@bys|白音胡硕|BCD|baiyinhushuo|byhs|612@bzh|巴中|IEW|bazhong|bz|613@bzh|霸州|RMP|bazhou|bz|614@bzh|北宅|BVP|beizhai|bz|615@cbb|赤壁北|CIN|chibibei|cbb|616@cbg|查布嘎|CBC|chabuga|cbg|617@cch|长城|CEJ|changcheng|cc|618@cch|长冲|CCM|changchong|cc|619@cdd|承德东|CCP|chengdedong|cdd|620@cfe|赤峰|CID|chifeng|cf|621@cga|嵯岗|CAX|cuogang|cg|622@cga|柴岗|CGT|chaigang|cg|623@cge|长葛|CEF|changge|cg|624@cgp|柴沟堡|CGV|chaigoupu|cgp|625@cgu|城固|CGY|chenggu|cg|626@cgy|陈官营|CAJ|chenguanying|cgy|627@cgz|成高子|CZB|chenggaozi|cgz|628@cha|草海|WBW|caohai|ch|629@che|柴河|CHB|chaihe|ch|630@che|册亨|CHZ|ceheng|ch|631@chk|草河口|CKT|caohekou|chk|632@chk|崔黄口|CHP|cuihuangkou|chk|633@chu|巢湖|CIH|chaohu|ch|634@cjg|蔡家沟|CJT|caijiagou|cjg|635@cjh|成吉思汗|CJX|chengjisihan|cjsh|636@cji|岔江|CAM|chajiang|cj|637@cjp|蔡家坡|CJY|caijiapo|cjp|638@cle|昌乐|CLK|changle|cl|639@clg|超梁沟|CYP|chaolianggou|clg|640@cli|慈利|CUQ|cili|cl|641@cli|昌黎|CLP|changli|cl|642@clz|长岭子|CLT|changlingzi|clz|643@cmi|晨明|CMB|chenming|cm|644@cno|长农|CNJ|changnong|cn|645@cpb|昌平北|VBP|changpingbei|cpb|646@cpi|常平|DAQ|changping|cp|647@cpl|长坡岭|CPM|changpoling|cpl|648@cqi|辰清|CQB|chenqing|cq|649@csh|楚山|CSB|chushan|cs|650@csh|长寿|EFW|changshou|cs|651@csh|蔡山|CON|caishan|cs|652@csh|磁山|CSP|cishan|cs|653@csh|苍石|CST|cangshi|cs|654@csh|草市|CSL|caoshi|cs|655@csq|察素齐|CSC|chasuqi|csq|656@cst|长山屯|CVT|changshantun|cst|657@cti|长汀|CES|changting|ct|658@ctn|朝天南|CTY|chaotiannan|ctn|659@ctx|昌图西|CPT|changtuxi|ctx|660@cwa|春湾|CQQ|chunwan|cw|661@cxi|磁县|CIP|cixian|cx|662@cxi|岑溪|CNZ|cenxi|cx|663@cxi|辰溪|CXQ|chenxi|cx|664@cxi|磁西|CRP|cixi|cx|665@cxn|长兴南|CFH|changxingnan|cxn|666@cya|磁窑|CYK|ciyao|cy|667@cya|春阳|CAL|chunyang|cy|668@cya|城阳|CEK|chengyang|cy|669@cyc|创业村|CEX|chuangyecun|cyc|670@cyc|朝阳川|CYL|chaoyangchuan|cyc|671@cyd|朝阳地|CDD|chaoyangdi|cyd|672@cyn|朝阳南|CYD|chaoyangnan|cyn|673@cyu|长垣|CYF|changyuan|cy|674@cyz|朝阳镇|CZL|chaoyangzhen|cyz|675@czb|滁州北|CUH|chuzhoubei|czb|676@czb|常州北|ESH|changzhoubei|czb|677@czh|滁州|CXH|chuzhou|cz|678@czh|潮州|CKQ|chaozhou|cz|679@czh|常庄|CVK|changzhuang|cz|680@czl|曹子里|CFP|caozili|czl|681@czw|车转湾|CWM|chezhuanwan|czw|682@czx|郴州西|ICQ|chenzhouxi|czx|683@czx|沧州西|CBP|cangzhouxi|czx|684@dan|德安|DAG|dean|da|685@dan|大安|RAT|daan|da|686@dba|大板|DBC|daban|db|687@dba|大坝|DBJ|daba|db|688@dba|大巴|DBD|daba|db|689@dba|电白|NWQ|dianbai|db|690@dba|到保|RBT|daobao|db|691@dbc|达坂城|DCR|dabancheng|dbc|692@dbi|定边|DYJ|dingbian|db|693@dbj|东边井|DBB|dongbianjing|dbj|694@dbs|德伯斯|RDT|debosi|dbs|695@dcg|打柴沟|DGJ|dachaigou|dcg|696@dch|德昌|DVW|dechang|dc|697@dda|滴道|DDB|didao|dd|698@ddg|大磴沟|DKJ|dadenggou|ddg|699@ded|刀尔登|DRD|daoerdeng|ded|700@dee|得耳布尔|DRX|deerbuer|debe|701@det|杜尔伯特|TKX|duerbote|debt|702@dfa|东方|UFQ|dongfang|df|703@dfe|丹凤|DGY|danfeng|df|704@dfe|东丰|DIL|dongfeng|df|705@dge|都格|DMM|duge|dg|706@dgt|大官屯|DTT|daguantun|dgt|707@dgu|大关|RGW|daguan|dg|708@dgu|东光|DGP|dongguang|dg|709@dha|东海|DHB|donghai|dh|710@dhc|大灰厂|DHP|dahuichang|dhc|711@dhq|大红旗|DQD|dahongqi|dhq|712@dht|大禾塘|SOQ|shaodong|dh|713@dhx|东海县|DQH|donghaixian|dhx|714@dhx|德惠西|DXT|dehuixi|dhx|715@djg|达家沟|DJT|dajiagou|djg|716@dji|东津|DKB|dongjin|dj|717@dji|杜家|DJL|dujia|dj|718@dkt|大口屯|DKP|dakoutun|dkt|719@dla|东来|RVD|donglai|dl|720@dlh|德令哈|DHO|delingha|dlh|721@dli|带岭|DLB|dailing|dl|722@dli|大林|DLD|dalin|dl|723@dlq|达拉特旗|DIC|dalateqi|dltq|724@dlt|独立屯|DTX|dulitun|dlt|725@dlu|豆罗|DLV|douluo|dl|726@dlx|达拉特西|DNC|dalatexi|dltx|727@dlx|大连西|GZT|dalianxi|dlx|728@dmc|东明村|DMD|dongmingcun|dmc|729@dmh|洞庙河|DEP|dongmiaohe|dmh|730@dmx|东明县|DNF|dongmingxian|dmx|731@dni|大拟|DNZ|dani|dn|732@dpf|大平房|DPD|dapingfang|dpf|733@dps|大盘石|RPP|dapanshi|dps|734@dpu|大埔|DPI|dapu|dp|735@dpu|大堡|DVT|dapu|dp|736@dqd|大庆东|LFX|daqingdong|dqd|737@dqh|大其拉哈|DQX|daqilaha|dqlh|738@dqi|道清|DML|daoqing|dq|739@dqs|对青山|DQB|duiqingshan|dqs|740@dqx|德清西|MOH|deqingxi|dqx|741@dqx|大庆西|RHX|daqingxi|dqx|742@dsh|砀山|DKH|dangshan|ds|743@dsh|独山|RWW|dushan|ds|744@dsh|东升|DRQ|dongsheng|ds|745@dsh|登沙河|DWT|dengshahe|dsh|746@dsp|读书铺|DPM|dushupu|dsp|747@dst|大石头|DSL|dashitou|dst|748@dsx|东胜西|DYC|dongshengxi|dsx|749@dsz|大石寨|RZT|dashizhai|dsz|750@dta|东台|DBH|dongtai|dt|751@dta|定陶|DQK|dingtao|dt|752@dta|灯塔|DGT|dengta|dt|753@dtb|大田边|DBM|datianbian|dtb|754@dth|东通化|DTL|dongtonghua|dth|755@dtu|丹徒|RUH|dantu|dt|756@dtu|大屯|DNT|datun|dt|757@dwa|东湾|DRJ|dongwan|dw|758@dwk|大武口|DFJ|dawukou|dwk|759@dwp|低窝铺|DWJ|diwopu|dwp|760@dwt|大王滩|DZZ|dawangtan|dwt|761@dwz|大湾子|DFM|dawanzi|dwz|762@dxg|大兴沟|DXL|daxinggou|dxg|763@dxi|大兴|DXX|daxing|dx|764@dxi|定西|DSJ|dingxi|dx|765@dxi|东乡|DXG|dongxiang|dx|766@dxi|代县|DKV|daixian|dx|767@dxi|定襄|DXV|dingxiang|dx|768@dxi|甸心|DXM|dianxin|dx|769@dxu|东戌|RXP|dongxu|dx|770@dxz|东辛庄|DXD|dongxinzhuang|dxz|771@dya|丹阳|DYH|danyang|dy|772@dya|大雁|DYX|dayan|dy|773@dya|德阳|DYW|deyang|dy|774@dya|当阳|DYN|dangyang|dy|775@dyb|丹阳北|EXH|danyangbei|dyb|776@dyd|大英东|IAW|dayingdong|dyd|777@dyd|东淤地|DBV|dongyudi|dyd|778@dyi|大营|DYV|daying|dy|779@dyu|定远|EWH|dingyuan|dy|780@dyu|岱岳|RYV|daiyue|dy|781@dyu|大元|DYZ|dayuan|dy|782@dyz|大营镇|DJP|dayingzhen|dyz|783@dyz|大营子|DZD|dayingzi|dyz|784@dzc|大战场|DTJ|dazhanchang|dzc|785@dzd|德州东|DIP|dezhoudong|dzd|786@dzh|东至|DCH|dongzhi|dz|787@dzh|低庄|DVQ|dizhuang|dz|788@dzh|东镇|DNV|dongzhen|dz|789@dzh|道州|DFZ|daozhou|dz|790@dzh|东庄|DZV|dongzhuang|dz|791@dzh|兑镇|DWV|duizhen|dz|792@dzh|定州|DXP|dingzhou|dz|793@dzh|豆庄|ROP|douzhuang|dz|794@dzy|大竹园|DZY|dazhuyuan|dzy|795@dzz|大杖子|DAP|dazhangzi|dzz|796@dzz|豆张庄|RZP|douzhangzhuang|dzz|797@ebi|峨边|EBW|ebian|eb|798@edm|二道沟门|RDP|erdaogoumen|edgm|799@edw|二道湾|RDX|erdaowan|edw|800@ees|鄂尔多斯|EEC|eerduosi|eeds|801@elo|二龙|RLD|erlong|el|802@elt|二龙山屯|ELA|erlongshantun|elst|803@eme|峨眉|EMW|emei|em|804@emh|二密河|RML|ermihe|emh|805@epi|恩平|PXQ|enping|ep|806@eyi|二营|RYJ|erying|ey|807@ezh|鄂州|ECN|ezhou|ez|808@fan|福安|FAS|fuan|fa|809@fch|丰城|FCG|fengcheng|fc|810@fcn|丰城南|FNG|fengchengnan|fcn|811@fdo|肥东|FIH|feidong|fd|812@fer|发耳|FEM|faer|fe|813@fha|富海|FHX|fuhai|fh|814@fha|福海|FHR|fuhai|fh|815@fhc|凤凰城|FHT|fenghuangcheng|fhc|816@fhe|汾河|FEV|fenhe|fh|817@fhu|奉化|FHH|fenghua|fh|818@fji|富锦|FIB|fujin|fj|819@fjt|范家屯|FTT|fanjiatun|fjt|820@flq|福利区|FLJ|fuliqu|flq|821@flt|福利屯|FTB|fulitun|flt|822@flz|丰乐镇|FZB|fenglezhen|flz|823@fna|阜南|FNH|funan|fn|824@fni|阜宁|AKH|funing|fn|825@fni|抚宁|FNP|funing|fn|826@fqi|福清|FQS|fuqing|fq|827@fqu|福泉|VMW|fuquan|fq|828@fsc|丰水村|FSJ|fengshuicun|fsc|829@fsh|丰顺|FUQ|fengshun|fs|830@fsh|繁峙|FSV|fanshi|fs|831@fsh|抚顺|FST|fushun|fs|832@fsk|福山口|FKP|fushankou|fsk|833@fsu|扶绥|FSZ|fusui|fs|834@ftu|冯屯|FTX|fengtun|ft|835@fty|浮图峪|FYP|futuyu|fty|836@fxd|富县东|FDY|fuxiandong|fxd|837@fxi|凤县|FXY|fengxian|fx|838@fxi|费县|FXK|feixian|fx|839@fxi|富县|FEY|fuxian|fx|840@fxi|肥西|FAH|feixi|fx|841@fya|汾阳|FAV|fenyang|fy|842@fya|凤阳|FUH|fengyang|fy|843@fyb|扶余北|FBT|fuyubei|fyb|844@fyi|分宜|FYG|fenyi|fy|845@fyu|富源|FYM|fuyuan|fy|846@fyu|扶余|FYT|fuyu|fy|847@fyu|富裕|FYX|fuyu|fy|848@fzb|抚州北|FBG|fuzhoubei|fzb|849@fzh|凤州|FZY|fengzhou|fz|850@fzh|丰镇|FZC|fengzhen|fz|851@fzh|范镇|VZK|fanzhen|fz|852@gan|广安|VJW|guangan|ga|853@gan|固安|GFP|guan|ga|854@gbd|高碑店|GBP|gaobeidian|gbd|855@gbz|沟帮子|GBD|goubangzi|gbz|856@gcd|甘草店|GDJ|gancaodian|gcd|857@gch|谷城|GCN|gucheng|gc|858@gch|藁城|GEP|gaocheng|gc|859@gcu|高村|GCV|gaocun|gc|860@gcz|古城镇|GZB|guchengzhen|gcz|861@gde|广德|GRH|guangde|gd|862@gdi|贵定|GTW|guiding|gd|863@gdn|贵定南|IDW|guidingnan|gdn|864@gdo|古东|GDV|gudong|gd|865@gga|贵港|GGZ|guigang|gg|866@gga|官高|GVP|guangao|gg|867@ggm|葛根庙|GGT|gegenmiao|ggm|868@ggo|干沟|GGL|gangou|gg|869@ggu|甘谷|GGJ|gangu|gg|870@ggz|高各庄|GGP|gaogezhuang|ggz|871@ghe|甘河|GAX|ganhe|gh|872@ghe|根河|GEX|genhe|gh|873@gjd|郭家店|GDT|guojiadian|gjd|874@gjz|孤家子|GKT|gujiazi|gjz|875@gla|古浪|GLJ|gulang|gl|876@gla|皋兰|GEJ|gaolan|gl|877@glf|高楼房|GFM|gaoloufang|glf|878@glh|归流河|GHT|guiliuhe|glh|879@gli|关林|GLF|guanlin|gl|880@glu|甘洛|VOW|ganluo|gl|881@glz|郭磊庄|GLP|guoleizhuang|glz|882@gmi|高密|GMK|gaomi|gm|883@gmz|公庙子|GMC|gongmiaozi|gmz|884@gnh|工农湖|GRT|gongnonghu|gnh|885@gnn|广宁寺南|GNT|guangningsinan|gnn|886@gnw|广南卫|GNM|guangnanwei|gnw|887@gpi|高平|GPF|gaoping|gp|888@gqb|甘泉北|GEY|ganquanbei|gqb|889@gqc|共青城|GAG|gongqingcheng|gqc|890@gqk|甘旗卡|GQD|ganqika|gqk|891@gqu|甘泉|GQY|ganquan|gq|892@gqz|高桥镇|GZD|gaoqiaozhen|gqz|893@gsh|灌水|GST|guanshui|gs|894@gsh|赶水|GSW|ganshui|gs|895@gsk|孤山口|GSP|gushankou|gsk|896@gso|果松|GSL|guosong|gs|897@gsz|高山子|GSD|gaoshanzi|gsz|898@gsz|嘎什甸子|GXD|gashidianzi|gsdz|899@gta|高台|GTJ|gaotai|gt|900@gta|高滩|GAY|gaotan|gt|901@gti|官厅|GTP|guanting|gt|902@gti|古田|GTS|gutian|gt|903@gtx|官厅西|KEP|guantingxi|gtx|904@gxi|贵溪|GXG|guixi|gx|905@gya|涡阳|GYH|guoyang|gy|906@gyi|巩义|GXF|gongyi|gy|907@gyi|高邑|GIP|gaoyi|gy|908@gyn|巩义南|GYF|gongyinan|gyn|909@gyn|广元南|GAW|guangyuannan|gyn|910@gyu|固原|GUJ|guyuan|gy|911@gyu|菇园|GYL|guyuan|gy|912@gyz|公营子|GYD|gongyingzi|gyz|913@gze|光泽|GZS|guangze|gz|914@gzh|固镇|GEH|guzhen|gz|915@gzh|瓜州|GZJ|guazhou|gz|916@gzh|古镇|GNQ|guzhen|gz|917@gzh|高州|GSQ|gaozhou|gz|918@gzh|盖州|GXT|gaizhou|gz|919@gzh|虢镇|GZY|guozhen|gz|920@gzj|官字井|GOT|guanzijing|gzj|921@gzs|冠豸山|GSS|guanzhaishan|gzs|922@gzx|盖州西|GAT|gaizhouxi|gzx|923@han|海安|HIH|haian|ha|924@han|淮安南|AMH|huaiannan|han|925@han|红安|HWN|hongan|ha|926@hax|红安西|VXN|honganxi|hax|927@hba|黄柏|HBL|huangbai|hb|928@hbe|海北|HEB|haibei|hb|929@hbi|鹤壁|HAF|hebi|hb|930@hcb|会昌北|XEG|huichangbei|hcb|931@hch|华城|VCQ|huacheng|hc|932@hch|河唇|HCZ|hechun|hc|933@hch|汉川|HCN|hanchuan|hc|934@hch|海城|HCT|haicheng|hc|935@hch|合川|WKW|hechuan|hc|936@hct|黑冲滩|HCJ|heichongtan|hct|937@hcu|黄村|HCP|huangcun|hc|938@hcx|海城西|HXT|haichengxi|hcx|939@hde|化德|HGC|huade|hd|940@hdo|洪洞|HDV|hongtong|hd|941@hes|霍尔果斯|HFR|huoerguosi|hegs|942@hfe|横峰|HFG|hengfeng|hf|943@hfw|韩府湾|HXJ|hanfuwan|hfw|944@hgu|汉沽|HGP|hangu|hg|945@hgy|黄瓜园|HYM|huangguayuan|hgy|946@hgz|红光镇|IGW|hongguangzhen|hgz|947@hhe|浑河|HHT|hunhe|hh|948@hhg|红花沟|VHD|honghuagou|hhg|949@hht|黄花筒|HUD|huanghuatong|hht|950@hjd|贺家店|HJJ|hejiadian|hjd|951@hji|和静|HJR|hejing|hj|952@hji|获嘉|HJF|huojia|hj|953@hji|河津|HJV|hejin|hj|954@hji|红江|HFM|hongjiang|hj|955@hji|黑井|HIM|heijing|hj|956@hji|涵江|HJS|hanjiang|hj|957@hji|华家|HJT|huajia|hj|958@hjq|杭锦后旗|HDC|hangjinhouqi|hjhq|959@hjx|河间西|HXP|hejianxi|hjx|960@hjz|花家庄|HJM|huajiazhuang|hjz|961@hkn|河口南|HKJ|hekounan|hkn|962@hko|黄口|KOH|huangkou|hk|963@hko|湖口|HKG|hukou|hk|964@hla|呼兰|HUB|hulan|hl|965@hlb|葫芦岛北|HPD|huludaobei|hldb|966@hlh|浩良河|HHB|haolianghe|hlh|967@hlh|哈拉海|HIT|halahai|hlh|968@hli|鹤立|HOB|heli|hl|969@hli|桦林|HIB|hualin|hl|970@hli|黄陵|ULY|huangling|hl|971@hli|海林|HRB|hailin|hl|972@hli|虎林|VLB|hulin|hl|973@hli|寒岭|HAT|hanling|hl|974@hlo|和龙|HLL|helong|hl|975@hlo|海龙|HIL|hailong|hl|976@hls|哈拉苏|HAX|halasu|hls|977@hlt|呼鲁斯太|VTJ|hulusitai|hlst|978@hlz|火连寨|HLT|huolianzhai|hlz|979@hme|黄梅|VEH|huangmei|hm|980@hmy|韩麻营|HYP|hanmaying|hmy|981@hnh|黄泥河|HHL|huangnihe|hnh|982@hni|海宁|HNH|haining|hn|983@hni|怀宁|APH|huaining|hn|984@hno|惠农|HMJ|huinong|hn|985@hpi|和平|VAQ|heping|hp|986@hpz|花棚子|HZM|huapengzi|hpz|987@hqi|花桥|VQH|huaqiao|hq|988@hqi|宏庆|HEY|hongqing|hq|989@hre|怀仁|HRV|huairen|hr|990@hro|华容|HRN|huarong|hr|991@hsb|华山北|HDY|huashanbei|hsb|992@hsd|黄松甸|HDL|huangsongdian|hsd|993@hsg|和什托洛盖|VSR|heshituoluogai|hstlg|994@hsh|红山|VSB|hongshan|hs|995@hsh|汉寿|VSQ|hanshou|hs|996@hsh|衡山|HSQ|hengshan|hs|997@hsh|黑水|HOT|heishui|hs|998@hsh|惠山|VCH|huishan|hs|999@hsh|虎什哈|HHP|hushiha|hsh|1000@hsp|红寺堡|HSJ|hongsipu|hsp|1001@hst|虎石台|HUT|hushitai|hst|1002@hsw|海石湾|HSO|haishiwan|hsw|1003@hsx|衡山西|HEQ|hengshanxi|hsx|1004@hsx|红砂岘|VSJ|hongshaxian|hsx|1005@hta|黑台|HQB|heitai|ht|1006@hta|桓台|VTK|huantai|ht|1007@hti|和田|VTR|hetian|ht|1008@hto|会同|VTQ|huitong|ht|1009@htz|海坨子|HZT|haituozi|htz|1010@hwa|黑旺|HWK|heiwang|hw|1011@hwa|海湾|RWH|haiwan|hw|1012@hxi|红星|VXB|hongxing|hx|1013@hxi|徽县|HYY|huixian|hx|1014@hxl|红兴隆|VHB|hongxinglong|hxl|1015@hxt|换新天|VTB|huanxintian|hxt|1016@hxt|红岘台|HTJ|hongxiantai|hxt|1017@hya|红彦|VIX|hongyan|hy|1018@hya|海晏|HFO|haiyan|hy|1019@hya|合阳|HAY|heyang|hy|1020@hyd|衡阳东|HVQ|hengyangdong|hyd|1021@hyi|华蓥|HUW|huaying|hy|1022@hyi|汉阴|HQY|hanyin|hy|1023@hyt|黄羊滩|HGJ|huangyangtan|hyt|1024@hyu|汉源|WHW|hanyuan|hy|1025@hyu|河源|VIQ|heyuan|hy|1026@hyu|花园|HUN|huayuan|hy|1027@hyu|湟源|HNO|huangyuan|hy|1028@hyz|黄羊镇|HYJ|huangyangzhen|hyz|1029@hzh|湖州|VZH|huzhou|hz|1030@hzh|化州|HZZ|huazhou|hz|1031@hzh|黄州|VON|huangzhou|hz|1032@hzh|霍州|HZV|huozhou|hz|1033@hzx|惠州西|VXQ|huizhouxi|hzx|1034@jba|巨宝|JRT|jubao|jb|1035@jbi|靖边|JIY|jingbian|jb|1036@jbt|金宝屯|JBD|jinbaotun|jbt|1037@jcb|晋城北|JEF|jinchengbei|jcb|1038@jch|金昌|JCJ|jinchang|jc|1039@jch|鄄城|JCK|juancheng|jc|1040@jch|交城|JNV|jiaocheng|jc|1041@jch|建昌|JFD|jianchang|jc|1042@jde|峻德|JDB|junde|jd|1043@jdi|井店|JFP|jingdian|jd|1044@jdo|鸡东|JOB|jidong|jd|1045@jdu|江都|UDH|jiangdu|jd|1046@jgs|鸡冠山|JST|jiguanshan|jgs|1047@jgt|金沟屯|VGP|jingoutun|jgt|1048@jha|静海|JHP|jinghai|jh|1049@jhe|金河|JHX|jinhe|jh|1050@jhe|锦河|JHB|jinhe|jh|1051@jhe|精河|JHR|jinghe|jh|1052@jhn|精河南|JIR|jinghenan|jhn|1053@jhu|江华|JHZ|jianghua|jh|1054@jhu|建湖|AJH|jianhu|jh|1055@jjg|纪家沟|VJD|jijiagou|jjg|1056@jji|晋江|JJS|jinjiang|jj|1057@jji|锦界|JEY|jinjie|jj|1058@jji|姜家|JJB|jiangjia|jj|1059@jji|江津|JJW|jiangjin|jj|1060@jke|金坑|JKT|jinkeng|jk|1061@jli|芨岭|JLJ|jiling|jl|1062@jmc|金马村|JMM|jinmacun|jmc|1063@jmd|江门东|JWQ|jiangmendong|jmd|1064@jme|角美|JES|jiaomei|jm|1065@jme|江门|JOQ|jiangmen|jm|1066@jna|莒南|JOK|junan|jn|1067@jna|井南|JNP|jingnan|jn|1068@jou|建瓯|JVS|jianou|jo|1069@jpe|经棚|JPC|jingpeng|jp|1070@jqi|江桥|JQX|jiangqiao|jq|1071@jsa|九三|SSX|jiusan|js|1072@jsb|金山北|EGH|jinshanbei|jsb|1073@jsh|嘉善|JSH|jiashan|js|1074@jsh|京山|JCN|jingshan|js|1075@jsh|建始|JRN|jianshi|js|1076@jsh|稷山|JVV|jishan|js|1077@jsh|吉舒|JSL|jishu|js|1078@jsh|建设|JET|jianshe|js|1079@jsh|甲山|JOP|jiashan|js|1080@jsj|建三江|JIB|jiansanjiang|jsj|1081@jsn|嘉善南|EAH|jiashannan|jsn|1082@jst|金山屯|JTB|jinshantun|jst|1083@jst|江所田|JOM|jiangsuotian|jst|1084@jta|景泰|JTJ|jingtai|jt|1085@jtn|九台南|JNL|jiutainan|jtn|1086@jwe|吉文|JWX|jiwen|jw|1087@jxi|进贤|JUG|jinxian|jx|1088@jxi|莒县|JKK|juxian|jx|1089@jxi|嘉祥|JUK|jiaxiang|jx|1090@jxi|介休|JXV|jiexiu|jx|1091@jxi|嘉兴|JXH|jiaxing|jx|1092@jxi|井陉|JJP|jingxing|jx|1093@jxn|嘉兴南|EPH|jiaxingnan|jxn|1094@jxz|夹心子|JXT|jiaxinzi|jxz|1095@jya|简阳|JYW|jianyang|jy|1096@jya|姜堰|UEH|jiangyan|jy|1097@jya|建阳|JYS|jianyang|jy|1098@jye|巨野|JYK|juye|jy|1099@jyn|揭阳南|JRQ|jieyangnan|jyn|1100@jyo|江永|JYZ|jiangyong|jy|1101@jyu|缙云|JYH|jinyun|jy|1102@jyu|靖远|JYJ|jingyuan|jy|1103@jyu|江源|SZL|jiangyuan|jy|1104@jyu|济源|JYF|jiyuan|jy|1105@jyx|靖远西|JXJ|jingyuanxi|jyx|1106@jzb|胶州北|JZK|jiaozhoubei|jzb|1107@jzd|焦作东|WEF|jiaozuodong|jzd|1108@jzh|金寨|JZH|jinzhai|jz|1109@jzh|蓟州|JIP|jizhou|jz|1110@jzh|靖州|JEQ|jingzhou|jz|1111@jzh|荆州|JBN|jingzhou|jz|1112@jzh|胶州|JXK|jiaozhou|jz|1113@jzh|晋州|JXP|jinzhou|jz|1114@jzn|锦州南|JOD|jinzhounan|jzn|1115@jzu|焦作|JOF|jiaozuo|jz|1116@jzw|旧庄窝|JVP|jiuzhuangwo|jzw|1117@jzz|金杖子|JYD|jinzhangzi|jzz|1118@kan|开安|KAT|kaian|ka|1119@kch|库车|KCR|kuche|kc|1120@kch|康城|KCP|kangcheng|kc|1121@kde|库都尔|KDX|kuduer|kde|1122@kdi|宽甸|KDT|kuandian|kd|1123@kdo|克东|KOB|kedong|kd|1124@kdz|昆都仑召|KDC|kundulunzhao|kdlz|1125@kji|开江|KAW|kaijiang|kj|1126@kjj|康金井|KJB|kangjinjing|kjj|1127@klq|喀喇其|KQX|kalaqi|klq|1128@klu|开鲁|KLC|kailu|kl|1129@kly|克拉玛依|KHR|kelamayi|klmy|1130@kpn|开平南|PVQ|kaipingnan|kpn|1131@kqi|口前|KQL|kouqian|kq|1132@ksh|昆山|KSH|kunshan|ks|1133@ksh|奎山|KAB|kuishan|ks|1134@ksh|克山|KSB|keshan|ks|1135@kxl|康熙岭|KXZ|kangxiling|kxl|1136@kya|昆阳|KAM|kunyang|ky|1137@kyh|克一河|KHX|keyihe|kyh|1138@kyx|开原西|KXT|kaiyuanxi|kyx|1139@kzh|康庄|KZP|kangzhuang|kz|1140@lbi|来宾|UBZ|laibin|lb|1141@lbi|老边|LLT|laobian|lb|1142@lbx|灵宝西|LPF|lingbaoxi|lbx|1143@lcd|洛川东|LRY|luochuandong|lcd|1144@lch|龙川|LUQ|longchuan|lc|1145@lch|乐昌|LCQ|lechang|lc|1146@lch|黎城|UCP|licheng|lc|1147@lch|聊城|UCK|liaocheng|lc|1148@lcu|蓝村|LCK|lancun|lc|1149@lda|两当|LDY|liangdang|ld|1150@ldo|林东|LRC|lindong|ld|1151@ldu|乐都|LDO|ledu|ld|1152@ldx|梁底下|LDP|liangdixia|ldx|1153@ldz|六道河子|LVP|liudaohezi|ldhz|1154@lfa|鲁番|LVM|lufan|lf|1155@lfa|廊坊|LJP|langfang|lf|1156@lfa|落垡|LOP|luofa|lf|1157@lfb|廊坊北|LFP|langfangbei|lfb|1158@lfu|老府|UFD|laofu|lf|1159@lga|兰岗|LNB|langang|lg|1160@lgd|龙骨甸|LGM|longgudian|lgd|1161@lgo|芦沟|LOM|lugou|lg|1162@lgo|龙沟|LGJ|longgou|lg|1163@lgu|拉古|LGB|lagu|lg|1164@lha|临海|UFH|linhai|lh|1165@lha|拉哈|LHX|laha|lh|1166@lha|凌海|JID|linghai|lh|1167@lha|林海|LXX|linhai|lh|1168@lhe|柳河|LNL|liuhe|lh|1169@lhe|六合|KLH|liuhe|lh|1170@lhu|龙华|LHP|longhua|lh|1171@lhy|滦河沿|UNP|luanheyan|lhy|1172@lhz|六合镇|LEX|liuhezhen|lhz|1173@ljd|亮甲店|LRT|liangjiadian|ljd|1174@ljd|刘家店|UDT|liujiadian|ljd|1175@ljh|刘家河|LVT|liujiahe|ljh|1176@lji|连江|LKS|lianjiang|lj|1177@lji|庐江|UJH|lujiang|lj|1178@lji|李家|LJB|lijia|lj|1179@lji|廉江|LJZ|lianjiang|lj|1180@lji|两家|UJT|liangjia|lj|1181@lji|龙江|LJX|longjiang|lj|1182@lji|罗江|LJW|luojiang|lj|1183@lji|龙嘉|UJL|longjia|lj|1184@ljk|莲江口|LHB|lianjiangkou|ljk|1185@ljl|蔺家楼|ULK|linjialou|ljl|1186@ljp|李家坪|LIJ|lijiaping|ljp|1187@lka|兰考|LKF|lankao|lk|1188@lko|林口|LKB|linkou|lk|1189@lkp|路口铺|LKQ|lukoupu|lkp|1190@lla|老莱|LAX|laolai|ll|1191@lli|拉林|LAB|lalin|ll|1192@lli|陆良|LRM|luliang|ll|1193@lli|临澧|LWQ|linli|ll|1194@lli|兰棱|LLB|lanling|ll|1195@lli|龙里|LLW|longli|ll|1196@lli|零陵|UWZ|lingling|ll|1197@llo|卢龙|UAP|lulong|ll|1198@lmd|喇嘛甸|LMX|lamadian|lmd|1199@lmd|里木店|LMB|limudian|lmd|1200@lme|洛门|LMJ|luomen|lm|1201@lna|龙南|UNG|longnan|ln|1202@lpi|梁平|UQW|liangping|lp|1203@lpi|罗平|LPM|luoping|lp|1204@lpl|落坡岭|LPP|luopoling|lpl|1205@lps|乐平市|LPG|lepingshi|lps|1206@lps|六盘山|UPJ|liupanshan|lps|1207@lqi|临清|UQK|linqing|lq|1208@lqs|龙泉寺|UQJ|longquansi|lqs|1209@lsb|乐山北|UTW|leshanbei|ls|1210@lsc|乐善村|LUM|leshancun|lsc|1211@lsd|冷水江东|UDQ|lengshuijiangdong|lsjd|1212@lsg|连山关|LGT|lianshanguan|lsg|1213@lsg|流水沟|USP|liushuigou|lsg|1214@lsh|丽水|USH|lishui|ls|1215@lsh|陵水|LIQ|lingshui|ls|1216@lsh|罗山|LRN|luoshan|ls|1217@lsh|鲁山|LAF|lushan|ls|1218@lsh|梁山|LMK|liangshan|ls|1219@lsh|灵石|LSV|lingshi|ls|1220@lsh|露水河|LUL|lushuihe|lsh|1221@lsh|庐山|LSG|lushan|ls|1222@lsp|林盛堡|LBT|linshengpu|lsp|1223@lst|柳树屯|LSD|liushutun|lst|1224@lsz|龙山镇|LAS|longshanzhen|lsz|1225@lsz|梨树镇|LSB|lishuzhen|lsz|1226@lsz|李石寨|LET|lishizhai|lsz|1227@lta|黎塘|LTZ|litang|lt|1228@lta|轮台|LAR|luntai|lt|1229@lta|芦台|LTP|lutai|lt|1230@ltb|龙塘坝|LBM|longtangba|ltb|1231@ltu|濑湍|LVZ|laituan|lt|1232@ltx|骆驼巷|LTJ|luotuoxiang|ltx|1233@lwa|李旺|VLJ|liwang|lw|1234@lwd|莱芜东|LWK|laiwudong|lwd|1235@lws|狼尾山|LRJ|langweishan|lws|1236@lwu|灵武|LNJ|lingwu|lw|1237@lwx|莱芜西|UXK|laiwuxi|lwx|1238@lxi|滦县|UXP|luanxian|lx|1239@lxi|朗乡|LXB|langxiang|lx|1240@lxi|陇县|LXY|longxian|lx|1241@lxi|临湘|LXQ|linxiang|lx|1242@lxi|林西|LXC|linxi|lx|1243@lxi|芦溪|LUG|luxi|lx|1244@lxi|良乡|LAP|liangxiang|lx|1245@lxn|莱西南|LXK|laixinan|lxn|1246@lya|略阳|LYY|lueyang|ly|1247@lya|莱阳|LYK|laiyang|ly|1248@lya|辽阳|LYT|liaoyang|ly|1249@lyd|凌源东|LDD|lingyuandong|lyd|1250@lyd|临沂东|UYK|linyidong|lyd|1251@lyg|连云港|UIH|lianyungang|lyg|1252@lyi|临颍|LNF|linying|ly|1253@lyi|老营|LXL|laoying|ly|1254@lyo|龙游|LMH|longyou|ly|1255@lyu|罗源|LVS|luoyuan|ly|1256@lyu|涟源|LAQ|lianyuan|ly|1257@lyu|涞源|LYP|laiyuan|ly|1258@lyu|林源|LYX|linyuan|ly|1259@lyx|耒阳西|LPQ|leiyangxi|lyx|1260@lze|临泽|LEJ|linze|lz|1261@lzg|龙爪沟|LZT|longzhuagou|lzg|1262@lzh|雷州|UAQ|leizhou|lz|1263@lzh|六枝|LIW|liuzhi|lz|1264@lzh|龙镇|LZA|longzhen|lz|1265@lzh|鹿寨|LIZ|luzhai|lz|1266@lzh|来舟|LZS|laizhou|lz|1267@lzh|拉鲊|LEM|lazha|lz|1268@lzq|兰州新区|LQJ|lanzhouxinqu|lzxq|1269@mas|马鞍山|MAH|maanshan|mas|1270@mba|毛坝|MBY|maoba|mb|1271@mbg|毛坝关|MGY|maobaguan|mbg|1272@mcb|麻城北|MBN|machengbei|mcb|1273@mch|渑池|MCF|mianchi|mc|1274@mch|明城|MCL|mingcheng|mc|1275@mch|庙城|MAP|miaocheng|mc|1276@mcn|渑池南|MNF|mianchinan|mcn|1277@mcp|茅草坪|KPM|maocaoping|mcp|1278@mdh|猛洞河|MUQ|mengdonghe|mdh|1279@mds|磨刀石|MOB|modaoshi|mds|1280@mdu|弥渡|MDF|midu|md|1281@mes|帽儿山|MRB|maoershan|mes|1282@mga|明港|MGN|minggang|mg|1283@mhk|梅河口|MHL|meihekou|mhk|1284@mhu|马皇|MHZ|mahuang|mh|1285@mjg|孟家岗|MGB|mengjiagang|mjg|1286@mla|美兰|MHQ|meilan|ml|1287@mld|汨罗东|MQQ|miluodong|mld|1288@mlh|马莲河|MHB|malianhe|mlh|1289@mli|麻柳|MLY|maliu|ml|1290@mli|茂林|MLD|maolin|ml|1291@mli|穆棱|MLB|muling|ml|1292@mli|茅岭|MLZ|maoling|ml|1293@mli|庙岭|MLL|miaoling|ml|1294@mli|马林|MID|malin|ml|1295@mlo|马龙|MGM|malong|ml|1296@mlt|木里图|MUD|mulitu|mlt|1297@mlu|汨罗|MLQ|miluo|ml|1298@mnh|玛纳斯湖|MNR|manasihu|mnsh|1299@mni|冕宁|UGW|mianning|mn|1300@mpa|沐滂|MPQ|mupang|mp|1301@mqh|马桥河|MQB|maqiaohe|mqh|1302@mqi|闽清|MQS|minqing|mq|1303@mqu|民权|MQF|minquan|mq|1304@msh|明水河|MUT|mingshuihe|msh|1305@msh|麻山|MAB|mashan|ms|1306@msh|眉山|MSW|meishan|ms|1307@msw|漫水湾|MKW|manshuiwan|msw|1308@msz|米沙子|MST|mishazi|msz|1309@msz|茂舍祖|MOM|maoshezu|msz|1310@mta|马踏|PWQ|mata|mt|1311@mxi|美溪|MEB|meixi|mx|1312@mxi|勉县|MVY|mianxian|mx|1313@mya|麻阳|MVQ|mayang|my|1314@myb|密云北|MUP|miyunbei|myb|1315@myi|米易|MMW|miyi|my|1316@myu|墨玉|MUR|moyu|my|1317@myu|麦园|MYS|maiyuan|my|1318@mzh|米脂|MEY|mizhi|mz|1319@mzh|庙庄|MZJ|miaozhuang|mz|1320@mzh|明珠|MFQ|mingzhu|mz|1321@nan|宁安|NAB|ningan|na|1322@nan|农安|NAT|nongan|na|1323@nbs|南博山|NBK|nanboshan|nbs|1324@nch|南仇|NCK|nanqiu|nc|1325@ncs|南城司|NSP|nanchengsi|ncs|1326@ncu|宁村|NCZ|ningcun|nc|1327@nde|宁德|NES|ningde|nd|1328@ngc|南观村|NGP|nanguancun|ngc|1329@ngd|南宫东|NFP|nangongdong|ngd|1330@ngl|南关岭|NLT|nanguanling|ngl|1331@ngu|宁国|NNH|ningguo|ng|1332@nha|宁海|NHH|ninghai|nh|1333@nhb|南华北|NHS|nanhuabei|nhb|1334@nhc|南河川|NHJ|nanhechuan|nhc|1335@nhz|泥河子|NHD|nihezi|nhz|1336@nji|宁家|NVT|ningjia|nj|1337@nji|南靖|NJS|nanjing|nj|1338@nji|牛家|NJB|niujia|nj|1339@nji|能家|NJD|nengjia|nj|1340@nko|南口|NKP|nankou|nk|1341@nkq|南口前|NKT|nankouqian|nkq|1342@nla|南朗|NNQ|nanlang|nl|1343@nli|乃林|NLD|nailin|nl|1344@nlk|尼勒克|NIR|nileke|nlk|1345@nlu|那罗|ULZ|naluo|nl|1346@nlx|宁陵县|NLF|ninglingxian|nlx|1347@nma|奈曼|NMD|naiman|nm|1348@nmi|宁明|NMZ|ningming|nm|1349@nmu|南木|NMX|nanmu|nm|1350@npu|那铺|NPZ|napu|np|1351@nqi|南桥|NQD|nanqiao|nq|1352@nqu|那曲|NQO|naqu|nq|1353@nqu|暖泉|NQJ|nuanquan|nq|1354@nta|南台|NTT|nantai|nt|1355@nto|南头|NOQ|nantou|nt|1356@nwu|宁武|NWV|ningwu|nw|1357@nwz|南湾子|NWP|nanwanzi|nwz|1358@nxb|南翔北|NEH|nanxiangbei|nxb|1359@nxi|宁乡|NXQ|ningxiang|nx|1360@nxi|内乡|NXF|neixiang|nx|1361@nxt|牛心台|NXT|niuxintai|nxt|1362@nyu|南峪|NUP|nanyu|ny|1363@nzg|娘子关|NIP|niangziguan|nzg|1364@nzh|南召|NAF|nanzhao|nz|1365@nzm|南杂木|NZT|nanzamu|nzm|1366@pan|蓬安|PAW|pengan|pa|1367@pan|平安|PAL|pingan|pa|1368@pay|平安驿|PNO|pinganyi|pay|1369@paz|磐安镇|PAJ|pananzhen|paz|1370@paz|平安镇|PZT|pinganzhen|paz|1371@pcd|蒲城东|PEY|puchengdong|pcd|1372@pch|蒲城|PCY|pucheng|pc|1373@pde|裴德|PDB|peide|pd|1374@pdi|偏店|PRP|piandian|pd|1375@pdx|坡底下|PXJ|podixia|pdx|1376@pet|瓢儿屯|PRT|piaoertun|pet|1377@pfa|平房|PFB|pingfang|pf|1378@pga|平岗|PGL|pinggang|pg|1379@pgu|平果|PGZ|pingguo|pg|1380@pgu|平关|PGM|pingguan|pg|1381@pgu|盘关|PAM|panguan|pg|1382@phb|徘徊北|PHP|paihuaibei|phb|1383@phk|平河口|PHM|pinghekou|phk|1384@phu|平湖|PHQ|pinghu|ph|1385@pjb|盘锦北|PBD|panjinbei|pjb|1386@pjd|潘家店|PDP|panjiadian|pjd|1387@pkn|皮口南|PKT|pikounan|pk|1388@pld|普兰店|PLT|pulandian|pld|1389@pli|偏岭|PNT|pianling|pl|1390@psh|平山|PSB|pingshan|ps|1391@psh|彭山|PSW|pengshan|ps|1392@psh|皮山|PSR|pishan|ps|1393@psh|磐石|PSL|panshi|ps|1394@psh|平社|PSV|pingshe|ps|1395@psh|彭水|PHW|pengshui|ps|1396@pta|平台|PVT|pingtai|pt|1397@pti|平田|PTM|pingtian|pt|1398@pti|莆田|PTS|putian|pt|1399@ptq|葡萄菁|PTW|putaojing|ptq|1400@pwa|普湾|PWT|puwan|pw|1401@pwa|平旺|PWV|pingwang|pw|1402@pxg|平型关|PGV|pingxingguan|pxg|1403@pxi|普雄|POW|puxiong|px|1404@pxi|蓬溪|KZW|pengxi|px|1405@pxi|郫县|PWW|pixian|px|1406@pya|平阳|ARH|pingyang|py|1407@pya|平洋|PYX|pingyang|py|1408@pya|平遥|PYV|pingyao|py|1409@pya|彭阳|PYJ|pengyang|py|1410@pyi|平邑|PIK|pingyi|py|1411@pyp|平原堡|PPJ|pingyuanpu|pyp|1412@pyu|平原|PYK|pingyuan|py|1413@pyu|平峪|PYP|pingyu|py|1414@pzb|平庄北|PZD|pingzhuangbei|pzb|1415@pze|彭泽|PZG|pengze|pz|1416@pzh|邳州|PJH|pizhou|pz|1417@pzi|泡子|POD|paozi|pz|1418@pzn|平庄南|PND|pingzhuangnan|pzn|1419@qan|乾安|QOT|qianan|qa|1420@qan|庆安|QAB|qingan|qa|1421@qan|迁安|QQP|qianan|qa|1422@qdb|祁东北|QRQ|qidongbei|qd|1423@qdi|七甸|QDM|qidian|qd|1424@qfd|曲阜东|QAK|qufudong|qfd|1425@qfe|庆丰|QFT|qingfeng|qf|1426@qft|奇峰塔|QVP|qifengta|qft|1427@qfu|曲阜|QFK|qufu|qf|1428@qha|琼海|QYQ|qionghai|qh|1429@qhd|秦皇岛|QTP|qinhuangdao|qhd|1430@qhe|千河|QUY|qianhe|qh|1431@qhe|清河|QIP|qinghe|qh|1432@qhm|清河门|QHD|qinghemen|qhm|1433@qhy|清华园|QHP|qinghuayuan|qhy|1434@qji|全椒|INH|quanjiao|qj|1435@qji|渠旧|QJZ|qujiu|qj|1436@qji|潜江|QJN|qianjiang|qj|1437@qji|秦家|QJB|qinjia|qj|1438@qji|綦江|QJW|qijiang|qj|1439@qjp|祁家堡|QBT|qijiapu|qjp|1440@qjx|清涧县|QNY|qingjianxian|qjx|1441@qjz|秦家庄|QZV|qinjiazhuang|qjz|1442@qlh|七里河|QLD|qilihe|qlh|1443@qli|秦岭|QLY|qinling|ql|1444@qli|渠黎|QLZ|quli|ql|1445@qlo|青龙|QIB|qinglong|ql|1446@qls|青龙山|QGH|qinglongshan|qls|1447@qme|祁门|QIH|qimen|qm|1448@qmt|前磨头|QMP|qianmotou|qmt|1449@qsh|青山|QSB|qingshan|qs|1450@qsh|确山|QSN|queshan|qs|1451@qsh|清水|QUJ|qingshui|qs|1452@qsh|前山|QXQ|qianshan|qs|1453@qsy|戚墅堰|QYH|qishuyan|qsy|1454@qti|青田|QVH|qingtian|qt|1455@qto|桥头|QAT|qiaotou|qt|1456@qtx|青铜峡|QTJ|qingtongxia|qtx|1457@qwe|前卫|QWD|qianwei|qw|1458@qwt|前苇塘|QWP|qianweitang|qwt|1459@qxi|渠县|QRW|quxian|qx|1460@qxi|祁县|QXV|qixian|qx|1461@qxi|青县|QXP|qingxian|qx|1462@qxi|桥西|QXJ|qiaoxi|qx|1463@qxu|清徐|QUV|qingxu|qx|1464@qxy|旗下营|QXC|qixiaying|qxy|1465@qya|千阳|QOY|qianyang|qy|1466@qya|泉阳|QYL|quanyang|qy|1467@qya|沁阳|QYF|qinyang|qy|1468@qyb|祁阳北|QVQ|qiyangbei|qy|1469@qyi|七营|QYJ|qiying|qy|1470@qys|庆阳山|QSJ|qingyangshan|qys|1471@qyu|清远|QBQ|qingyuan|qy|1472@qyu|清原|QYT|qingyuan|qy|1473@qzd|钦州东|QDZ|qinzhoudong|qzd|1474@qzh|钦州|QRZ|qinzhou|qz|1475@qzs|青州市|QZK|qingzhoushi|qzs|1476@ran|瑞安|RAH|ruian|ra|1477@rch|荣昌|RCW|rongchang|rc|1478@rch|瑞昌|RCG|ruichang|rc|1479@rga|如皋|RBH|rugao|rg|1480@rgu|容桂|RUQ|ronggui|rg|1481@rqi|任丘|RQP|renqiu|rq|1482@rsh|乳山|ROK|rushan|rs|1483@rsh|融水|RSZ|rongshui|rs|1484@rsh|热水|RSD|reshui|rs|1485@rxi|容县|RXZ|rongxian|rx|1486@rya|饶阳|RVP|raoyang|ry|1487@rya|汝阳|RYF|ruyang|ry|1488@ryh|绕阳河|RHD|raoyanghe|ryh|1489@rzh|汝州|ROF|ruzhou|rz|1490@sba|石坝|OBJ|shiba|sb|1491@sbc|上板城|SBP|shangbancheng|sbc|1492@sbi|施秉|AQW|shibing|sb|1493@sbn|上板城南|OBP|shangbanchengnan|sbcn|1494@sby|世博园|ZWT|shiboyuan|sby|1495@scb|双城北|SBB|shuangchengbei|scb|1496@sch|舒城|OCH|shucheng|sc|1497@sch|商城|SWN|shangcheng|sc|1498@sch|莎车|SCR|shache|sc|1499@sch|顺昌|SCS|shunchang|sc|1500@sch|神池|SMV|shenchi|sc|1501@sch|沙城|SCP|shacheng|sc|1502@sch|石城|SCT|shicheng|sc|1503@scz|山城镇|SCL|shanchengzhen|scz|1504@sda|山丹|SDJ|shandan|sd|1505@sde|绥德|ODY|suide|sd|1506@sde|顺德|ORQ|shunde|sd|1507@sdo|水洞|SIL|shuidong|sd|1508@sdu|商都|SXC|shangdu|sd|1509@sdu|十渡|SEP|shidu|sd|1510@sdw|四道湾|OUD|sidaowan|sdw|1511@sdy|顺德学院|OJQ|shundexueyuan|sdxy|1512@sfa|绅坊|OLH|shenfang|sf|1513@sfe|双丰|OFB|shuangfeng|sf|1514@sft|四方台|STB|sifangtai|sft|1515@sfu|水富|OTW|shuifu|sf|1516@sgk|三关口|OKJ|sanguankou|sgk|1517@sgl|桑根达来|OGC|sanggendalai|sgdl|1518@sgu|韶关|SNQ|shaoguan|sg|1519@sgz|上高镇|SVK|shanggaozhen|sgz|1520@sha|沙海|SED|shahai|sh|1521@sha|上杭|JBS|shanghang|sh|1522@she|蜀河|SHY|shuhe|sh|1523@she|松河|SBM|songhe|sh|1524@she|沙河|SHP|shahe|sh|1525@shk|沙河口|SKT|shahekou|shk|1526@shl|赛汗塔拉|SHC|saihantala|shtl|1527@shs|沙河市|VOP|shaheshi|shs|1528@shs|沙后所|SSD|shahousuo|shs|1529@sht|山河屯|SHL|shanhetun|sht|1530@shx|三河县|OXP|sanhexian|shx|1531@shy|四合永|OHD|siheyong|shy|1532@shz|双河镇|SEL|shuanghezhen|shz|1533@shz|三汇镇|OZW|sanhuizhen|shz|1534@shz|石河子|SZR|shihezi|shz|1535@shz|三合庄|SVP|sanhezhuang|shz|1536@sjd|三家店|ODP|sanjiadian|sjd|1537@sjh|水家湖|SQH|shuijiahu|sjh|1538@sjh|松江河|SJL|songjianghe|sjh|1539@sjh|沈家河|OJJ|shenjiahe|sjh|1540@sji|尚家|SJB|shangjia|sj|1541@sji|孙家|SUB|sunjia|sj|1542@sji|沈家|OJB|shenjia|sj|1543@sji|双吉|SML|shuangji|sj|1544@sji|松江|SAH|songjiang|sj|1545@sjk|三江口|SKD|sanjiangkou|sjk|1546@sjl|司家岭|OLK|sijialing|sjl|1547@sjn|松江南|IMH|songjiangnan|sjn|1548@sjn|石景山南|SRP|shijingshannan|sjsn|1549@sjt|邵家堂|SJJ|shaojiatang|sjt|1550@sjx|三江县|SOZ|sanjiangxian|sjx|1551@sjz|松江镇|OZL|songjiangzhen|sjz|1552@sjz|三家寨|SMM|sanjiazhai|sjz|1553@sjz|十家子|SJD|shijiazi|sjz|1554@sjz|深井子|SWT|shenjingzi|sjz|1555@sjz|施家嘴|SHM|shijiazui|sjz|1556@sld|什里店|OMP|shilidian|sld|1557@sle|疏勒|SUR|shule|sl|1558@slh|疏勒河|SHJ|shulehe|slh|1559@slh|舍力虎|VLD|shelihu|slh|1560@sli|石磷|SPB|shilin|sl|1561@sli|石林|SLM|shilin|sl|1562@sli|双辽|ZJD|shuangliao|sl|1563@sli|绥棱|SIB|suiling|sl|1564@sli|石岭|SOL|shiling|sl|1565@sln|石林南|LNM|shilinnan|sln|1566@slo|石龙|SLQ|shilong|sl|1567@slq|萨拉齐|SLC|salaqi|slq|1568@slu|索伦|SNT|suolun|sl|1569@slu|商洛|OLY|shangluo|sl|1570@slz|沙岭子|SLP|shalingzi|slz|1571@smb|石门县北|VFQ|shimenxianbei|smxb|1572@smn|三门峡南|SCF|sanmenxianan|smxn|1573@smx|三门县|OQH|sanmenxian|smx|1574@smx|神木西|OUY|shenmuxi|smx|1575@smx|三门峡西|SXF|sanmenxiaxi|smxx|1576@smx|石门县|OMQ|shimenxian|smx|1577@sni|肃宁|SYP|suning|sn|1578@son|宋|SOB|song|son|1579@spa|双牌|SBZ|shuangpai|sp|1580@spb|沙坪坝|CYW|shapingba|spb|1581@spd|四平东|PPT|sipingdong|spd|1582@spi|遂平|SON|suiping|sp|1583@spt|沙坡头|SFJ|shapotou|spt|1584@sqi|沙桥|SQM|shaqiao|sq|1585@sqn|商丘南|SPF|shangqiunan|sqn|1586@squ|水泉|SID|shuiquan|sq|1587@sqx|石泉县|SXY|shiquanxian|sqx|1588@sqz|石桥子|SQT|shiqiaozi|sqz|1589@src|石人城|SRB|shirencheng|src|1590@sre|石人|SRL|shiren|sr|1591@ssh|山市|SQB|shanshi|ss|1592@ssh|神树|SWB|shenshu|ss|1593@ssh|鄯善|SSR|shanshan|ss|1594@ssh|三水|SJQ|sanshui|ss|1595@ssh|泗水|OSK|sishui|ss|1596@ssh|松树|SFT|songshu|ss|1597@ssh|石山|SAD|shishan|ss|1598@ssh|首山|SAT|shoushan|ss|1599@ssj|三十家|SRD|sanshijia|ssj|1600@ssp|三十里堡|SST|sanshilipu|sslp|1601@ssz|双水镇|PQQ|shuangshuizhen|ssz|1602@ssz|松树镇|SSL|songshuzhen|ssz|1603@sta|松桃|MZQ|songtao|st|1604@sth|索图罕|SHX|suotuhan|sth|1605@stj|三堂集|SDH|santangji|stj|1606@sto|石头|OTB|shitou|st|1607@sto|神头|SEV|shentou|st|1608@stu|沙沱|SFM|shatuo|st|1609@swa|上万|SWP|shangwan|sw|1610@swu|孙吴|SKB|sunwu|sw|1611@swx|沙湾县|SXR|shawanxian|swx|1612@sxi|歙县|OVH|shexian|sx|1613@sxi|遂溪|SXZ|suixi|sx|1614@sxi|沙县|SAS|shaxian|sx|1615@sxi|绍兴|SOH|shaoxing|sx|1616@sxi|石岘|SXL|shixian|sx|1617@sxp|上西铺|SXM|shangxipu|sxp|1618@sxz|石峡子|SXJ|shixiazi|sxz|1619@sya|沭阳|FMH|shuyang|sy|1620@sya|绥阳|SYB|suiyang|sy|1621@sya|寿阳|SYV|shouyang|sy|1622@sya|水洋|OYP|shuiyang|sy|1623@syc|三阳川|SYJ|sanyangchuan|syc|1624@syd|上腰墩|SPJ|shangyaodun|syd|1625@syi|三营|OEJ|sanying|sy|1626@syi|顺义|SOP|shunyi|sy|1627@syj|三义井|OYD|sanyijing|syj|1628@syp|三源浦|SYL|sanyuanpu|syp|1629@syu|上虞|BDH|shangyu|sy|1630@syu|三原|SAY|sanyuan|sy|1631@syu|上园|SUD|shangyuan|sy|1632@syu|水源|OYJ|shuiyuan|sy|1633@syz|桑园子|SAJ|sangyuanzi|syz|1634@szb|绥中北|SND|suizhongbei|szb|1635@szb|苏州北|OHH|suzhoubei|szb|1636@szd|宿州东|SRH|suzhoudong|szd|1637@szd|深圳东|BJQ|shenzhendong|szd|1638@szh|深州|OZP|shenzhou|sz|1639@szh|孙镇|OZY|sunzhen|sz|1640@szh|绥中|SZD|suizhong|sz|1641@szh|尚志|SZB|shangzhi|sz|1642@szh|师庄|SNM|shizhuang|sz|1643@szi|松滋|SIN|songzi|sz|1644@szo|师宗|SEM|shizong|sz|1645@szq|苏州园区|KAH|suzhouyuanqu|szyq|1646@szq|苏州新区|ITH|suzhouxinqu|szxq|1647@tan|泰安|TMK|taian|ta|1648@tan|台安|TID|taian|ta|1649@tay|通安驿|TAJ|tonganyi|tay|1650@tba|桐柏|TBF|tongbai|tb|1651@tbe|通北|TBB|tongbei|tb|1652@tch|桐城|TTH|tongcheng|tc|1653@tch|汤池|TCX|tangchi|tc|1654@tch|郯城|TZK|tancheng|tc|1655@tch|铁厂|TCL|tiechang|tc|1656@tcu|桃村|TCK|taocun|tc|1657@tda|通道|TRQ|tongdao|td|1658@tdo|田东|TDZ|tiandong|td|1659@tga|天岗|TGL|tiangang|tg|1660@tgl|土贵乌拉|TGC|tuguiwula|tgwl|1661@tgo|通沟|TOL|tonggou|tg|1662@tgu|太谷|TGV|taigu|tg|1663@tha|塔哈|THX|taha|th|1664@tha|棠海|THM|tanghai|th|1665@the|唐河|THF|tanghe|th|1666@the|泰和|THG|taihe|th|1667@thu|太湖|TKH|taihu|th|1668@tji|团结|TIX|tuanjie|tj|1669@tjj|谭家井|TNJ|tanjiajing|tjj|1670@tjt|陶家屯|TOT|taojiatun|tjt|1671@tjw|唐家湾|PDQ|tangjiawan|tjw|1672@tjz|统军庄|TZP|tongjunzhuang|tjz|1673@tld|吐列毛杜|TMD|tuliemaodu|tlmd|1674@tlh|图里河|TEX|tulihe|tlh|1675@tli|铜陵|TJH|tongling|tl|1676@tli|田林|TFZ|tianlin|tl|1677@tli|亭亮|TIZ|tingliang|tl|1678@tli|铁力|TLB|tieli|tl|1679@tlx|铁岭西|PXT|tielingxi|tlx|1680@tmb|图们北|QSL|tumenbei|tmb|1681@tme|天门|TMN|tianmen|tm|1682@tmn|天门南|TNN|tianmennan|tmn|1683@tms|太姥山|TLS|taimushan|tms|1684@tmt|土牧尔台|TRC|tumuertai|tmet|1685@tmz|土门子|TCJ|tumenzi|tmz|1686@tna|洮南|TVT|taonan|tn|1687@tna|潼南|TVW|tongnan|tn|1688@tpc|太平川|TIT|taipingchuan|tpc|1689@tpz|太平镇|TEB|taipingzhen|tpz|1690@tqi|图强|TQX|tuqiang|tq|1691@tqi|台前|TTK|taiqian|tq|1692@tql|天桥岭|TQL|tianqiaoling|tql|1693@tqz|土桥子|TQJ|tuqiaozi|tqz|1694@tsc|汤山城|TCT|tangshancheng|tsc|1695@tsh|桃山|TAB|taoshan|ts|1696@tsh|台山|PUQ|taishan|ts|1697@tsz|塔石嘴|TIM|tashizui|tsz|1698@ttu|通途|TUT|tongtu|tt|1699@twh|汤旺河|THB|tangwanghe|twh|1700@txi|同心|TXJ|tongxin|tx|1701@txi|土溪|TSW|tuxi|tx|1702@txi|桐乡|TCH|tongxiang|tx|1703@tya|田阳|TRZ|tianyang|ty|1704@tyi|天义|TND|tianyi|ty|1705@tyi|汤阴|TYF|tangyin|ty|1706@tyl|驼腰岭|TIL|tuoyaoling|tyl|1707@tys|太阳山|TYJ|taiyangshan|tys|1708@tyu|通榆|KTT|tongyu|ty|1709@tyu|汤原|TYB|tangyuan|ty|1710@tyy|塔崖驿|TYP|tayayi|tyy|1711@tzd|滕州东|TEK|tengzhoudong|tzd|1712@tzh|台州|TZH|taizhou|tz|1713@tzh|天祝|TZJ|tianzhu|tz|1714@tzh|滕州|TXK|tengzhou|tz|1715@tzh|天镇|TZV|tianzhen|tz|1716@tzl|桐子林|TEW|tongzilin|tzl|1717@tzs|天柱山|QWH|tianzhushan|tzs|1718@wan|武安|WAP|wuan|wa|1719@wan|文安|WBP|wenan|wa|1720@waz|王安镇|WVP|wanganzhen|waz|1721@wbu|吴堡|WUY|wubu|wb|1722@wca|旺苍|WEW|wangcang|wc|1723@wcg|五叉沟|WCT|wuchagou|wcg|1724@wch|温春|WDB|wenchun|wc|1725@wch|文昌|WEQ|wenchang|wc|1726@wdc|五大连池|WRB|wudalianchi|wdlc|1727@wde|文登|WBK|wendeng|wd|1728@wdg|五道沟|WDL|wudaogou|wdg|1729@wdh|五道河|WHP|wudaohe|wdh|1730@wdi|文地|WNZ|wendi|wd|1731@wdo|卫东|WVT|weidong|wd|1732@wds|武当山|WRN|wudangshan|wds|1733@wdu|望都|WDP|wangdu|wd|1734@weh|乌尔旗汗|WHX|wuerqihan|weqh|1735@wfa|潍坊|WFK|weifang|wf|1736@wft|万发屯|WFB|wanfatun|wft|1737@wfu|王府|WUT|wangfu|wf|1738@wfx|瓦房店西|WXT|wafangdianxi|wfdx|1739@wga|王岗|WGB|wanggang|wg|1740@wgo|武功|WGY|wugong|wg|1741@wgo|湾沟|WGL|wangou|wg|1742@wgt|吴官田|WGM|wuguantian|wgt|1743@wha|乌海|WVC|wuhai|wh|1744@whe|苇河|WHB|weihe|wh|1745@whu|卫辉|WHF|weihui|wh|1746@wjc|吴家川|WCJ|wujiachuan|wjc|1747@wji|五家|WUB|wujia|wj|1748@wji|威箐|WAM|weiqing|wj|1749@wji|午汲|WJP|wuji|wj|1750@wji|渭津|WJL|weijin|wj|1751@wjw|王家湾|WJJ|wangjiawan|wjw|1752@wke|倭肯|WQB|woken|wk|1753@wks|五棵树|WKT|wukeshu|wks|1754@wlb|五龙背|WBT|wulongbei|wlb|1755@wle|万乐|WEB|wanle|wl|1756@wlg|瓦拉干|WVX|walagan|wlg|1757@wli|温岭|VHH|wenling|wl|1758@wli|五莲|WLK|wulian|wl|1759@wlq|乌拉特前旗|WQC|wulateqianqi|wltqq|1760@wlt|卧里屯|WLX|wolitun|wlt|1761@wnb|渭南北|WBY|weinanbei|wnb|1762@wne|乌奴耳|WRX|wunuer|wne|1763@wni|万宁|WNQ|wanning|wn|1764@wni|万年|WWG|wannian|wn|1765@wnn|渭南南|WVY|weinannan|wnn|1766@wnz|渭南镇|WNJ|weinanzhen|wnz|1767@wpi|沃皮|WPT|wopi|wp|1768@wqi|吴桥|WUP|wuqiao|wq|1769@wqi|汪清|WQL|wangqing|wq|1770@wqi|武清|WWP|wuqing|wq|1771@wsh|武山|WSJ|wushan|ws|1772@wsh|文水|WEV|wenshui|ws|1773@wsz|魏善庄|WSP|weishanzhuang|wsz|1774@wto|王瞳|WTP|wangtong|wt|1775@wts|五台山|WSV|wutaishan|wts|1776@wtz|王团庄|WZJ|wangtuanzhuang|wtz|1777@wwu|五五|WVR|wuwu|ww|1778@wxd|武乡东|WVV|wuxiangdong|wxd|1779@wxd|无锡东|WGH|wuxidong|wxd|1780@wxi|卫星|WVB|weixing|wx|1781@wxi|闻喜|WXV|wenxi|wx|1782@wxq|无锡新区|IFH|wuxixinqu|wxxq|1783@wxu|武穴|WXN|wuxue|wx|1784@wxu|吴圩|WYZ|wuxu|wx|1785@wya|王杨|WYB|wangyang|wy|1786@wyi|武义|RYH|wuyi|wy|1787@wyi|五营|WWB|wuying|wy|1788@wyt|瓦窑田|WIM|wayaotian|wyt|1789@wyu|五原|WYC|wuyuan|wy|1790@wzg|苇子沟|WZL|weizigou|wzg|1791@wzh|韦庄|WZY|weizhuang|wz|1792@wzh|五寨|WZV|wuzhai|wz|1793@wzt|王兆屯|WZB|wangzhaotun|wzt|1794@wzz|微子镇|WQP|weizizhen|wzz|1795@wzz|魏杖子|WKD|weizhangzi|wzz|1796@xan|新安|EAM|xinan|xa|1797@xan|兴安|XAZ|xingan|xa|1798@xax|新安县|XAF|xinanxian|xax|1799@xba|新保安|XAP|xinbaoan|xba|1800@xbc|下板城|EBP|xiabancheng|xbc|1801@xbl|西八里|XLP|xibali|xbl|1802@xch|宣城|ECH|xuancheng|xc|1803@xch|兴城|XCD|xingcheng|xc|1804@xcu|小村|XEM|xiaocun|xc|1805@xcy|新绰源|XRX|xinchuoyuan|xcy|1806@xcz|下城子|XCB|xiachengzi|xcz|1807@xcz|新城子|XCT|xinchengzi|xcz|1808@xde|喜德|EDW|xide|xd|1809@xdj|小得江|EJM|xiaodejiang|xdj|1810@xdm|西大庙|XMP|xidamiao|xdm|1811@xdo|小东|XOD|xiaodong|xd|1812@xdo|小董|XEZ|xiaodong|xd|1813@xfa|香坊|XFB|xiangfang|xf|1814@xfe|信丰|EFG|xinfeng|xf|1815@xfe|襄汾|XFV|xiangfen|xf|1816@xfe|息烽|XFW|xifeng|xf|1817@xga|新干|EGG|xingan|xg|1818@xga|轩岗|XGV|xuangang|xg|1819@xga|孝感|XGN|xiaogan|xg|1820@xgc|西固城|XUJ|xigucheng|xgc|1821@xgu|兴国|EUG|xingguo|xg|1822@xgu|西固|XIJ|xigu|xg|1823@xgy|夏官营|XGJ|xiaguanying|xgy|1824@xgz|西岗子|NBB|xigangzi|xgz|1825@xha|宣汉|XHY|xuanhan|xh|1826@xhe|襄河|XXB|xianghe|xh|1827@xhe|新和|XIR|xinhe|xh|1828@xhe|宣和|XWJ|xuanhe|xh|1829@xhj|斜河涧|EEP|xiehejian|xhj|1830@xht|新华屯|XAX|xinhuatun|xht|1831@xhu|新华|XHB|xinhua|xh|1832@xhu|新会|EFQ|xinhui|xh|1833@xhu|新晃|XLQ|xinhuang|xh|1834@xhu|新化|EHQ|xinhua|xh|1835@xhu|宣化|XHP|xuanhua|xh|1836@xhx|兴和西|XEC|xinghexi|xhx|1837@xhy|下花园|XYP|xiahuayuan|xhy|1838@xhy|小河沿|XYD|xiaoheyan|xhy|1839@xhz|小河镇|EKY|xiaohezhen|xhz|1840@xjd|徐家店|HYK|xujiadian|xjd|1841@xji|徐家|XJB|xujia|xj|1842@xji|峡江|EJG|xiajiang|xj|1843@xji|新绛|XJV|xinjiang|xj|1844@xji|辛集|ENP|xinji|xj|1845@xji|新江|XJM|xinjiang|xj|1846@xjk|西街口|EKM|xijiekou|xjk|1847@xjt|许家屯|XJT|xujiatun|xjt|1848@xjt|许家台|XTJ|xujiatai|xjt|1849@xjz|谢家镇|XMT|xiejiazhen|xjz|1850@xka|兴凯|EKB|xingkai|xk|1851@xla|香兰|XNB|xianglan|xl|1852@xla|小榄|EAQ|xiaolan|xl|1853@xld|兴隆店|XDD|xinglongdian|xld|1854@xle|新乐|ELP|xinle|xl|1855@xli|新林|XPX|xinlin|xl|1856@xli|小岭|XLB|xiaoling|xl|1857@xli|西林|XYB|xilin|xl|1858@xli|西柳|GCT|xiliu|xl|1859@xli|新李|XLJ|xinli|xl|1860@xli|仙林|XPH|xianlin|xl|1861@xlt|新立屯|XLD|xinlitun|xlt|1862@xlx|兴隆县|EXP|xinglongxian|xlx|1863@xlz|兴隆镇|XZB|xinglongzhen|xlz|1864@xlz|新立镇|XGT|xinlizhen|xlz|1865@xmi|新民|XMD|xinmin|xm|1866@xms|西麻山|XMB|ximashan|xms|1867@xmt|下马塘|XAT|xiamatang|xmt|1868@xna|孝南|XNV|xiaonan|xn|1869@xnb|咸宁北|XRN|xianningbei|xnb|1870@xni|兴宁|ENQ|xingning|xn|1871@xni|咸宁|XNN|xianning|xn|1872@xpd|犀浦东|XAW|xipudong|xpd|1873@xpi|西平|XPN|xiping|xp|1874@xpi|兴平|XPY|xingping|xp|1875@xpt|新坪田|XPM|xinpingtian|xpt|1876@xpu|霞浦|XOS|xiapu|xp|1877@xpu|溆浦|EPQ|xupu|xp|1878@xpu|犀浦|XIW|xipu|xp|1879@xqi|新青|XQB|xinqing|xq|1880@xqi|新邱|XQD|xinqiu|xq|1881@xqp|兴泉堡|XQJ|xingquanbu|xqp|1882@xrq|仙人桥|XRL|xianrenqiao|xrq|1883@xsg|小寺沟|ESP|xiaosigou|xsg|1884@xsh|杏树|XSB|xingshu|xs|1885@xsh|浠水|XZN|xishui|xs|1886@xsh|下社|XSV|xiashe|xs|1887@xsh|小市|XST|xiaoshi|xs|1888@xsh|徐水|XSP|xushui|xs|1889@xsh|夏石|XIZ|xiashi|xs|1890@xsh|秀山|ETW|xiushan|xs|1891@xsh|小哨|XAM|xiaoshao|xs|1892@xsp|新松浦|XOB|xinsongpu|xsp|1893@xst|杏树屯|XDT|xingshutun|xst|1894@xsw|许三湾|XSJ|xusanwan|xsw|1895@xta|湘潭|XTQ|xiangtan|xt|1896@xta|邢台|XTP|xingtai|xt|1897@xta|向塘|XTG|xiangtang|xt|1898@xtx|仙桃西|XAN|xiantaoxi|xtx|1899@xtz|下台子|EIP|xiataizi|xtz|1900@xwe|徐闻|XJQ|xuwen|xw|1901@xwp|新窝铺|EPD|xinwopu|xwp|1902@xwu|修武|XWF|xiuwu|xw|1903@xxi|新县|XSN|xinxian|xx|1904@xxi|息县|ENN|xixian|xx|1905@xxi|西乡|XQY|xixiang|xx|1906@xxi|湘乡|XXQ|xiangxiang|xx|1907@xxi|西峡|XIF|xixia|xx|1908@xxi|孝西|XOV|xiaoxi|xx|1909@xxj|小新街|XXM|xiaoxinjie|xxj|1910@xxx|新兴县|XGQ|xinxingxian|xxx|1911@xxz|西小召|XZC|xixiaozhao|xxz|1912@xxz|小西庄|XXP|xiaoxizhuang|xxz|1913@xya|向阳|XDB|xiangyang|xy|1914@xya|旬阳|XUY|xunyang|xy|1915@xyb|旬阳北|XBY|xunyangbei|xyb|1916@xye|兴业|SNZ|xingye|xy|1917@xyg|小雨谷|XHM|xiaoyugu|xyg|1918@xyi|新沂|VIH|xinyi|xy|1919@xyi|兴义|XRZ|xingyi|xy|1920@xyi|信宜|EEQ|xinyi|xy|1921@xyj|小月旧|XFM|xiaoyuejiu|xyj|1922@xyq|小扬气|XYX|xiaoyangqi|xyq|1923@xyu|襄垣|EIF|xiangyuan|xy|1924@xyx|夏邑县|EJH|xiayixian|xyx|1925@xyx|祥云西|EXM|xiangyunxi|xyx|1926@xyy|新友谊|EYB|xinyouyi|xyy|1927@xyz|新阳镇|XZJ|xinyangzhen|xyz|1928@xzd|徐州东|UUH|xuzhoudong|xzd|1929@xzf|新帐房|XZX|xinzhangfang|xzf|1930@xzh|新肇|XZT|xinzhao|xz|1931@xzh|悬钟|XRP|xuanzhong|xz|1932@xzh|襄州|XWN|xiangzhou|xz|1933@xzh|忻州|XXV|xinzhou|xz|1934@xzi|汐子|XZD|xizi|xz|1935@xzm|西哲里木|XRD|xizhelimu|xzlm|1936@xzz|新杖子|ERP|xinzhangzi|xzz|1937@yan|依安|YAX|yian|ya|1938@yan|姚安|YAC|yaoan|ya|1939@yan|永安|YAS|yongan|ya|1940@yax|永安乡|YNB|yonganxiang|yax|1941@ybl|亚布力|YBB|yabuli|ybl|1942@ybs|元宝山|YUD|yuanbaoshan|ybs|1943@yca|羊草|YAB|yangcao|yc|1944@ycd|秧草地|YKM|yangcaodi|ycd|1945@ych|阳澄湖|AIH|yangchenghu|ych|1946@ych|迎春|YYB|yingchun|yc|1947@ych|叶城|YER|yecheng|yc|1948@ych|盐池|YKJ|yanchi|yc|1949@ych|砚川|YYY|yanchuan|yc|1950@ych|阳春|YQQ|yangchun|yc|1951@ych|宜城|YIN|yicheng|yc|1952@ych|应城|YHN|yingcheng|yc|1953@ych|禹城|YCK|yucheng|yc|1954@ych|晏城|YEK|yancheng|yc|1955@ych|阳岔|YAL|yangcha|yc|1956@ych|阳城|YNF|yangcheng|yc|1957@ych|郓城|YPK|yuncheng|yc|1958@ych|雁翅|YAP|yanchi|yc|1959@ycl|云彩岭|ACP|yuncailing|ycl|1960@ycx|虞城县|IXH|yuchengxian|ycx|1961@ycz|营城子|YCT|yingchengzi|ycz|1962@yde|英德|YDQ|yingde|yd|1963@yde|永登|YDJ|yongdeng|yd|1964@ydi|永定|YGS|yongding|yd|1965@ydi|尹地|YDM|yindi|yd|1966@ydo|阳东|WLQ|yangdong|yd|1967@yds|雁荡山|YGH|yandangshan|yds|1968@ydu|于都|YDG|yudu|yd|1969@ydu|园墩|YAJ|yuandun|yd|1970@ydx|英德西|IIQ|yingdexi|ydx|1971@yfy|永丰营|YYM|yongfengying|yfy|1972@yga|杨岗|YRB|yanggang|yg|1973@yga|阳高|YOV|yanggao|yg|1974@ygu|阳谷|YIK|yanggu|yg|1975@yha|友好|YOB|youhao|yh|1976@yha|余杭|EVH|yuhang|yh|1977@yhc|沿河城|YHP|yanhecheng|yhc|1978@yhu|岩会|AEP|yanhui|yh|1979@yjh|羊臼河|YHM|yangjiuhe|yjh|1980@yji|永嘉|URH|yongjia|yj|1981@yji|盐津|AEW|yanjin|yj|1982@yji|阳江|WRQ|yangjiang|yj|1983@yji|余江|YHG|yujiang|yj|1984@yji|燕郊|AJP|yanjiao|yj|1985@yji|营街|YAM|yingjie|yj|1986@yji|姚家|YAT|yaojia|yj|1987@yjj|岳家井|YGJ|yuejiajing|yjj|1988@yjp|一间堡|YJT|yijianpu|yjp|1989@yjs|英吉沙|YIR|yingjisha|yjs|1990@yjs|云居寺|AFP|yunjusi|yjs|1991@yjz|燕家庄|AZK|yanjiazhuang|yjz|1992@yka|永康|RFH|yongkang|yk|1993@ykd|营口东|YGT|yingkoudong|ykd|1994@yla|银浪|YJX|yinlang|yl|1995@yla|永郎|YLW|yonglang|yl|1996@ylb|宜良北|YSM|yiliangbei|ylb|1997@yld|永乐店|YDY|yongledian|yld|1998@ylh|伊拉哈|YLX|yilaha|ylh|1999@yli|杨陵|YSY|yangling|yl|2000@yli|伊林|YLB|yilin|yl|2001@yli|彝良|ALW|yiliang|yl|2002@yli|杨林|YLM|yanglin|yl|2003@ylp|余粮堡|YLD|yuliangpu|ylp|2004@ylq|杨柳青|YQP|yangliuqing|ylq|2005@ylt|月亮田|YUM|yueliangtian|ylt|2006@yma|义马|YMF|yima|ym|2007@ymb|阳明堡|YVV|yangmingbu|ymb|2008@yme|玉门|YXJ|yumen|ym|2009@yme|云梦|YMN|yunmeng|ym|2010@ymo|元谋|YMM|yuanmou|ym|2011@yms|一面山|YST|yimianshan|yms|2012@yna|沂南|YNK|yinan|yn|2013@yna|宜耐|YVM|yinai|yn|2014@ynd|伊宁东|YNR|yiningdong|ynd|2015@yps|营盘水|YZJ|yingpanshui|yps|2016@ypu|羊堡|ABM|yangpu|yp|2017@yqb|阳泉北|YPP|yangquanbei|yqb|2018@yqi|乐清|UPH|yueqing|yq|2019@yqi|焉耆|YSR|yanqi|yq|2020@yqi|源迁|AQK|yuanqian|yq|2021@yqt|姚千户屯|YQT|yaoqianhutun|yqht|2022@yqu|阳曲|YQV|yangqu|yq|2023@ysg|榆树沟|YGP|yushugou|ysg|2024@ysh|月山|YBF|yueshan|ys|2025@ysh|偃师|YSF|yanshi|ys|2026@ysh|颍上|YVH|yingshang|ys|2027@ysh|沂水|YUK|yishui|ys|2028@ysh|榆社|YSV|yushe|ys|2029@ysh|玉石|YSJ|yushi|ys|2030@ysh|玉舍|AUM|yushe|ys|2031@ysh|窑上|ASP|yaoshang|ys|2032@ysh|元氏|YSP|yuanshi|ys|2033@ysl|杨树岭|YAD|yangshuling|ysl|2034@ysp|野三坡|AIP|yesanpo|ysp|2035@yst|榆树屯|YSX|yushutun|yst|2036@yst|榆树台|YUT|yushutai|yst|2037@ysz|鹰手营子|YIP|yingshouyingzi|ysyz|2038@yta|源潭|YTQ|yuantan|yt|2039@ytp|牙屯堡|YTZ|yatunpu|ytp|2040@yts|烟筒山|YSL|yantongshan|yts|2041@ytt|烟筒屯|YUX|yantongtun|ytt|2042@yws|羊尾哨|YWM|yangweishao|yws|2043@yxi|越西|YHW|yuexi|yx|2044@yxi|阳西|WMQ|yangxi|yx|2045@yxi|永修|ACG|yongxiu|yx|2046@yxi|攸县|YOG|youxian|yx|2047@yxx|玉溪西|YXM|yuxixi|yxx|2048@yya|弋阳|YIG|yiyang|yy|2049@yya|余姚|YYH|yuyao|yy|2050@yya|酉阳|AFW|youyang|yy|2051@yyd|岳阳东|YIQ|yueyangdong|yyd|2052@yyi|阳邑|ARP|yangyi|yy|2053@yyu|鸭园|YYL|yayuan|yy|2054@yyz|鸳鸯镇|YYJ|yuanyangzhen|yyz|2055@yzb|燕子砭|YZY|yanzibian|yzb|2056@yzh|宜州|YSZ|yizhou|yz|2057@yzh|仪征|UZH|yizheng|yz|2058@yzh|兖州|YZK|yanzhou|yz|2059@yzi|迤资|YQM|yizi|yz|2060@yzw|羊者窝|AEM|yangzhewo|yzw|2061@yzz|杨杖子|YZD|yangzhangzi|yzz|2062@zan|镇安|ZEY|zhenan|za|2063@zan|治安|ZAD|zhian|za|2064@zba|招柏|ZBP|zhaobai|zb|2065@zbw|张百湾|ZUP|zhangbaiwan|zbw|2066@zcc|中川机场|ZJJ|zhongchuanjichang|zcjc|2067@zch|枝城|ZCN|zhicheng|zc|2068@zch|子长|ZHY|zichang|zc|2069@zch|诸城|ZQK|zhucheng|zc|2070@zch|邹城|ZIK|zoucheng|zc|2071@zch|赵城|ZCV|zhaocheng|zc|2072@zda|章党|ZHT|zhangdang|zd|2073@zdi|正定|ZDP|zhengding|zd|2074@zdo|肇东|ZDB|zhaodong|zd|2075@zfp|照福铺|ZFM|zhaofupu|zfp|2076@zgt|章古台|ZGD|zhanggutai|zgt|2077@zgu|赵光|ZGB|zhaoguang|zg|2078@zhe|中和|ZHX|zhonghe|zh|2079@zhm|中华门|VNH|zhonghuamen|zhm|2080@zjb|枝江北|ZIN|zhijiangbei|zjb|2081@zjc|钟家村|ZJY|zhongjiacun|zjc|2082@zjg|朱家沟|ZUB|zhujiagou|zjg|2083@zjg|紫荆关|ZYP|zijingguan|zjg|2084@zji|周家|ZOB|zhoujia|zj|2085@zji|诸暨|ZDH|zhuji|zj|2086@zjn|镇江南|ZEH|zhenjiangnan|zjn|2087@zjt|周家屯|ZOD|zhoujiatun|zjt|2088@zjw|褚家湾|CWJ|zhujiawan|zjw|2089@zjx|湛江西|ZWQ|zhanjiangxi|zjx|2090@zjy|朱家窑|ZUJ|zhujiayao|zjy|2091@zjz|曾家坪子|ZBW|zengjiapingzi|zjpz|2092@zla|张兰|ZLV|zhanglan|zl|2093@zla|镇赉|ZLT|zhenlai|zl|2094@zli|枣林|ZIV|zaolin|zl|2095@zlt|扎鲁特|ZLD|zhalute|zlt|2096@zlx|扎赉诺尔西|ZXX|zhalainuoerxi|zlnex|2097@zmt|樟木头|ZOQ|zhangmutou|zmt|2098@zmu|中牟|ZGF|zhongmu|zm|2099@znd|中宁东|ZDJ|zhongningdong|znd|2100@zni|中宁|VNJ|zhongning|zn|2101@znn|中宁南|ZNJ|zhongningnan|znn|2102@zpi|镇平|ZPF|zhenping|zp|2103@zpi|漳平|ZPS|zhangping|zp|2104@zpu|泽普|ZPR|zepu|zp|2105@zqi|枣强|ZVP|zaoqiang|zq|2106@zqi|张桥|ZQY|zhangqiao|zq|2107@zqi|章丘|ZTK|zhangqiu|zq|2108@zrh|朱日和|ZRC|zhurihe|zrh|2109@zrl|泽润里|ZLM|zerunli|zrl|2110@zsb|中山北|ZGQ|zhongshanbei|zsb|2111@zsd|樟树东|ZOG|zhangshudong|zsd|2112@zsh|柞水|ZSY|zhashui|zs|2113@zsh|中山|ZSQ|zhongshan|zs|2114@zsh|樟树|ZSG|zhangshu|zs|2115@zsh|珠斯花|ZHD|zhusihua|zsh|2116@zsh|钟山|ZSZ|zhongshan|zs|2117@zwo|珠窝|ZOP|zhuwo|zw|2118@zwt|张维屯|ZWB|zhangweitun|zwt|2119@zwu|彰武|ZWD|zhangwu|zw|2120@zxi|钟祥|ZTN|zhongxiang|zx|2121@zxi|资溪|ZXS|zixi|zx|2122@zxi|棕溪|ZOY|zongxi|zx|2123@zxi|镇西|ZVT|zhenxi|zx|2124@zxi|张辛|ZIP|zhangxin|zx|2125@zxq|正镶白旗|ZXC|zhengxiangbaiqi|zxbq|2126@zya|紫阳|ZVY|ziyang|zy|2127@zya|枣阳|ZYN|zaoyang|zy|2128@zyb|竹园坝|ZAW|zhuyuanba|zyb|2129@zye|张掖|ZYJ|zhangye|zy|2130@zyu|镇远|ZUW|zhenyuan|zy|2131@zzd|漳州东|GOS|zhangzhoudong|zzd|2132@zzh|漳州|ZUS|zhangzhou|zz|2133@zzh|子洲|ZZY|zizhou|zz|2134@zzh|涿州|ZXP|zhuozhou|zz|2135@zzh|壮志|ZUX|zhuangzhi|zz|2136@zzh|中寨|ZZM|zhongzhai|zz|2137@zzi|咋子|ZAL|zhazi|zz|2138@zzs|卓资山|ZZC|zhuozishan|zzs|2139@zzx|株洲西|ZAQ|zhuzhouxi|zzx|2140@zzx|郑州西|XPF|zhengzhouxi|zzx|2141@abq|阿巴嘎旗|AQC|abagaqi|abgq|2142@acb|阿城北|ABB|achengbei|acb|2143@aeb|阿尔山北|ARX|aershanbei|aesb|2144@ajd|安江东|ADA|anjiangdong|ajd|2145@aji|安吉|AJU|anji|aj|2146@aks|阿克塞|AKJ|akesai|aks|2147@alt|阿勒泰|AUR|aletai|alt|2148@alx|安陆西|AXN|anluxi|alx|2149@are|安仁|ARG|anren|ar|2150@asx|安顺西|ASE|anshunxi|asx|2151@atx|安图西|AXL|antuxi|atx|2152@atx|安亭西|AXU|antingxi|atx|2153@ayd|安阳东|ADF|anyangdong|ayd|2154@bba|博白|BBZ|bobai|bb|2155@bbu|八步|BBE|babu|bb|2156@bch|栟茶|FWH|bencha|bc|2157@bdc|八达岭长城|VLP|badalingchangcheng|bdlcc|2158@bdd|保定东|BMP|baodingdong|bdd|2159@bel|博尔塔拉|BER|boertala|betl|2160@bfs|八方山|FGQ|bafangshan|bfs|2161@bgo|白沟|FEP|baigou|bg|2162@bha|滨海|YKP|binhai|bh|2163@bhb|滨海北|FCP|binhaibei|bhb|2164@bhg|滨海港|BGU|binhaigang|bhg|2165@bhx|滨海西|FHP|binhaixi|bhx|2166@bji|毕节|BOE|bijie|bj|2167@bjn|宝鸡南|BBY|baojinan|bjn|2168@bjx|北京大兴|IPP|beijingdaxing|bjdx|2169@bjz|北井子|BRT|beijingzi|bjz|2170@blz|八里甸子|BLT|balidianzi|bldz|2171@bmj|白马井|BFQ|baimajing|bmj|2172@bpi|北票|BPT|beipiao|bp|2173@bqi|宝清|BUB|baoqing|bq|2174@bsh|璧山|FZW|bishan|bs|2175@bsp|白沙铺|BSN|baishapu|bsp|2176@bsx|白水县|BGY|baishuixian|bsx|2177@bta|板塘|NGQ|bantang|bt|2178@bwd|白文东|BCV|baiwendong|bwd|2179@bxb|宾西北|BBB|binxibei|bxb|2180@bxc|本溪新城|BVT|benxixincheng|bxxc|2181@bxj|步行街|BWW|buxingjie|bxj|2182@bya|宾阳|UKZ|binyang|by|2183@byb|白云北|BVE|baiyunbei|byb|2184@byb|白云机场北|BBA|baiyunjichangbei|byjcb|2185@byd|白洋淀|FWP|baiyangdian|byd|2186@byi|宝应|BAU|baoying|by|2187@byi|百宜|FHW|baiyi|by|2188@byn|白音华南|BOD|baiyinhuanan|byhn|2189@bzb|霸州北|VPP|bazhoubei|bzb|2190@bzd|彬州东|BFY|binzhoudong|bzd|2191@bzd|巴中东|BDE|bazhongdong|bzd|2192@bzh|彬州|BXY|binzhou|bz|2193@bzh|滨州|BIK|binzhou|bz|2194@bzh|宾州|BZB|binzhou|bz|2195@bzn|亳州南|BNU|bozhounan|bzn|2196@bzx|霸州西|FOP|bazhouxi|bzx|2197@can|长安|CAA|changan|ca|2198@cax|长安西|CXA|changanxi|cax|2199@cch|澄城|CUY|chengcheng|cc|2200@cdb|承德县北|IYP|chengdexianbei|cdxb|2201@cdd|成 都东|WEI|chengdudong|cdd|2202@cdn|承德南|IVP|chengdenan|cdn|2203@cfd|曹妃甸东|POP|caofeidiandong|cfdd|2204@cfg|曹妃甸港|PGP|caofeidiangang|cfdg|2205@cgb|城固北|CBY|chenggubei|cgb|2206@cgb|长葛北|CGF|changgebei|cgb|2207@cgh|查干湖|VAT|chaganhu|cgh|2208@chd|巢湖东|GUH|chaohudong|chd|2209@cji|从江|KNW|congjiang|cj|2210@cjy|蔡家崖|EBV|caijiaya|cjy|2211@cka|茶卡|CVO|chaka|ck|2212@cld|长乐东|CIS|changledong|cld|2213@cle|长乐|CAS|changle|cl|2214@clh|长临河|FVH|changlinhe|clh|2215@cli|长流|CLA|changliu|cl|2216@cln|长乐南|CVS|changlenan|cln|2217@cln|茶陵南|CNG|chalingnan|cln|2218@cni|长宁|CNE|changning|cn|2219@cpd|常平东|FQQ|changpingdong|cpd|2220@cpn|常平南|FPQ|changpingnan|cpn|2221@cqi|长箐|CQE|changqing|cq|2222@cqq|长庆桥|CQJ|changqingqiao|cqq|2223@cqx|重 庆西|WWI|chongqingxi|cqx|2224@csb|长寿北|COW|changshoubei|csb|2225@csh|长寿湖|CSE|changshouhu|csh|2226@csh|常熟|CAU|changshu|cs|2227@csh|潮汕|CBQ|chaoshan|cs|2228@csh|常山|CSU|changshan|cs|2229@csx|长沙西|RXQ|changshaxi|csx|2230@cti|朝天|CTE|chaotian|ct|2231@ctn|长汀南|CNS|changtingnan|ctn|2232@cwu|长武|CWY|changwu|cw|2233@cxi|长兴|CBH|changxing|cx|2234@cxi|苍溪|CXE|cangxi|cx|2235@cxi|楚雄|CUM|chuxiong|cx|2236@cxi|城西|CIA|chengxi|cx|2237@cya|长阳|CYN|changyang|cy|2238@cya|潮阳|CNQ|chaoyang|cy|2239@cyh|朝阳湖|CYE|chaoyanghu|cyh|2240@cyi|昌邑|CRK|changyi|cy|2241@czd|长治东|CUF|changzhidong|czd|2242@czh|崇州|CZE|chongzhou|cz|2243@czn|长治南|CAF|changzhinan|czn|2244@czt|城子坦|CWT|chengzitan|czt|2245@dad|东安东|DCZ|dongandong|dad|2246@dba|德保|RBZ|debao|db|2247@dch|都昌|DCG|duchang|dc|2248@dch|东岔|DCJ|dongcha|dc|2249@dcn|东城南|IYQ|dongchengnan|dcn|2250@ddh|东戴河|RDD|dongdaihe|ddh|2251@ddx|丹东西|RWT|dandongxi|ddx|2252@deh|东二道河|DRB|dongerdaohe|dedh|2253@dfa|大方|DFE|dafang|df|2254@dfe|大丰|KRQ|dafeng|df|2255@dfn|大方南|DNE|dafangnan|dfn|2256@dgb|东港北|RGT|donggangbei|dgb|2257@dgg|东莞港|DGA|dongguangang|dgg|2258@dgn|大港南|DNU|dagangnan|dgn|2259@dgs|大孤山|RMT|dagushan|dgs|2260@dgu|东莞|RTQ|dongguan|dg|2261@dgx|东莞西|WGQ|dongguanxi|dgx|2262@dhb|东花园北|QBP|donghuayuanbei|dhyb|2263@dhd|鼎湖东|UWQ|dinghudong|dhd|2264@dhs|鼎湖山|NVQ|dinghushan|dhs|2265@dji|道滘|RRQ|daojiao|dj|2266@dji|垫江|DJE|dianjiang|dj|2267@dji|洞井|FWQ|dongjing|dj|2268@djk|丹江口|DON|danjiangkou|djk|2269@djk|董家口|DTK|dongjiakou|djk|2270@dju|大苴|DIM|daju|dj|2271@dko|洞口|DKA|dongkou|dk|2272@dlh|达连河|DCB|dalianhe|dlh|2273@dli|大荔|DNY|dali|dl|2274@dlz|大朗镇|KOQ|dalangzhen|dlz|2275@dml|得莫利|DTB|demoli|dml|2276@dqg|大青沟|DSD|daqinggou|dqg|2277@dqi|德清|DRH|deqing|dq|2278@dsd|东胜东|RSC|dongshengdong|dsd|2279@dsn|砀山南|PRH|dangshannan|dsn|2280@dsn|大石头南|DAL|dashitounan|dstn|2281@dtd|当涂东|OWH|dangtudong|dtd|2282@dtn|大同南|DMV|datongnan|dtn|2283@dtx|大通西|DTO|datongxi|dtx|2284@dwa|大旺|WWQ|dawang|dw|2285@dxb|定西北|DNJ|dingxibei|dxb|2286@dxc|大兴机场|IWP|daxingjichang|dxjc|2287@dxd|德兴东|DDG|dexingdong|dxd|2288@dxi|德兴|DWG|dexing|dx|2289@dxs|丹霞山|IRQ|danxiashan|dxs|2290@dya|大阳|RET|dayang|dy|2291@dyb|大冶北|DBN|dayebei|dyb|2292@dyd|都匀东|KJW|duyundong|dyd|2293@dyi|大邑|DEE|dayi|dy|2294@dyn|东营南|DOK|dongyingnan|dyn|2295@dyu|大余|DYG|dayu|dy|2296@dzd|邓州东|DDF|dengzhoudong|dzd|2297@dzd|定州东|DOP|dingzhoudong|dzd|2298@dzh|端州|WZQ|duanzhou|dz|2299@dzn|大足南|FQW|dazunan|dzn|2300@emi|额敏|EMR|emin|em|2301@ems|峨眉山|IXW|emeishan|ems|2302@epg|阿房宫|EGY|epanggong|epg|2303@ezd|鄂州东|EFN|ezhoudong|ezd|2304@fcb|防城港北|FBZ|fangchenggangbei|fcgb|2305@fcd|丰城东|FIG|fengchengdong|fcd|2306@fcd|凤城东|FDT|fengchengdong|fcd|2307@fch|富川|FDZ|fuchuan|fc|2308@fch|方城|FNF|fangcheng|fc|2309@fcx|繁昌西|PUH|fanchangxi|fcx|2310@fdu|丰都|FUW|fengdu|fd|2311@fgn|扶沟南|FGF|fugounan|fgn|2312@fhx|福海西|FHA|fuhaixi|fhx|2313@flb|涪陵北|FEW|fulingbei|flb|2314@fli|枫林|FLN|fenglin|fl|2315@fnd|阜宁东|FDU|funingdong|fnd|2316@fni|富宁|FNM|funing|fn|2317@fnn|阜宁南|FNU|funingnan|fnn|2318@fnn|阜宁南|FNU|funingnan|fnn|2319@fpi|佛坪|FUY|foping|fp|2320@fqi|法启|FQE|faqi|fq|2321@frn|芙蓉南|KCQ|furongnan|frn|2322@fsd|丰顺东|FDA|fengshundong|fsd|2323@fsh|复盛|FAW|fusheng|fs|2324@fso|抚松|FSL|fusong|fs|2325@fsx|佛山西|FOQ|foshanxi|fsx|2326@fsz|福山镇|FZQ|fushanzhen|fsz|2327@fti|福田|NZQ|futian|ft|2328@ftn|凤台南|FTU|fengtainan|ftn|2329@fxb|费县北|FBK|feixianbei|fxb|2330@fxi|阜新|FOT|fuxin|fx|2331@fya|富阳|FYU|fuyang|fy|2332@fyb|富源北|FBM|fuyuanbei|fyb|2333@fyu|抚远|FYB|fuyuan|fy|2334@fyu|富蕴|FYR|fuyun|fyu|2335@fyx|阜阳西|FXU|fuyangxi|fyx|2336@fzd|抚州东|FDG|fuzhoudong|fzd|2337@fzh|抚州|FZG|fuzhou|fz|2338@fzh|方正|FNB|fangzheng|fz|2339@fzn|福州 南|FXS|fuzhounan|fzn|2340@gad|固安东|GQP|guandong|gad|2341@gan|高安|GCG|gaoan|ga|2342@gan|广安南|VUW|guangannan|gan|2343@gan|贵安|GAE|guian|ga|2344@gbd|高碑店东|GMP|gaobeidiandong|gbdd|2345@gbk|古北口|GKP|gubeikou|gbk|2346@gcb|谷城北|GBN|guchengbei|gcb|2347@gcd|古城东|GUU|guchengdong|gcd|2348@gch|恭城|GCZ|gongcheng|gc|2349@gcn|藁城南|GUP|gaochengnan|gcn|2350@gdb|贵定北|FMW|guidingbei|gdb|2351@gdn|广德南|GNU|guangdenan|gdn|2352@gdn|葛店南|GNN|gediannan|gdn|2353@gdx|贵定县|KIW|guidingxian|gdx|2354@ghb|广汉北|GVW|guanghanbei|ghb|2355@ghu|高花|HGD|gaohua|gh|2356@gju|革居|GEM|geju|gj|2357@gle|高楞|GLB|gaoleng|gl|2358@gli|关岭|GLE|guanling|gl|2359@glx|桂林西|GEZ|guilinxi|glx|2360@gmb|高密北|GVK|gaomibei|gmb|2361@gmc|光明城|IMQ|guangmingcheng|gmc|2362@gna|灌南|GIU|guannan|gn|2363@gni|广宁|FBQ|guangning|gn|2364@gns|广宁寺|GQT|guangningsi|gns|2365@gnx|广南县|GXM|guangnanxian|gnx|2366@gpd|高平东|GVF|gaopingdong|gpd|2367@gpi|桂平|GAZ|guiping|gp|2368@gpi|高坪|GGN|gaoping|gp|2369@gpi|广平|GPP|guangping|gp|2370@gpz|弓棚子|GPT|gongpengzi|gpz|2371@gsd|赶水东|GDE|ganshuidong|gsd|2372@gsh|光山|GUN|guangshan|gs|2373@gsh|谷山|FFQ|gushan|gs|2374@gsl|观沙岭|FKQ|guanshaling|gsl|2375@gtb|古田北|GBS|gutianbei|gtb|2376@gtb|广通北|GPM|guangtongbei|gtb|2377@gtn|高台南|GAJ|gaotainan|gtn|2378@gtz|古田会址|STS|gutianhuizhi|gthz|2379@gxb|赣县北|GIG|ganxianbei|gxb|2380@gyb|高邮北|GEU|gaoyoubei|gyb|2381@gyb|贵 阳北|WNI|guiyangbei|gyb|2382@gyb|贵阳北|KQW|guiyangbei|gyb|2383@gyc|观音机场|GCU|guanyinjichang|gyjc|2384@gyd|贵阳东|KEW|guiyangdong|gyd|2385@gyo|高邮|GAU|gaoyou|gy|2386@gyu|灌云|GOU|guanyun|gy|2387@gyu|赣榆|GYU|ganyu|gy|2388@gyx|高邑西|GNP|gaoyixi|gyx|2389@gzx|赣州西|GOG|ganzhouxi|gzx|2390@had|淮安东|HAU|huaiandong|had|2391@had|淮安东|HAU|huaiandong|had|2392@han|惠安|HNS|huian|ha|2393@han|怀安|QAP|huaian|ha|2394@hap|惠安堡|KBJ|huianpu|hap|2395@hbb|淮北北|PLH|huaibeibei|hbb|2396@hbd|鹤壁东|HFF|hebidong|hbd|2397@hbs|花博山|KBT|huaboshan|hbs|2398@hcg|寒葱沟|HKB|hanconggou|hcg|2399@hch|霍城|SER|huocheng|hc|2400@hch|珲春|HUL|hunchun|hc|2401@hcj|花城街|HCA|huachengjie|hcj|2402@hdc|河东机场|HFJ|hedongjichang|hdjc|2403@hdd|横道河子东|KUX|hengdaohezidong|hdhzd|2404@hdd|邯郸东|HPP|handandong|hdd|2405@hdo|海东|LVO|haidong|hd|2406@hdo|惠东|KDQ|huidong|hd|2407@hdp|哈达铺|HDJ|hadapu|hdp|2408@hdu|花都|HAA|huadu|hd|2409@hdx|洪洞西|HTV|hongtongxi|hdx|2410@hdx|海东西|HDO|haidongxi|hdx|2411@heb|哈尔滨北|HTB|haerbinbei|hebb|2412@hfc|合肥北城|COH|hefeibeicheng|hfbc|2413@hfn|合肥南|ENH|hefeinan|hfn|2414@hfn|合肥 南|HAI|hefeinan|hfn|2415@hga|黄冈|KGN|huanggang|hg|2416@hgd|黄冈东|KAN|huanggangdong|hgd|2417@hgd|横沟桥东|HNN|henggouqiaodong|hgqd|2418@hgx|黄冈西|KXN|huanggangxi|hgx|2419@hhe|洪河|HPB|honghe|hh|2420@hhn|怀化南|KAQ|huaihuanan|hhn|2421@hhq|黄河景区|HCF|huanghejingqu|hhjq|2422@hhu|惠环|KHQ|huihuan|hh|2423@hhu|花湖|KHN|huahu|hh|2424@hhu|后湖|IHN|houhu|hh|2425@hji|怀集|FAQ|huaiji|hj|2426@hji|厚街|HJA|houjie|hj|2427@hkb|河口北|HBM|hekoubei|hkb|2428@hkl|宏克力|OKB|hongkeli|hkl|2429@hla|怀来|VQP|huailai|hl|2430@hlb|海林北|KBX|hailinbei|hlb|2431@hli|黄流|KLQ|huangliu|hl|2432@hln|黄陵南|VLY|huanglingnan|hln|2433@hmb|虎门北|HBA|humenbei|hmb|2434@hmd|虎门东|HDA|humendong|hmd|2435@hme|鲘门|KMQ|houmen|hm|2436@hme|海门|HMU|haimen|hm|2437@hme|虎门|IUQ|humen|hm|2438@hme|洪梅|HMA|hongmei|hm|2439@hmx|侯马西|HPV|houmaxi|hmx|2440@hna|衡南|HNG|hengnan|hn|2441@hnd|淮南东|HOH|huainandong|hnd|2442@hnn|淮南南|HNU|huainannan|hnn|2443@hpu|合浦|HVZ|hepu|hp|2444@hqb|横琴北|HOA|hengqinbei|hqb|2445@hqi|霍邱|FBH|huoqiu|hq|2446@hqi|横琴|HQA|hengqin|hq|2447@hrd|怀仁东|HFV|huairendong|hrd|2448@hrd|华容东|HPN|huarongdong|hrd|2449@hrn|华容南|KRN|huarongnan|hrn|2450@hsb|红寺堡北|HEJ|hongsibaobei|hsbb|2451@hsb|黑山北|HQT|heishanbei|hsb|2452@hsb|黄山北|NYH|huangshanbei|hsb|2453@hsb|黄石北|KSN|huangshibei|hsb|2454@hsb|衡水北|IHP|hengshuibei|hsb|2455@hsd|贺胜桥东|HLN|heshengqiaodong|hsqd|2456@hsh|和硕|VUR|heshuo|hs|2457@hsn|含山南|HSU|hanshannan|hsn|2458@hsn|含山南|HSU|hanshannan|hsn|2459@hsn|花山南|KNN|huashannan|hsn|2460@hss|黑山寺|HVP|heishansi|hss|2461@hsz|花山镇|HZA|huashanzhen|hsz|2462@hta|荷塘|KXQ|hetang|ht|2463@htb|黄桶北|HBE|huangtongbei|htb|2464@htd|黄土店|HKP|huangtudian|htd|2465@htg|花土沟|HTO|huatugou|htg|2466@hxi|环县|KXJ|huanxian|hx|2467@hyb|合阳北|HTY|heyangbei|hyb|2468@hyb|海阳北|HEK|haiyangbei|hyb|2469@hyi|槐荫|IYN|huaiyin|hy|2470@hyi|鄠邑|KXY|huyi|hyi|2471@hyk|花园口|HYT|huayuankou|hyk|2472@hyn|淮阳南|HVF|huaiyangnan|hyn|2473@hzd|霍州东|HWV|huozhoudong|hzd|2474@hzn|惠州南|KNQ|huizhounan|hzn|2475@jan|建安|JUL|jianan|ja|2476@jax|吉安西|JIG|jianxi|jax|2477@jcd|晋城东|JGF|jinchengdong|jcd|2478@jch|泾川|JAJ|jingchuan|jc|2479@jch|碱厂|JUT|jianchang|jc|2480@jdb|景德镇北|JDG|jingdezhenbei|jdzb|2481@jde|旌德|NSH|jingde|jd|2482@jde|建德|JDU|jiande|jd|2483@jfe|尖峰|PFQ|jianfeng|jf|2484@jha|近海|JHD|jinhai|jh|2485@jhx|蛟河西|JOL|jiaohexi|jhx|2486@jlb|军粮城北|JMP|junliangchengbei|jlcb|2487@jle|将乐|JLS|jiangle|jl|2488@jlh|贾鲁河|JLF|jialuhe|jlh|2489@jls|九郎山|KJQ|jiulangshan|jls|2490@jmb|即墨北|JVK|jimobei|jmb|2491@jmg|剑门关|JME|jianmenguan|jmg|2492@jmx|佳木斯西|JUB|jiamusixi|jmsx|2493@jnb|建宁县北|JCS|jianningxianbei|jnxb|2494@jnb|莒南北|VNK|junanbei|jnb|2495@jnd|济南东|MDK|jinandong|jnd|2496@jni|江宁|JJH|jiangning|jn|2497@jnx|江宁西|OKH|jiangningxi|jnx|2498@jod|建瓯东|JZS|jianoudong|jod|2499@jox|建瓯西|JUS|jianouxi|jox|2500@jpi|建平|JAD|jianping|jp|2501@jqi|建桥|JQA|jianqiao|jq|2502@jqn|酒泉南|JNJ|jiuquannan|jqn|2503@jrx|句容西|JWH|jurongxi|jrx|2504@jsh|建水|JSM|jianshui|js|2505@jsh|尖山|JPQ|jianshan|js|2506@jsn|界首南|JKU|jieshounan|jsn|2507@jss|界首市|JUN|jieshoushi|jss|2508@jsx|吉水西|JSG|jishuixi|jsx|2509@jxb|绩溪北|NRH|jixibei|jxb|2510@jxd|介休东|JDV|jiexiudong|jxd|2511@jxi|泾县|LOH|jingxian|jx|2512@jxi|靖西|JMZ|jingxi|jx|2513@jxi|郏县|JXF|jiaxian|jx|2514@jxn|进贤南|JXG|jinxiannan|jxn|2515@jya|揭阳|JYA|jieyang|jy|2516@jyb|江油北|JBE|jiangyoubei|jyb|2517@jyc|揭阳机场|JUA|jieyangjichang|jyjc|2518@jyn|简阳南|JOW|jianyangnan|jyn|2519@jyn|嘉峪关南|JBJ|jiayuguannan|jygn|2520@jyt|金银潭|JTN|jinyintan|jyt|2521@jyu|靖宇|JYL|jingyu|jy|2522@jyw|金月湾|PYQ|jinyuewan|jyw|2523@jyx|缙云西|PYH|jinyunxi|jyx|2524@jzh|晋中|JZV|jinzhong|jz|2525@jzh|景州|JEP|jingzhou|jz|2526@jzx|焦作西|JIF|jiaozuoxi|jzx|2527@key|库尔木依|VPR|kuermuyi|kemy|2528@kfb|开封北|KBF|kaifengbei|kfb|2529@kfs|开福寺|FLQ|kaifusi|kfs|2530@khu|开化|KHU|kaihua|kh|2531@kln|凯里南|QKW|kailinan|kln|2532@klu|库伦|KLD|kulun|kl|2533@kmn|昆明南|KOM|kunmingnan|kmn|2534@kta|葵潭|KTQ|kuitan|kt|2535@kya|开阳|KVW|kaiyang|ky|2536@kyu|昆玉|ESR|kunyu|ky|2537@kzu|喀左|KZT|kazuo|kz|2538@lad|隆安东|IDZ|longandong|lad|2539@lba|冷坝|LBE|lengba|lb|2540@lbb|来宾北|UCZ|laibinbei|lbb|2541@lbi|灵璧|GMH|lingbi|lb|2542@lbu|寮步|LTQ|liaobu|lb|2543@lby|绿博园|LCF|lvboyuan|lby|2544@lca|临沧|LXM|lincang|lc|2545@lcb|隆昌北|NWW|longchangbei|lcb|2546@lcd|乐昌东|ILQ|lechangdong|lcd|2547@lch|临城|UUP|lincheng|lc|2548@lch|罗城|VCZ|luocheng|lc|2549@lch|陵城|LGK|lingcheng|lc|2550@lcz|老城镇|ACQ|laochengzhen|lcz|2551@ldb|龙洞堡|FVW|longdongbao|ldb|2552@ldn|娄底南|UOQ|loudinan|ldn|2553@ldo|乐东|UQQ|ledong|ld|2554@ldy|离堆公园|INW|liduigongyuan|ldgy|2555@lfa|娄烦|USV|loufan|lf|2556@lfe|陆丰|LLQ|lufeng|lf|2557@lfe|来凤|LFA|laifeng|lf|2558@lfe|龙丰|KFQ|longfeng|lf|2559@lfn|禄丰南|LQM|lufengnan|lfn|2560@lfx|临汾西|LXV|linfenxi|lfx|2561@lgn|临高南|KGQ|lingaonan|lgn|2562@lgu|麓谷|BNQ|lugu|lg|2563@lhe|滦河|UDP|luanhe|lh|2564@lhn|珞璜南|LNE|luohuangnan|lhn|2565@lhu|隆回|LHA|longhui|lh|2566@lhx|漯河西|LBN|luohexi|lhx|2567@ljd|罗江东|IKW|luojiangdong|ljd|2568@lji|柳江|UQZ|liujiang|lj|2569@ljn|利津南|LNK|lijinnan|ljn|2570@ljx|庐江西|LUU|lujiangxi|ljx|2571@ljz|厉家寨|UPK|lijiazhai|ljz|2572@lkn|兰考南|LUF|lankaonan|lkn|2573@lks|龙口市|UKK|longkoushi|lks|2574@llb|兰陵北|COK|lanlingbei|llb|2575@llb|龙里北|KFW|longlibei|llb|2576@llb|沥林北|KBQ|lilinbei|llb|2577@lld|醴陵东|UKQ|lilingdong|lld|2578@lmi|芦庙|LMU|lumiao|lm|2579@lna|陇南|INJ|longnan|ln|2580@lny|辽宁朝阳|VET|liaoningchaoyang|lncy|2581@lpd|六盘水东|LDE|liupanshuidong|lpsd|2582@lpn|梁平南|LPE|liangpingnan|lpn|2583@lqi|龙桥|LQU|longqiao|lq|2584@lqn|礼泉南|UNY|liquannan|lqn|2585@lqs|龙泉市|LVU|longquanshi|lqs|2586@lqu|礼泉|LGY|liquan|lq|2587@lqu|临泉|LOU|linquan|lq|2588@lsb|龙山北|LBA|longshanbei|lsb|2589@lsd|灵石东|UDV|lingshidong|lsd|2590@lsh|乐山|IVW|leshan|ls|2591@lsh|涟水|LIU|lianshui|ls|2592@lsh|龙市|LAG|longshi|ls|2593@lsh|溧水|LDH|lishui|ls|2594@lsn|娄山关南|LSE|loushanguannan|lsgn|2595@lsx|岚山西|UWK|lanshanxi|lsx|2596@lto|乐同|LEA|letong|lt|2597@ltz|龙塘镇|LVB|longtangzhen|ltz|2598@lwb|灵武北|UWJ|lingwubei|lwb|2599@lwj|洛湾三江|KRW|luowansanjiang|lwsj|2600@lxi|莱西|LBK|laixi|lx|2601@lxi|岚县|UXV|lanxian|lx|2602@lxn|郎溪南|LXU|langxinan|lxn|2603@lya|溧阳|LEH|liyang|ly|2604@lyb|临沂北|UMK|linyibei|lyb|2605@lyb|临 沂北|III|linyibei|lyb|2606@lyi|临邑|LUK|linyi|ly|2607@lyn|柳园南|LNR|liuyuannan|lyn|2608@lyn|龙游南|LYU|longyounan|lyn|2609@lzb|鹿寨北|LSZ|luzhaibei|lzb|2610@lzb|临淄北|UEK|linzibei|lzb|2611@lzh|阆中|LZE|langzhong|lz|2612@lzn|临泽南|LDJ|linzenan|lzn|2613@lzn|六枝南|LOE|liuzhinan|lzn|2614@mad|马鞍山东|OMH|maanshandong|masd|2615@mch|毛陈|MHN|maochen|mc|2616@mex|帽儿山西|MUB|mershanxi|mesx|2617@mgd|明港东|MDN|minggangdong|mgd|2618@mhn|民和南|MNO|minhenan|mhn|2619@mji|闵集|MJN|minji|mj|2620@mla|米兰|MIR|milan|ml|2621@mla|马兰|MLR|malan|ml|2622@mle|民乐|MBJ|minle|ml|2623@mle|弥勒|MLM|mile|ml|2624@mns|玛纳斯|MSR|manasi|mns|2625@mpi|牟平|MBK|muping|mp|2626@mqb|闽清北|MBS|minqingbei|mqb|2627@mqb|民权北|MIF|minquanbei|mqb|2628@msd|眉山东|IUW|meishandong|msd|2629@msh|名山|MSE|mingshan|ms|2630@msh|蒙山|MOK|mengshan|ms|2631@msh|庙山|MSN|miaoshan|ms|2632@mxi|岷县|MXJ|minxian|mx|2633@myd|米易东|MDE|miyidong|myd|2634@myu|门源|MYO|menyuan|my|2635@myu|暮云|KIQ|muyun|my|2636@mzb|蒙自北|MBM|mengzibei|mzb|2637@mzh|孟庄|MZF|mengzhuang|mz|2638@mzi|蒙自|MZM|mengzi|mz|2639@mzx|梅州西|MXA|meizhouxi|mzx|2640@nbu|南部|NBE|nanbu|nb|2641@nca|南曹|NEF|nancao|nc|2642@ncb|南充北|NCE|nanchongbei|ncb|2643@nch|南城|NDG|nancheng|nc|2644@nch|牛车河|NHA|niuchehe|nch|2645@nch|宁城|NCD|ningcheng|nc|2646@nch|南 昌|NOG|nanchang|nc|2647@ncx|南昌西|NXG|nanchangxi|ncx|2648@ndn|宁东南|NDJ|ningdongnan|ndn|2649@ndo|宁东|NOJ|ningdong|nd|2650@nfb|南芬北|NUT|nanfenbei|nfb|2651@nfe|南丰|NFG|nanfeng|nf|2652@nhd|南湖东|NDN|nanhudong|nhd|2653@nhl|牛河梁|LKT|niuheliang|nhl|2654@nhu|南华|NAM|nanhua|nh|2655@njb|内江北|NKW|neijiangbei|njb|2656@nji|南江|FIW|nanjiang|nj|2657@njk|南江口|NDQ|nanjiangkou|njk|2658@nlg|奈林皋|NGT|nailingao|nlg|2659@nli|南陵|LLH|nanling|nl|2660@nls|牛栏山|NLP|niulanshan|nls|2661@nmu|尼木|NMO|nimu|nm|2662@nnd|南宁东|NFZ|nanningdong|nnd|2663@nnx|南宁西|NXZ|nanningxi|nnx|2664@npb|南堡北|TLP|nanpubei|npb|2665@nps|南平市|NOS|nanpingshi|nps|2666@nqn|宁强南|NOY|ningqiangnan|nqn|2667@ntx|南通西|NXU|nantongxi|ntx|2668@nxi|泥溪|NIE|nixi|nxi|2669@nxi|宁县|AXJ|ningxian|nx|2670@nxi|南雄|NCQ|nanxiong|nx|2671@nyd|南阳东|NOF|nanyangdong|nyd|2672@nyo|纳雍|NYE|nayong|ny|2673@nyz|南阳寨|NYF|nanyangzhai|nyz|2674@pan|普安|PAN|puan|pa|2675@pax|普安县|PUE|puanxian|pax|2676@pbi|屏边|PBM|pingbian|pb|2677@pbn|平坝南|PBE|pingbanan|pbn|2678@pch|平昌|PCE|pingchang|pc|2679@pdi|普定|PGW|puding|pd|2680@pdu|平度|PNK|pingdu|pd|2681@pdx|平度西|PAK|pingduxi|pdx|2682@pdx|平顶山西|PDF|pingdingshanxi|pdsx|2683@pji|蒲江|PJE|pujiang|pj|2684@pko|皮口|PUT|pikou|pk|2685@plc|盘龙城|PNN|panlongcheng|plc|2686@pls|蓬莱市|POK|penglaishi|pls|2687@pna|屏南|PNS|pingnan|pn|2688@pni|普宁|PEQ|puning|pn|2689@pnn|平南南|PAZ|pingnannan|pnn|2690@pqb|平泉北|PBP|pingquanbei|pqb|2691@psb|彭山北|PPW|pengshanbei|psb|2692@psh|屏山|PSE|pingshan|psh|2693@psh|盘山|PUD|panshan|ps|2694@psh|坪上|PSK|pingshang|ps|2695@pta|平潭|PIS|pingtan|pt|2696@pxb|萍乡北|PBG|pingxiangbei|pxb|2697@pya|濮阳|PYF|puyang|py|2698@pya|鄱阳|PYG|poyang|py|2699@pyc|平遥古城|PDV|pingyaogucheng|pygc|2700@pyd|平原东|PUK|pingyuandong|pyd|2701@pzh|平庄|PAD|pingzhuang|pz|2702@pzh|普者黑|PZM|puzhehei|pzh|2703@pzh|盘州|PAE|panzhou|pz|2704@pzh|彭州|PMW|pengzhou|pz|2705@pzn|攀枝花南|PNE|panzhihuanan|pzhn|2706@pzn|彭州南|PKW|pengzhounan|pzn|2707@qan|秦安|QGJ|qinan|qa|2708@qbd|青白江东|QFW|qingbaijiangdong|qbjd|2709@qch|庆城|QHJ|qingcheng|qc|2710@qch|青川|QCE|qingchuan|qc|2711@qch|清城|QCA|qingcheng|qc|2712@qdb|青岛北|QHK|qingdaobei|qdb|2713@qdb|青 岛北|KAI|qingdaobei|qdb|2714@qdh|千岛湖|QDU|qiandaohu|qdh|2715@qdo|祁东|QMQ|qidong|qd|2716@qdo|启东|QOU|qidong|qd|2717@qdu|青堆|QET|qingdui|qd|2718@qdx|青岛西|QUK|qingdaoxi|qdx|2719@qfe|前锋|QFB|qianfeng|qf|2720@qhb|清河门北|QBD|qinghemenbei|qhmb|2721@qhe|齐河|QIK|qihe|qh|2722@qjb|曲靖北|QBM|qujingbei|qjb|2723@qjd|綦江东|QDE|qijiangdong|qjd|2724@qji|曲江|QIM|qujiang|qj|2725@qla|邛崃|QLE|qionglai|ql|2726@qli|青莲|QEW|qinglian|ql|2727@qqn|齐齐哈尔南|QNB|qiqihaernan|qqhen|2728@qsb|清水北|QEJ|qingshuibei|qsb|2729@qsh|青神|QVW|qingshen|qs|2730@qsh|岐山|QAY|qishan|qs|2731@qsh|庆盛|QSQ|qingsheng|qs|2732@qsx|清水县|QIJ|qingshuixian|qsx|2733@qsx|曲水县|QSO|qushuixian|qsx|2734@qwe|犍为|JWE|qianwei|qwe|2735@qxd|祁县东|QGV|qixiandong|qxd|2736@qxi|乾县|QBY|qianxian|qx|2737@qxi|黔西|QXE|qianxi|qx|2738@qxn|旗下营南|QNC|qixiayingnan|qxyn|2739@qya|庆阳|QOJ|qingyang|qy|2740@qya|祁阳|QWQ|qiyang|qy|2741@qyu|庆元|QYU|qingyuan|qy|2742@qzb|青州市北|QOK|qingzhoushibei|qzsb|2743@qzd|乔庄东|QEP|qiaozhuangdong|qzd|2744@qzi|曲子|QJJ|quzi|qz|2745@qzn|全州南|QNZ|quanzhounan|qzn|2746@qzw|棋子湾|QZQ|qiziwan|qzw|2747@qzx|清镇西|QUE|qingzhenxi|qzx|2748@rbu|仁布|RUO|renbu|rb|2749@rcb|荣昌北|RQW|rongchangbei|rcb|2750@rch|荣成|RCK|rongcheng|rc|2751@rcx|瑞昌西|RXG|ruichangxi|rcx|2752@rdo|如东|RIH|rudong|rd|2753@rgn|如皋南|RNU|rugaonan|rgn|2754@rji|榕江|RVW|rongjiang|rj|2755@rkz|日喀则|RKO|rikaze|rkz|2756@rpi|饶平|RVQ|raoping|rp|2757@rqi|若羌|RQR|ruoqiang|rq|2758@rzx|日照西|KZK|rizhaoxi|rzx|2759@sbe|肃北|SBJ|subei|sb|2760@scd|舒城东|SDU|shuchengdong|scd|2761@sch|遂昌|SCU|suichang|sc|2762@scl|宋城路|SFF|songchenglu|scl|2763@sdh|三道湖|SDL|sandaohu|sdh|2764@sdo|邵东|FIQ|shaodong|sd|2765@sdx|三都县|KKW|sanduxian|sdx|2766@sfa|胜芳|SUP|shengfang|sf|2767@sfb|双峰北|NFQ|shuangfengbei|sfb|2768@she|商河|SOK|shanghe|sh|2769@sho|泗洪|GQH|sihong|sh|2770@shs|双河市|OHR|shuangheshi|shs|2771@shu|四会|AHQ|sihui|sh|2772@sjb|畲江北|SOA|shejiangbei|sjb|2773@sjd|石家庄东|SXP|shijiazhuangdong|sjzd|2774@sjn|三江南|SWZ|sanjiangnan|sjn|2775@sjx|沙井西|SJA|shajingxi|sjx|2776@sjz|三井子|OJT|sanjingzi|sjz|2777@sks|四棵树|SIR|sikeshu|sks|2778@slc|双流机场|IPW|shuangliujichang|sljc|2779@slh|双龙湖|OHB|shuanglonghu|slh|2780@sli|狮岭|SLA|shiling|sl|2781@slx|石林西|SYM|shilinxi|slx|2782@slx|双流西|IQW|shuangliuxi|slx|2783@slz|胜利镇|OLB|shenglizhen|slz|2784@smb|三明北|SHS|sanmingbei|smb|2785@smi|三明|SVS|sanming|sm|2786@smi|嵩明|SVM|songming|sm|2787@sml|树木岭|FMQ|shumuling|sml|2788@smu|神木|HMY|shenmu|sm|2789@sni|睢宁|SNU|suining|sn|2790@snq|苏尼特左旗|ONC|sunitezuoqi|sntzq|2791@spd|山坡东|SBN|shanpodong|spd|2792@sqb|沈丘北|SKF|shenqiubei|sqb|2793@sqd|商丘东|SIF|shangqiudong|sqd|2794@sqi|沈丘|SQN|shenqiu|sq|2795@sqi|宿迁|SQU|suqian|sq|2796@sqi|石桥|SQE|shiqiao|sq|2797@ssb|鄯善北|SMR|shanshanbei|ssb|2798@ssb|狮山北|NSQ|shishanbei|ssb|2799@ssb|三水北|ARQ|sanshuibei|ssb|2800@ssb|松山湖北|KUQ|songshanhubei|sshb|2801@ssh|狮山|KSQ|shishan|ss|2802@ssn|三水南|RNQ|sanshuinan|ssn|2803@ssn|泗水南|ONK|sishuinan|ssn|2804@ssn|韶山南|INQ|shaoshannan|ssn|2805@ssu|三穗|QHW|sansui|ss|2806@sti|石梯|STE|shiti|st|2807@swe|汕尾|OGQ|shanwei|sw|2808@sxb|歙县北|NPH|shexianbei|sxb|2809@sxb|绍兴北|SLH|shaoxingbei|sxb|2810@sxd|绍兴东|SSH|shaoxingdong|sxd|2811@sxi|泗县|GPH|sixian|sx|2812@sxi|始兴|IPQ|shixing|sx|2813@sxi|松溪|SIS|songxi|sx|2814@sxi|寿县|SOU|shouxian|sx|2815@sxi|随县|OVN|suixian|sx|2816@sya|泗阳|MPH|siyang|sy|2817@sya|双洋|SQS|shuangyang|sy|2818@sya|松阳|SUU|songyang|sy|2819@sya|三阳|SYU|sanyang|sy|2820@sya|射阳|SAU|sheyang|sy|2821@sya|双阳|OYT|shuangyang|sy|2822@syb|邵阳北|OVQ|shaoyangbei|syb|2823@syb|松原北|OCT|songyuanbei|syb|2824@syd|十堰东|OUN|shiyandong|syd|2825@syi|山阴|SNV|shanyin|sy|2826@syx|邵阳西|SXA|shaoyangxi|syx|2827@syx|沈阳西|OOT|shenyangxi|syx|2828@szb|深圳机场北|SBA|shenzhenjichangbei|szjcb|2829@szb|深圳北|IOQ|shenzhenbei|szb|2830@szc|深圳机场|SCA|shenzhenjichang|szjc|2831@szh|神州|SRQ|shenzhou|sz|2832@szh|桑植|SZA|sangzhi|sz|2833@szm|十字门|SIA|shizimen|szm|2834@szn|尚志南|OZB|shangzhinan|szn|2835@szn|随州南|ONN|suizhounan|szn|2836@szs|石嘴山|QQJ|shizuishan|szs|2837@szs|深圳坪山|IFQ|shenzhenpingshan|szps|2838@szx|石柱县|OSW|shizhuxian|szx|2839@tan|台安南|TAD|taiannan|tan|2840@tca|太仓|TCU|taicang|tc|2841@tcb|桃村北|TOK|taocunbei|tcb|2842@tcd|桐城东|TOU|tongchengdong|tcd|2843@tcg|铁厂沟|TJR|tiechanggou|tcg|2844@tch|塔城|TZR|tacheng|tc|2845@tcn|桐城南|TUU|tongchengnan|tcn|2846@tcn|太仓南|TNU|taicangnan|tcn|2847@tcs|铁刹山|PST|tiechashan|tcs|2848@tdb|田东北|TBZ|tiandongbei|tdb|2849@tdd|土地堂东|TTN|tuditangdong|tdtd|2850@tgd|太谷东|TEV|taigudong|tgd|2851@tgk|铁干里克|VAR|tieganlike|tglk|2852@tgx|太谷西|TIV|taiguxi|tgx|2853@tha|吐哈|THR|tuha|th|2854@tha|通海|TAM|tonghai|th|2855@thb|太和北|JYN|taihebei|thb|2856@thc|天河机场|TJN|tianhejichang|thjc|2857@thd|太和东|TDU|taihedong|thd|2858@thj|天河街|TEN|tianhejie|thj|2859@thn|唐海南|IEP|tanghainan|thn|2860@thx|通化县|TXL|tonghuaxian|thx|2861@tji|同江|TJB|tongjiang|tj|2862@tkd|托克托东|TVC|tuoketuodong|tktd|2863@tlb|铜陵北|KXH|tonglingbei|tlb|2864@tlb|吐鲁番北|TAR|tulufanbei|tlfb|2865@tlu|桐庐|TLU|tonglu|tl|2866@tmk|图木舒克|TMR|tumushuke|tmsk|2867@tni|泰宁|TNS|taining|tn|2868@trn|铜仁南|TNW|tongrennan|trn|2869@tsb|甜水堡|TUJ|tianshuibu|tsb|2870@tsn|天水南|TIJ|tianshuinan|tsn|2871@twe|通渭|TWJ|tongwei|tw|2872@txd|田心东|KQQ|tianxindong|txd|2873@txh|汤逊湖|THN|tangxunhu|txh|2874@txi|藤县|TAZ|tengxian|tx|2875@tyn|太原南|TNV|taiyuannan|tyn|2876@tyu|桃源|TYA|taoyuan|ty|2877@tyx|通远堡西|TST|tongyuanpuxi|typx|2878@tzb|桐梓北|TBE|tongzibei|tzb|2879@tzc|太子城|IZP|taizicheng|tzc|2880@tzd|桐梓东|TDE|tongzidong|tzd|2881@tzh|通州|TOP|tongzhou|tz|2882@wax|万安县|WAG|wananxian|wax|2883@wch|吴川|WAQ|wuchuan|wc|2884@wdd|文登东|WGK|wendengdong|wdd|2885@wdx|武当山西|WWN|wudangshanxi|wdsx|2886@wfb|潍坊北|WJK|weifangbei|wfb|2887@wfs|五府山|WFG|wufushan|wfs|2888@whb|威虎岭北|WBL|weihulingbei|whlb|2889@whb|芜湖北|WBU|wuhubei|whb|2890@whb|威海北|WHK|weihaibei|whb|2891@whn|芜湖南|RVH|wuhunan|whn|2892@whx|苇河西|WIB|weihexi|whx|2893@wji|温江|WJE|wenjiang|wj|2894@wjq|魏家泉|WJR|weijiaquan|wjq|2895@wlb|乌兰察布|WPC|wulanchabu|wlcb|2896@wld|五龙背东|WMT|wulongbeidong|wlbd|2897@wln|乌龙泉南|WFN|wulongquannan|wlqn|2898@wlt|乌兰木图|VLT|wulanmutu|wlmt|2899@wnd|望牛墩|WNA|wangniudun|wnd|2900@wns|五女山|WET|wunvshan|wns|2901@wnx|渭南西|WXY|weinanxi|wnx|2902@wsh|巍山|WOM|weishan|ws|2903@wsh|武胜|WSE|wusheng|ws|2904@wsq|乌审旗|WGC|wushenqi|wsq|2905@wsu|乌苏|WSR|wusu|ws|2906@wto|五通|WTZ|wutong|wt|2907@wwe|无为|IIH|wuwei|ww|2908@wwn|无为南|WWU|wuweinan|wwn|2909@wws|瓦屋山|WAH|wawushan|wws|2910@wxi|威信|WXE|weixin|wx|2911@wxi|武乡|WUV|wuxiang|wx|2912@wxx|闻喜西|WOV|wenxixi|wxx|2913@wyb|武义北|WDH|wuyibei|wyb|2914@wyb|武夷山北|WBS|wuyishanbei|wysb|2915@wyu|婺源|WYG|wuyuan|wy|2916@wyu|渭源|WEJ|weiyuan|wy|2917@wza|湾仔|WZA|wanzai|wz|2918@wzb|万州北|WZE|wanzhoubei|wzb|2919@wzb|湾仔北|WBA|wanzaibei|wzb|2920@wzh|吴忠|WVJ|wuzhong|wz|2921@wzh|武陟|WIF|wuzhi|wz|2922@wzn|梧州南|WBZ|wuzhounan|wzn|2923@wzn|湾沚南|WNU|wanzhinan|wzn|2924@xab|兴安北|XDZ|xinganbei|xab|2925@xan|雄安|IQP|xiongan|xa|2926@xcb|许昌北|EBF|xuchangbei|xcb|2927@xcd|许昌东|XVF|xuchangdong|xcd|2928@xch|项城|ERN|xiangcheng|xc|2929@xdd|新都东|EWW|xindudong|xdd|2930@xdu|西渡|XDA|xidu|xd|2931@xfe|咸丰|XFA|xianfeng|xf|2932@xfe|西丰|XFT|xifeng|xf|2933@xfe|先锋|NQQ|xianfeng|xf|2934@xfl|湘府路|FVQ|xiangfulu|xfl|2935@xfx|襄汾西|XTV|xiangfenxi|xfx|2936@xgb|孝感北|XJN|xiaoganbei|xgb|2937@xgd|新干东|XGG|xingandong|xgd|2938@xgd|孝感东|GDN|xiaogandong|xgd|2939@xgx|兴国西|XIG|xingguoxi|xgx|2940@xgz|夏格庄|XZK|xiagezhuang|xgz|2941@xhb|下花园北|OKP|xiahuayuanbei|xhyb|2942@xhb|兴和北|EBC|xinghebei|xhb|2943@xhb|宣化北|VJP|xuanhuabei|xhb|2944@xhd|西湖东|WDQ|xihudong|xhd|2945@xhn|新化南|EJQ|xinhuanan|xhn|2946@xhu|西华|EHF|xihua|xh|2947@xhx|新晃西|EWQ|xinhuangxi|xhx|2948@xji|新津|IRW|xinjin|xj|2949@xjk|小金口|NKQ|xiaojinkou|xjk|2950@xjn|辛集南|IJP|xinjinan|xjn|2951@xjn|新津南|ITW|xinjinnan|xjn|2952@xla|西来|XLE|xilai|xl|2953@xmb|新民北|XOT|xinminbei|xmb|2954@xme|厦 门|EMS|xiamen|xm|2955@xnd|咸宁东|XKN|xianningdong|xnd|2956@xnn|咸宁南|UNN|xianningnan|xnn|2957@xpn|溆浦南|EMQ|xupunan|xpn|2958@xpx|西平西|EGQ|xipingxi|xpx|2959@xsx|响水县|XSU|xiangshuixian|xsx|2960@xta|仙桃|VTN|xiantao|xt|2961@xtb|湘潭北|EDQ|xiangtanbei|xtb|2962@xtd|邢台东|EDP|xingtaidong|xtd|2963@xtn|新塘南|NUQ|xintangnan|xtn|2964@xwe|兴文|XNE|xingwen|xw|2965@xwq|西乌旗|XWD|xiwuqi|xwq|2966@xwx|修武西|EXF|xiuwuxi|xwx|2967@xwx|修文县|XWE|xiuwenxian|xwx|2968@xxb|萧县北|QSH|xiaoxianbei|xxb|2969@xxb|新香坊北|RHB|xinxiangfangbei|xxfb|2970@xxd|新乡东|EGF|xinxiangdong|xxd|2971@xxi|萧县|EOH|xiaoxian|xx|2972@xya|岫岩|XXT|xiuyan|xy|2973@xyb|新余北|XBG|xinyubei|xyb|2974@xyb|咸阳北|EBY|xianyangbei|xyb|2975@xyc|西阳村|XQF|xiyangcun|xyc|2976@xyd|信阳东|OYN|xinyangdong|xyd|2977@xyd|襄垣东|EAF|xiangyuandong|xyd|2978@xyd|咸阳秦都|XOY|xianyangqindu|xyqd|2979@xyd|襄阳东|EKN|xiangyangdong|xyd|2980@xyi|秀英|XYA|xiuying|xy|2981@xyo|仙游|XWS|xianyou|xy|2982@xyu|祥云|XQM|xiangyun|xy|2983@xzc|新郑机场|EZF|xinzhengjichang|xzjc|2984@xzl|香樟路|FNQ|xiangzhanglu|xzl|2985@xzx|忻州西|IXV|xinzhouxi|xzx|2986@yan|雅安|YAE|yaan|ya|2987@yan|永安南|YQS|yongannan|yan|2988@ybi|盐边|YBE|yanbian|yb|2989@ybl|迎宾路|YFW|yingbinlu|ybl|2990@ybx|亚布力西|YSB|yabulixi|yblx|2991@ybx|宜宾西|YXE|yibinxi|ybx|2992@ycb|永城北|RGH|yongchengbei|ycb|2993@ycb|盐城北|AEH|yanchengbei|ycb|2994@ycb|运城北|ABV|yunchengbei|ycb|2995@ycd|永川东|WMW|yongchuandong|ycd|2996@ycd|禹城东|YSK|yuchengdong|ycd|2997@ycf|盐城大丰|YFU|yanchengdafeng|ycdf|2998@ych|宜春|YEG|yichun|yc|2999@ych|岳池|AWW|yuechi|yc|3000@ydh|云东海|NAQ|yundonghai|ydh|3001@ydu|姚渡|AOJ|yaodu|yd|3002@yfd|云浮东|IXQ|yunfudong|yfd|3003@yfn|永福南|YBZ|yongfunan|yfn|3004@yge|雨格|VTM|yuge|yg|3005@ygn|阳高南|AGV|yanggaonan|ygn|3006@yhe|洋河|GTH|yanghe|yh|3007@yjb|永济北|AJV|yongjibei|yjb|3008@yjx|延吉西|YXL|yanjixi|yjx|3009@ykl|英库勒|YLR|yinfkule|ykl|3010@ykn|永康南|QUH|yongkangnan|ykn|3011@yla|依兰|YEB|yilan|yl|3012@ylh|运粮河|YEF|yunlianghe|ylh|3013@yli|尉犁|WRR|yuli|yl|3014@yli|炎陵|YAG|yanling|yl|3015@yli|鄢陵|YIF|yanling|yl|3016@yln|杨陵南|YEY|yanglingnan|yln|3017@yma|羊马|YME|yangma|ym|3018@ymb|一面坡北|YXB|yimianpobei|ympb|3019@ymd|云梦东|YRN|yunmengdong|ymd|3020@ymi|伊敏|YMX|yimin|ym|3021@ymx|元谋西|AMM|yuanmouxi|ymx|3022@yna|郁南|YKQ|yunan|yn|3023@yny|云南驿|ANM|yunnanyi|yny|3024@ypd|延平东|ADS|yanpingdong|ypd|3025@ypi|延平|YPS|yanping|yp|3026@ypi|银瓶|KPQ|yinping|yp|3027@ypx|延平西|YWS|yanpingxi|ypx|3028@ypx|原平西|IPV|yuanpingxi|ypx|3029@yqd|阳泉东|AYP|yangquandong|yqd|3030@yqh|雁栖湖|FGP|yanqihu|yqh|3031@yqi|杨桥|YQA|yangqiao|yq|3032@yqx|阳曲西|IQV|yangquxi|yqx|3033@yre|永仁|ARM|yongren|yr|3034@ysb|颍上北|YBU|yingshangbei|ysb|3035@ysh|永寿|ASY|yongshou|ys|3036@ysh|阳朔|YCZ|yangshuo|ys|3037@ysh|云山|KZQ|yunshan|ys|3038@ysn|玉山南|YGG|yushannan|ysn|3039@ysn|雁石南|YMS|yanshinan|ysn|3040@ysx|永寿西|AUY|yongshouxi|ysx|3041@ysx|榆社西|AXV|yushexi|ysx|3042@yta|永泰|YTS|yongtai|yt|3043@yta|银滩|CTQ|yintan|yt|3044@ytb|鹰潭北|YKG|yingtanbei|ytb|3045@ytk|依吞布拉克|YVR|yitunbulake|ytblk|3046@ytn|烟台南|YLK|yantainan|ytn|3047@yto|伊通|YTL|yitong|yt|3048@ytx|烟台西|YTK|yantaixi|ytx|3049@yxi|尤溪|YXS|youxi|yx|3050@yxi|云霄|YBS|yunxiao|yx|3051@yxi|宜兴|YUH|yixing|yx|3052@yxi|云县|AIM|yunxian|yx|3053@yxi|玉溪|AXM|yuxi|yx|3054@yxi|阳信|YVK|yangxin|yx|3055@yxi|应县|YZV|yingxian|yx|3056@yxn|攸县南|YXG|youxiannan|yxn|3057@yxx|洋县西|YXY|yangxianxi|yxx|3058@yxx|义县西|YSD|yixianxi|yxx|3059@yyb|余姚北|CTH|yuyaobei|yyb|3060@yzd|扬州东|YDU|yangzhoudong|yzd|3061@yzh|银盏|YZA|yinzhan|yz|3062@yzh|禹州|YZF|yuzhou|yz|3063@yzh|榆中|IZJ|yuzhong|yz|3064@zan|诏安|ZDS|zhaoan|za|3065@zbb|淄博北|ZRK|zibobei|zbb|3066@zdc|正定机场|ZHP|zhengdingjichang|zdjc|3067@zdo|准东|ZER|zhundong|zd|3068@zfd|纸坊东|ZMN|zhifangdong|zfd|3069@zga|柘皋|ZGU|zhegao|zg|3070@zge|准格尔|ZEC|zhungeer|zge|3071@zhb|庄河北|ZUT|zhuanghebei|zhb|3072@zhe|政和|ZES|zhenghe|zh|3073@zhl|珠海长隆|ZLA|zhuhaichanglong|zhcl|3074@zhu|昭化|ZHW|zhaohua|zh|3075@zjb|织金北|ZJE|zhijinbei|zjb|3076@zjc|张家川|ZIJ|zhangjiachuan|zjc|3077@zjg|张家港|ZAU|zhangjiagang|zjg|3078@zji|织金|IZW|zhijin|zj|3079@zji|芷江|ZPQ|zhijiang|zj|3080@zjn|张家口南|IXP|zhangjiakounan|zjkn|3081@zjx|张家界西|JXA|zhangjiajiexi|zjjx|3082@zka|仲恺|KKQ|zhongkai|zk|3083@zkd|周口东|ZKF|zhoukoudong|zkd|3084@zko|曾口|ZKE|zengkou|zk|3085@zli|珠琳|ZOM|zhulin|zl|3086@zli|左岭|ZSN|zuoling|zl|3087@zmd|樟木头东|ZRQ|zhangmutoudong|zmtd|3088@zmx|驻马店西|ZLN|zhumadianxi|zmdx|3089@zni|周宁|ZNS|zhouning|zn|3090@zpi|邹平|ZLK|zouping|zp|3091@zpu|漳浦|ZCS|zhangpu|zp|3092@zpx|漳平西|ZXG|zhangpingxi|zpx|3093@zqb|章丘北|ZVK|zhangqiubei|zqb|3094@zqd|肇庆东|FCQ|zhaoqingdong|zqd|3095@zqi|庄桥|ZQH|zhuangqiao|zq|3096@zsh|昭山|KWQ|zhaoshan|zs|3097@zsx|钟山西|ZAZ|zhongshanxi|zsx|3098@zsz|朱砂古镇|ZSE|zhushaguzhen|zsgz|3099@zta|中堂|ZTA|zhongtang|zt|3100@zts|支提山|ZIS|zhitishan|zts|3101@zwn|中卫南|ZTJ|zhongweinan|zwn|3102@zxi|漳县|ZXJ|zhangxian|zx|3103@zxi|镇雄|ZXE|zhenxiong|zx|3104@zyb|资阳北|FYW|ziyangbei|zyb|3105@zyi|遵义|ZYE|zunyi|zy|3106@zyn|遵义南|ZNE|zunyinan|zyn|3107@zyx|张掖西|ZEJ|zhangyexi|zyx|3108@zzb|资中北|WZW|zizhongbei|zzb|3109@zzd|枣庄东|ZNK|zaozhuangdong|zzd|3110@zzd|卓资东|ZDC|zhuozidong|zzd|3111@zzd|涿州东|ZAP|zhuozhoudong|zzd|3112@zzd|郑州东|ZAF|zhengzhoudong|zzd|3113@zzn|株洲南|KVQ|zhuzhounan|zzn|3114'; \ No newline at end of file diff --git a/src/12306/tmp/__init__.py b/src/12306/tmp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/tmp/log/__init__.py b/src/12306/tmp/log/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/uml/REIL_DEVICEID.png b/src/12306/uml/REIL_DEVICEID.png new file mode 100644 index 0000000..9f201ae Binary files /dev/null and b/src/12306/uml/REIL_DEVICEID.png differ diff --git a/src/12306/uml/uml.png b/src/12306/uml/uml.png new file mode 100644 index 0000000..b8ed4c8 Binary files /dev/null and b/src/12306/uml/uml.png differ diff --git a/src/12306/uml/wx.jpeg b/src/12306/uml/wx.jpeg new file mode 100644 index 0000000..df53a48 Binary files /dev/null and b/src/12306/uml/wx.jpeg differ diff --git a/src/12306/uml/zfb.jpeg b/src/12306/uml/zfb.jpeg new file mode 100644 index 0000000..3ec49b2 Binary files /dev/null and b/src/12306/uml/zfb.jpeg differ diff --git a/src/12306/uml/登录.png b/src/12306/uml/登录.png new file mode 100644 index 0000000..9d5db08 Binary files /dev/null and b/src/12306/uml/登录.png differ diff --git a/src/12306/uml/程序主界面.png b/src/12306/uml/程序主界面.png new file mode 100644 index 0000000..0deccff Binary files /dev/null and b/src/12306/uml/程序主界面.png differ diff --git a/src/12306/verify/__init__.py b/src/12306/verify/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/12306/verify/localVerifyCode.py b/src/12306/verify/localVerifyCode.py new file mode 100644 index 0000000..06564e6 --- /dev/null +++ b/src/12306/verify/localVerifyCode.py @@ -0,0 +1,115 @@ +# coding: utf-8 +import TickerConfig + +if TickerConfig.AUTO_CODE_TYPE == 2: + import base64 + import os + import cv2 + import numpy as np + from keras import models, backend + import tensorflow as tf + from verify import pretreatment + from verify.mlearn_for_image import preprocess_input + + graph = tf.get_default_graph() + +PATH = lambda p: os.path.abspath( + os.path.join(os.path.dirname(__file__), p) +) + + +TEXT_MODEL = "" +IMG_MODEL = "" + + +def get_text(img, offset=0): + text = pretreatment.get_text(img, offset) + text = cv2.cvtColor(text, cv2.COLOR_BGR2GRAY) + text = text / 255.0 + h, w = text.shape + text.shape = (1, h, w, 1) + return text + + +def base64_to_image(base64_code): + # base64解码 + img_data = base64.b64decode(base64_code) + # 转换为np数组 + img_array = np.fromstring(img_data, np.uint8) + # 转换成opencv可用格式 + img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR) + + return img + + +class Verify: + def __init__(self): + self.textModel = "" + self.imgModel = "" + self.loadImgModel() + self.loadTextModel() + + def loadTextModel(self): + if not self.textModel: + self.textModel = models.load_model(PATH('../model.v2.0.h5')) + else: + print("无需加载模型model.v2.0.h5") + + def loadImgModel(self): + if not self.imgModel: + self.imgModel = models.load_model(PATH('../12306.image.model.h5')) + + def verify(self, fn): + verify_titles = ['打字机', '调色板', '跑步机', '毛线', '老虎', '安全帽', '沙包', '盘子', '本子', '药片', '双面胶', '龙舟', '红酒', '拖把', '卷尺', + '海苔', '红豆', '黑板', '热水袋', '烛台', '钟表', '路灯', '沙拉', '海报', '公交卡', '樱桃', '创可贴', '牌坊', '苍蝇拍', '高压锅', + '电线', '网球拍', '海鸥', '风铃', '订书机', '冰箱', '话梅', '排风机', '锅铲', '绿豆', '航母', '电子秤', '红枣', '金字塔', '鞭炮', + '菠萝', '开瓶器', '电饭煲', '仪表盘', '棉棒', '篮球', '狮子', '蚂蚁', '蜡烛', '茶盅', '印章', '茶几', '啤酒', '档案袋', '挂钟', '刺绣', + '铃铛', '护腕', '手掌印', '锦旗', '文具盒', '辣椒酱', '耳塞', '中国结', '蜥蜴', '剪纸', '漏斗', '锣', '蒸笼', '珊瑚', '雨靴', '薯条', + '蜜蜂', '日历', '口哨'] + # 读取并预处理验证码 + img = base64_to_image(fn) + text = get_text(img) + imgs = np.array(list(pretreatment._get_imgs(img))) + imgs = preprocess_input(imgs) + text_list = [] + # 识别文字 + self.loadTextModel() + global graph + with graph.as_default(): + label = self.textModel.predict(text) + label = label.argmax() + text = verify_titles[label] + text_list.append(text) + # 获取下一个词 + # 根据第一个词的长度来定位第二个词的位置 + if len(text) == 1: + offset = 27 + elif len(text) == 2: + offset = 47 + else: + offset = 60 + text = get_text(img, offset=offset) + if text.mean() < 0.95: + with graph.as_default(): + label = self.textModel.predict(text) + label = label.argmax() + text = verify_titles[label] + text_list.append(text) + print("题目为{}".format(text_list)) + # 加载图片分类器 + self.loadImgModel() + with graph.as_default(): + labels = self.imgModel.predict(imgs) + labels = labels.argmax(axis=1) + results = [] + for pos, label in enumerate(labels): + l = verify_titles[label] + print(pos + 1, l) + if l in text_list: + results.append(str(pos + 1)) + return results + + +if __name__ == '__main__': + pass + # verify("verify-img1.jpeg") diff --git a/src/12306/verify/mlearn_for_image.py b/src/12306/verify/mlearn_for_image.py new file mode 100644 index 0000000..5724b7e --- /dev/null +++ b/src/12306/verify/mlearn_for_image.py @@ -0,0 +1,94 @@ +# coding: utf-8 +import TickerConfig +if TickerConfig.AUTO_CODE_TYPE == 2: + import sys + + import cv2 + import numpy as np + from keras import models + from keras import layers + from keras import optimizers + from keras.applications import VGG16 + from keras.callbacks import ReduceLROnPlateau + from keras.preprocessing.image import ImageDataGenerator + + +def preprocess_input(x): + x = x.astype('float32') + # 我是用cv2来读取的图片,其已经是BGR格式了 + mean = [103.939, 116.779, 123.68] + x -= mean + return x + + +def load_data(): + # 这是统计学专家提供的训练集 + data = np.load('captcha.npz') + train_x, train_y = data['images'], data['labels'] + train_x = preprocess_input(train_x) + # 由于是统计得来的信息,所以在此给定可信度 + sample_weight = train_y.max(axis=1) / np.sqrt(train_y.sum(axis=1)) + sample_weight /= sample_weight.mean() + train_y = train_y.argmax(axis=1) + + # 这是人工提供的验证集 + data = np.load('captcha.test.npz') + test_x, test_y = data['images'], data['labels'] + test_x = preprocess_input(test_x) + return (train_x, train_y, sample_weight), (test_x, test_y) + + +def learn(): + (train_x, train_y, sample_weight), (test_x, test_y) = load_data() + datagen = ImageDataGenerator(horizontal_flip=True, + vertical_flip=True) + train_generator = datagen.flow(train_x, train_y, sample_weight=sample_weight) + base = VGG16(weights='imagenet', include_top=False, input_shape=(None, None, 3)) + for layer in base.layers[:-4]: + layer.trainable = False + model = models.Sequential([ + base, + layers.BatchNormalization(), + layers.Conv2D(64, (3, 3), activation='relu', padding='same'), + layers.GlobalAveragePooling2D(), + layers.BatchNormalization(), + layers.Dense(64, activation='relu'), + layers.BatchNormalization(), + layers.Dropout(0.20), + layers.Dense(80, activation='softmax') + ]) + model.compile(optimizer=optimizers.RMSprop(lr=1e-5), + loss='sparse_categorical_crossentropy', + metrics=['accuracy']) + model.summary() + reduce_lr = ReduceLROnPlateau(verbose=1) + model.fit_generator(train_generator, epochs=400, + steps_per_epoch=100, + validation_data=(test_x[:800], test_y[:800]), + callbacks=[reduce_lr]) + result = model.evaluate(test_x, test_y) + print(result) + model.save('12306.image.model.h5', include_optimizer=False) + + +def predict(imgs): + imgs = preprocess_input(imgs) + model = models.load_model('12306.image.model.h5') + labels = model.predict(imgs) + return labels + + +def _predict(fn): + imgs = cv2.imread(fn) + imgs = cv2.resize(imgs, (67, 67)) + imgs.shape = (-1, 67, 67, 3) + labels = predict(imgs) + print(labels.max(axis=1)) + print(labels.argmax(axis=1)) + + +if __name__ == '__main__': + if len(sys.argv) >= 2: + _predict(sys.argv[1]) + else: + learn() diff --git a/src/12306/verify/pretreatment.py b/src/12306/verify/pretreatment.py new file mode 100644 index 0000000..9171434 --- /dev/null +++ b/src/12306/verify/pretreatment.py @@ -0,0 +1,102 @@ +#! env python +# coding: utf-8 +# 功能:对图像进行预处理,将文字部分单独提取出来 +# 并存放到ocr目录下 +# 文件名为原验证码文件的文件名 +import TickerConfig +if TickerConfig.AUTO_CODE_TYPE == 2: + import hashlib + import os + import pathlib + + import cv2 + import numpy as np + import requests + import scipy.fftpack + + +PATH = 'imgs' + + +def download_image(): + # 抓取验证码 + # 存放到指定path下 + # 文件名为图像的MD5 + url = 'https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand' + r = requests.get(url) + fn = hashlib.md5(r.content).hexdigest() + with open(f'{PATH}/{fn}.jpg', 'wb') as fp: + fp.write(r.content) + + +def download_images(): + pathlib.Path(PATH).mkdir(exist_ok=True) + for idx in range(40000): + download_image() + print(idx) + + +def get_text(img, offset=0): + # 得到图像中的文本部分 + return img[3:22, 120 + offset:177 + offset] + + +def avhash(im): + im = cv2.resize(im, (8, 8), interpolation=cv2.INTER_CUBIC) + avg = im.mean() + im = im > avg + im = np.packbits(im) + return im + + +def phash(im): + im = cv2.resize(im, (32, 32), interpolation=cv2.INTER_CUBIC) + im = scipy.fftpack.dct(scipy.fftpack.dct(im, axis=0), axis=1) + im = im[:8, :8] + med = np.median(im) + im = im > med + im = np.packbits(im) + return im + + +def _get_imgs(img): + interval = 5 + length = 67 + for x in range(40, img.shape[0] - length, interval + length): + for y in range(interval, img.shape[1] - length, interval + length): + yield img[x:x + length, y:y + length] + + +def get_imgs(img): + imgs = [] + for img in _get_imgs(img): + imgs.append(phash(img)) + return imgs + + +def pretreat(): + if not os.path.isdir(PATH): + download_images() + texts, imgs = [], [] + for img in os.listdir(PATH): + img = os.path.join(PATH, img) + img = cv2.imread(img, cv2.IMREAD_GRAYSCALE) + texts.append(get_text(img)) + imgs.append(get_imgs(img)) + return texts, imgs + + +def load_data(path='data.npz'): + if not os.path.isfile(path): + texts, imgs = pretreat() + np.savez(path, texts=texts, images=imgs) + f = np.load(path) + return f['texts'], f['images'] + + +if __name__ == '__main__': + texts, imgs = load_data() + print(texts.shape) + print(imgs.shape) + imgs = imgs.reshape(-1, 8) + print(np.unique(imgs, axis=0).shape)