一、导读

本篇文章所采用的技术仅用于学习、研究,任何其他用途请自行承担后果。

12306自动查票使用到的python库主要是splinter,同时也涉及到查票的城市编码,具体的城市编码请在网络上搜索,基本格式如下:

北京北:VAP

北京东:BOP

北京: BJP

北京南:VNP

北京西:BXP

实现的功能包括:
(1)自动打开Google浏览器,进入12306登录页面
(2)命令行手动输入账号、密码、出发、目的地,时间等相关信息,登录验证图片需要手动选择。
(3)自动填充输入,完成查询和页面跳转。

后续可以优化的功能:
(1)从配置文件中读取账号、密码、出发、目的地,时间等相关信息。
(2)从配置文件中获取城市编码
(3)登录验证图片可以使用第三方识别自动选择

二、初识Splinter

1.简介

Splinter 是用 Python 开发的一个开源web自动化测试的工具集。 它可以帮你自动化浏览器的行为,比如浏览 URLs 并和页面进行交互。

Splinter是现有浏览器之上抽象层自动化工具(如 SeleniumPhantomJS 和 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()

python之12306自动查票的更多相关文章

  1. Python实现12306自动查票程序

    这是在网上扒拉过来的,原文链接: http://blog.csdn.net/An_Feng_z/article/details/78631290 目前时间2018/01/04 文中各种接口均为可用,亲 ...

  2. 利用Python实现12306爬虫--查票

    在上一篇文章(http://www.cnblogs.com/fangtaoa/p/8321449.html)中,我们实现了12306爬虫的登录功能,接下来,我们就来实现查票的功能. 其实实现查票的功能 ...

  3. Python实例--12306的抢票功能

    基础知识学习 目标: 通过python程序实现自动登录下单功能 知识点: Selenium + 云打码 + Python 学习链接: 1. Python学习--Selenium模块 2. Python ...

  4. python+selenium实现自动抢票

    使用说明 程序运行开始,需要输入出发地,目的地,出发时间,乘客信息,车次:乘客信息和车次可以输入多个 刚刚开始学习爬虫,selenium仅仅是解放了双手,运行效率不是很高: 程序运行时会打开chrom ...

  5. 基于selenium+java的12306自动抢票

    import java.util.concurrent.TimeUnit; import org.openqa.selenium.By;import org.openqa.selenium.Keys; ...

  6. vue+node+mongoDB火车票H5(七)-- nodejs 爬12306查票接口

    菜鸟一枚,业余一直想做个火车票查票的H5,前端页面什么的已经写好了,node+mongoDB 也写了一个车站的接口,但 接下来的爬12306获取车次信息数据一直卡住,网上的爬12306的大部分是pyt ...

  7. 利用Python攻破12306的最后一道防线

    各位同学大家好,我是强子,好久没跟大家带来最新的技术文章了,最近有好几个同学问我12306自动抢票能否实现,我就趁这两天有时间用Python做了个12306自动抢票的项目,在这里我来带着大家一起来看看 ...

  8. python写12306抢票

    #!/usr/bin/env python # -*- coding: utf-8 -*- ''' 利用splinter写的一个手动过验证及自动抢票的例子, 大家可以自己扩展或者弄错窗体.web端. ...

  9. 【java下午茶】12306的双人票

    明天下午就要和客户谈需求了,今天还在列车上假象着明天的情景,由于这是一个旅游的项目,所以想尽可能设计得人性化一些. 不过有件很不爽的事情就是和老公的位子是分开的,虽然我们订的是连坐号.就这个问题也是我 ...

随机推荐

  1. hadoop 测试框架

    hadoop 0.21以前的版本中(这里拿0.20为例,其他版本可能有少许不同),所有的测试相关代码都是放置在${HADOOP_HOME}/src/test下,在该目录下,是按照不同的目录来区分针对不 ...

  2. 【34】包含min函数的stack

    题目: 实现一个包含min函数的栈,min和push,pop都是o(1)时间 思路: 采用一个辅助的栈,来存储不同阶段的最小值 - 代码: push(int value){ //data是数据栈,mi ...

  3. OpenCV 1 图像分割--分水岭算法代码

    // watershed_test20140801.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" // // ch9_watershed ...

  4. DB Query Analyzer 5.05 is released, 65 articles concerned have been published

    DB Query Analyzer 5.05 is released, 65 articles concerned have been published DB Query Analyzer is p ...

  5. mybatis中#{}与${}的区别

    今天学习了下mybatis的查询,了解到了#{}与${}的区别, 配置文件如下: <?xml version="1.0" encoding="UTF-8" ...

  6. ionic1 打包过程 常用命令行

    ionic start myapp                                             myapp是项目名字 ionic start myapp --v2     ...

  7. Dubbo性能调优参数及原理

    本文是针对 Dubbo 协议调用的调优指导,详细说明常用调优参数的作用域及源码. Dubbo调用模型 常用性能调优参数 参数名 作用范围 默认值 说明 备注 threads provider 200 ...

  8. 剑指offer--矩阵中的路径

    请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子.如果一条路径经过了矩阵中的某一个格 ...

  9. iframe局部刷新的二种实现方法

    需求描述: 当页面有一部分是不变的或整个页面的图片很多时,可以考虑使用局部刷新,以提高整体的下载速度与用户体验.   1,iframe实现局部刷新的方法一 复制代码代码示例: <script t ...

  10. jjava Date格式是 May 07 17:44:06 CST 2018,怎么插入数据库中的timestamp格式中

    首先 我来记录下错误 死在时间格式转换错误手里了 大致就是时间格式转化失败 java代码中的May 07 17:44:06 CST 2018  是这个格式转换为 数据库的 yyyy-MM-dd HH: ...