一导读
本篇文章所采用的技术仅用于学习研究, 任何其他用途请自行承担后果
12306 自动查票使用到的 python 库主要是 splinter, 同时也涉及到查票的城市编码, 具体的城市编码请在网络上搜索, 基本格式如下:
北京北: VAP
北京东: BOP
北京: BJP
北京南: VNP
北京西: BXP
实现的功能包括:
(1)自动打开 Google 浏览器, 进入 12306 登录页面
(1)命令行手动输入账号密码出发目的地, 时间等相关信息, 登录验证图片需要手动选择
(2)自动填充输入, 完成查询和页面跳转
后续可以优化的功能:
(1)从配置文件中读取账号密码出发目的地, 时间等相关信息
(2)从配置文件中获取城市编码
(3)登录验证图片可以使用第三方识别自动选择
二初识 Splinter
1. 简介
Splinter 是用 Python 开发的一个开源 web 自动化测试的工具集 它可以帮你自动化浏览器的行为, 比如浏览 URLs 并和页面进行交互
Splinter 是现有浏览器之上抽象层自动化工具 (如 Selenium, PhantomJS 和 zope.testbrowser ) 它具有 高级 API , 这使得它很容易去编写 Web 应用程序的自动化测试
例如, 用 Splinter 填写一个表单项:
browser.fill('username', 'janedoe')
在 Selenium 中, 等效代码会是:
- elem = browser.find_element.by_name('username')
- elem.send_keys('janedoe')
2. 安装
命令行下执行以下命令: sudo pip install splinter
3. 快速上手
(1)导入 Browser 类
from splinter.browser import Browser
(2)创建一个实例
指定 driver 为 chrome 浏览器, 如果你不为 Browser 指定 driver, 那么会默认使用 firefox
browser = Browser(driver_name='chrome',executable_path='xxx')
其中 executable_path 为对应浏览器 driver 的本地目录
(3)访问百度搜索页面
使用 browser.visit 方法可访问任意网站:
browser.visit('http://baidu.com')
(4)输入搜索关键词
页面加载完毕后, 可以在输入框填充字段, 大过年的我们就搜索一下 2018 年新年祝福吧:
browser.fill('wd', '2018 年新年祝福')
(5)点击搜索按钮
Splinter 可以通过按钮的 CSS, xpath, id, tag 或 name 来识别, 百度搜素按钮使用以下来操作:
button = browser.find_by_xpath('//input[@type="submit"]').click()
(6)匹配结果
使用 is_text_present 查看匹配结果:
- if browser.is_text_present('春节'):
- print("找到了")
- else:
- print("没找到")
(7)关闭浏览器
结束测试后, 我们需要使用 browser.quit 关闭浏览器:
browser**.**quit()
完整代码如下:
- # -*- coding: utf-8 -*-
- # 导入 Browser 类
- from splinter.browser import Browser
- # 创建一个实例, 指定 driver 为 chrome 浏览器, 如果你不为 Browser 指定 driver, 那么会默认使用 firefox
- browser = Browser(driver_name='chrome',executable_path='/Users/xxx/Downloads/chromedriver')
- browser.visit('http://baidu.com')
- browser.fill('wd', '2018 年新年祝福')
- button = browser.find_by_xpath('//input[@type="submit"]').click()
- if browser.is_text_present('春节'):
- print("找到了")
- else:
- print("没找到")
- browser.quit()
三 12306 自动查票
1 流程分析
(1)执行 python 脚本后, 能够自动打开浏览器, 进入 12306 登录页面因此需要加载浏览器驱动并打开登录页面
(2)命令行提示用户输入用户名密码, 并等待用户手动在浏览器选择验证码完成登录
(3)命令行提示用户输入出发地目的地以及出发时间
(4)根据输入查询车次信息
2 示例代码
代码均有详细注释, 根据上面的流程分析, 我们简化为三步
第一步是加载基本信息, 包括浏览器 url 等第二步是输入个人信息登录第三步是输入查询条件查询车次信息
- # -*- coding: utf-8 -*-
- from splinter.browser import Browser
- from time import sleep
- class TicketsUtil(object):
- def __init__(self):
- self.loadBasicInfo()
- def loadBasicInfo(self):
- # 登录的 url
- self.loginUrl = 'https://kyfw.12306.cn/otn/login/init'
- #登录成功后的 url
- self.myUrl = 'https://kyfw.12306.cn/otn/index/initMy12306'
- #余票查询页面
- self.ticketUrl = 'https://kyfw.12306.cn/otn/leftTicket/init'
- # 初始化驱动
- self.driver=Browser(driver_name='chrome',executable_path='/Users/xxx/Downloads/chromedriver')
- # 初始化浏览器窗口大小
- self.driver.driver.set_window_size(1400, 1000)
- def login(self):
- print("开始登录...")
- # 登录
- self.driver.visit(self.loginUrl)
- self.username = input("\n 请输入用户名, 输入按回车...")
- #合法性判断
- while True:
- if self.username == '':
- self.username = input("\n 请输入用户名, 输入按回车...")
- else:
- break
- self.password = input("\n 请输入密码, 输入按回车...")
- #合法性判断
- while True:
- if self.password == '':
- self.password = input("\n 请输入密码, 输入按回车...")
- else:
- break
- # 自动填充用户名
- self.driver.fill("loginUserDTO.user_name", self.username)
- # 自动填充密码
- self.driver.fill("userDTO.password", self.password)
- print(u"等待验证码, 自行输入...")
- # 验证码需要自行输入, 程序自旋等待, 直到验证码通过, 点击登录
- while True:
- if self.driver.url != self.myUrl:
- sleep(1)
- else:
- break
- print(u"登录成功...")
- def query(self):
- self.source = input("\n 请输入出发地(格式为: 北京, BJP), 输入按回车...")
- #合法性判断
- while True:
- if self.source == '':
- self.source = input("\n 请输入出发地(格式为: 北京, BJP), 输入按回车...")
- else:
- break
- self.destination = input("\n 请输入目的地(格式为: 深圳, SZQ), 输入按回车...")
- while True:
- if self.destination == '':
- self.destination = input("\n 请输入目的地(格式为: 深圳, SZQ), 输入按回车...")
- else:
- break
- self.date = input("\n 请输入出发日期(格式为: 2018-02-14), 输入按回车...")
- while True:
- if self.date == '':
- self.date = input("\n 请输入出发日期, 输入按回车...")
- else:
- break
- #转换输入的出发地成 "武汉, WHN", 再进行编码
- self.source = self.source.encode('unicode_escape').decode("utf-8").replace("\\u", "%u").replace(",", "%2c")
- #转换输入的目的地
- self.destination = self.destination.encode('unicode_escape').decode("utf-8").replace("\\u", "%u").replace(",", "%2c")
- # 加载出发地
- self.driver.cookies.add({"_jc_save_fromStation": self.source})
- # 加载目的地
- self.driver.cookies.add({"_jc_save_toStation": self.destination})
- # 加载出发日
- self.driver.cookies.add({"_jc_save_fromDate": self.date})
- # 带着查询条件, 重新加载页面
- self.driver.reload()
- # 查询余票
- self.driver.find_by_text(u"查询").click()
- sleep(0.1)
- # 防止超时再次查询余票
- self.driver.find_by_text(u"查询").click()
- print('查询成功')
- """入口函数"""
- def start(self):
- self.loadBasicInfo()
- # 登录, 自动填充用户名密码, 自旋等待输入验证码, 输入完验证码, 点登录后, 访问 tick_url(余票查询页面)
- self.login()
- # 登录成功, 访问余票查询页面
- self.driver.visit(self.ticketUrl)
- self.query()
- if __name__ == '__main__':
- print(u"=========== 自动查票开启 ===========")
- ticketsUtil = TicketsUtil()
- ticketsUtil.start()
来源: https://juejin.im/entry/5a8e932d5188252478690298