12306刷票工具

项目地址: https://github.com/vicalloy/12306-ticket-checker

只是在刷出票后发送提醒消息,并不能自动购票。在收到消息后还是得拼手速。 脚本用 Python3 实现,可挂到服务器上 24 小时刷。

前言

总体来说火车票应当是越来越好买,因此一直没怎么太操心。哪知道今年票似乎没有很好买,最近在 12306 刷了几天一张票都没看到。广大抢票软件又都只支持 Windows 系统,作为 Mac 用起来不是太方便。
弄了一个小脚本挂到服务器上,在查询到有符合条件的车票后将通过Slack将消息推送给我。

注意事项

  • 脚本采用python3开发,请使用python3运行该脚本。
  • 在刷到票后,采用 Slack 发送通知消息,因此请先创建Slack的Team。在创建好Team后,创建一个名叫ticket的channel,并申请一个Bot用于发消息。如希望采用其他的通知途径,请自行修改12306.py中的send_message实现。

后记

一大早就刷出了一大波票,不过等我兴冲冲的打开手机客户端一查,连个票的影子都没看到。可能是经过几年的发展抢票市场也日渐成熟,所有的票都在第一时间给抢票软件给刷走了。

TODO

目前这个脚本只能实现余票的提醒功能,但理论上要实现自动购票的功能并会太难。buy.py中给出了登陆的基础实现,不过考虑到实现所有功能所要付出的时间成本因此不打算继续了。
注:也是因为票被秒光的速度太快,估计折腾完也用处不大。

自动购票最大的障碍还是来自于12306的验证码。

验证码的处理思路

手动处理验证码

手动处理验证码应当是最简单有效的处理方式,当前缺点也很明显,无法做到全自动。Slack的API非常强大且易用,通过Slack的”Real Time Messaging API”,我们可以利用Slack实现交互。在需要输入验证码的时候,通过Slack将验证码推送到用户,用户在完成验证码输入后,系统自动处理之后的业务逻辑。

自动识别

要做好验证码的自动识别时间就比手动处理要麻烦多了。如果不是想卖给黄牛我个人是觉得没必要打自动识别的主意了。

12306的验证码可以分为2部分,最顶部的文字以及下方的8张图片。

文字的变形其实并不算太大,相信以现在OCR的水平识别率还是挺高的,重点是下发的8张图片。12306的验证码图小分辨率低,不说机器,要人来识别都不容易。如果纯粹根据机器学习来做图片识别,即使学习库再大效果也不会好到哪去。

最有效的还是”笨方法”,让系统频繁的去请求12306的验证码,然后手工将所有图片打上Tag。考虑到12306的图库不会太小,给图片打Tag必然会有很大的工作量,如果没有利益驱使是百分百做不来的。
另一方面,即使前期做了非常多的准备工作也很难保证12306不会添加新的图片。在遇到不认识图片的时候最简单的方法自然是先将图片记录下来等待手工加Tag,另一方面重新刷新验证换个自己认识的。
Google有提供上传图片进行搜索的功能,可以把图片上传到Google然后得到图片的关键字(当然精确度不会太高)。在图片资料库不够完整的时候也可以利用Google来猜些图。

Django 2.0放弃Python 2的支持了

Django的master分支已经正式切换到Django 2.0了,其中的一个commit就是去掉Python 2支持的相关代码。这意味着从Django 2.0开始,Django将要放弃Python 2.x的支持。
对于这个消息,Reddit上一片喜大普奔。对我而言这绝对是一个好消息,毕竟我还是非常喜欢Python 3的type hints。如果放弃Python 2的支持,他们还是很有希望会加入type hints的支持。
从去年开始,不少最新的Python库只支持Python 3。另外type hints加入让甚至可以说让Python更像一个新的语言。或许Python 2终于要开始淘汰出局了。对我而言,除了老项目的维护外,新项目似乎没有什么理由再支持Python 2。

注:根据Reddit上的回复,由于model里用了太多的magic,model这部分要加入type hints还有很多问题要解决。不过可以肯定的是type hints绝对会是今后Python库的大方向,Django也是会支持的。

Python 3的type hints

近年来新出的语言Go、Rust、Swift都无疑例外的是静态类型。随着软件的越来越复杂,动态语言“太过随意”的缺点也越来越明显。此外随着IDE的发展,静态类型语言“繁琐”的缺点也得到了很好的规避。
在学习Swift的时候,Swift的类型推导给了留下了很深的印象。类型推导或许是现阶段兼顾类型检查以及动态语言简洁的最佳解决方案。
Python从3.5开始加入了type hints(类型注释)。

def greeting(name: str) -> str:
    return 'Hello ' + name

从名字“type hints”就可以看出,只是类型注释并不是强制要求。由于只是“注释”,“type hints”需要第三方工具的配合。你需要使用Mypy来对代码进行语法检查。另外PyCharm在新版本中也加入了对“type hints”的支持。

对我而言“type hints”无疑是一个非常棒的特性,让Python也具备了类似Swift的类型推导功能。希望日后的各类Python都能加入type hints的支持。另外就希望各类开发工具可以充分的利用type hints特性。

注:
Swift中使用“?”表示option,Python里则需要写成Optional[str]相比之下有些太过繁琐。

亚庇

第一次是同老婆一起,这次多了一个宝宝。之前一直想去长滩岛,考虑到带着父母和宝宝,长滩岛还得车船联运有些麻烦,最终还是选择了亚庇。

水上清真寺。只在外面拍了个照,并没有进去。

沙巴大学里的码头。

由于宝宝要睡觉,很晚才上岛,几乎没怎么玩就回来了。

传说中的最美落日。不过在我看来海上落日似乎都差不多,并未感觉有什么特别的。

Docker

很早之前就听过Docker,当时感觉对个人使用而言Docker似乎派不是太大的用场。

  • Docker非常类似虚拟机。如果单纯出于统一开发环境的考虑,直接用虚拟机似乎还更直接一些。
  • 虚拟机+ Vagrant也可以方便的对虚拟环境进行管理,Docker在这方面似乎也木太占优势。
  • Docker通过仓库分发Images,似乎同直接复制虚拟机的镜像效果也差不了太多。
  • 由于并不需要管理大量的服务器,直接手动部署或用部署工具操作也不会太过复杂。用Docker还得学习Docker的使用,似乎也不太值得。

近期由于Discourse的缘故,实际用了一下Docker。感觉Docker确实是个不错的东西,不论是开发还是运维Docker都是值得使用的。

Docker有啥好处

  • Puppet, Chef等传统的运维工具可以实现应用的批量以及自动化的部署。但实际工作中,用户的系统千差万别,可能换个系统环境你的脚本就挂了。
  • 对开发人员,可以使用统一的虚拟机作为开发环境。但虚拟机无法直接部署到生产环境。生产环境、测试环境、生产环境无法做到统一。很可能开发环境跑的好好的,一到生产环境就出各类莫名其妙的问题。
  • Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
  • 使用Docker可做到“各类环境”的完全统一。不论用户原始的环境是什么,真正跑应用的环境都是一样的。由于在开发阶段就已经把环境完全整好了,只需要简单的几个命令即可完成部署,Docker的部署异常简单。由于不用考虑系统的差异,Dockerfile写起来相对来是比较简单的。

相关资源

黄山

第一次自驾出行,第一次带着爸妈,拉着宝宝一同出行,也是第一次重装露营。

呈坎

徽派村落的代表无疑是宏村。不过不管是宏村还是呈坎现在去的都不是季节。之所以去呈坎完全是因为顺路,看地图呈坎就在去黄山的路上,而且在高速边上。

人文的景点更多看的是文化及历史,就如我当初看《人间词话》时也曾对文中的白石很感兴趣,甚至想去探访白石在杭州所留下的痕迹。我终归不是一个文化人,少了对文化及历史的好奇后呈坎只是一个普通的小村落。

论名气,呈坎完全无法同宏村西递相媲美,因此商业化程度也好低很多。里面的村民对游客都有些过于热情,这个热情多半来源于经济目的,他们的讲解收费是10¥。作为非文化人,对村子背后的故事并无多少兴趣,反倒觉得有些打扰自己游玩的兴致。

呈坎

汤口

黄山脚下的小镇。
想09年第一次来黄山的时候,大巴把我放到一个鸟不拉屎的地方,旁边只有一个不起眼的小店。当时我都怀疑是否是司机把我放错了地方。短短的几年,汤口已经变得有些过于繁华了,这次都开始堵车了。
黄山作为一个固定的景点,接待能力终归有限,能拓展的周边也极为有限。简单的说整个旅游市场的规模也只能这么大,能开发的潜力极为有限。汤口依托黄山发展起来,不知能走多远。

DSC06641

黄山

黄山本身并无太多变化,和第一次见时一样美,但人多。这次的时间并不是周末,虽受免票的影响人会多些,但有些太多。到处都是排队,连天都峰都排队。
至少近期几年是不会再去黄山了,黄山虽美,但人多到有些影响体验了。

DSC06694

露营

帐篷、睡袋、背包都已经买了很久了,一直几乎着要去露营却一直没机会。这次也算是作死,带着一大家子,抱个宝宝,背个大包去黄山露营。本还想继续做死背包徒步上山,老婆不同意才改为索道。没有爬山,外加一路排队,虽是重装但并未感觉太累。

DSC06707

OA平台技术分享

为公司其他部门做的技术分享,在一定程度上也算是在公司内部推广Python。不过很不幸的是由于某些原因,该分享不幸夭折。

PPT在这里:http://vik.haoluobo.com/static/slide/oa/

下面是更为详细的文案。

OA平台概况

  • Nginx
    • 使用Nginx作为前端服务器,负责静态资源处理及HTTP请求分发
    • 在需要扩展到多服务器时,Nginx可以用做负载均衡服务器
  • UCenter(统一认证中心)
    • 统一的用户登陆管理
    • 用户信息存储在公司的AD域中
  • OA
    • 业务平台,公司的行政、人力等各项OA业务都在该平台搭建
    • 同携程、inTrack平台对接实现相关业务
    • 数据的汇总及分析

OA构架

  • 基于Django搭建的可插拔APP平台
    • 核心APP(基础APP)
      • 核心APP包括:UI框架、权限认证、流程引擎、用户、员工、部门管理等
      • 作为系统的核心模块,需要被其他各个业务模块所用到。
      • 为具体业务做支撑,大多不同具体业务相关
      • 核心模块在系统上线后将不太做改动,只需要少量的核心开发人员维护即可
      • 核心模块也是可复用的
        • UCenter同OA就是公用的相同的UI框架
    • 可插拔APP(业务APP)
      • 可插拔APP包括:人力模,请假出差、财务模块,报销、预算、行政、固定资产管理…
      • 同具体业务相关,依赖核心模块。
      • 业务需求多,且易变,在平台建设初期难以做周全的计划。
      • 各个业务模块相对独立,各业务模块可独立开发。
      • 多个业务模块可由多人并行开发。

Django

  • The web framework for perfectionists with deadlines.
  • 全功能的Web开发框架,依托Python提供快速开发的支持
    – 提供模板、控制器、URL路由、表单、验证、ORM等各项Web开发需要的基础功能
    – ORM及其强大,即使不懂SQL也可使用。
    – 支持数据库的版本管理,并可自动更新线上数据库结构
    – 模板支持继承清晰易用,对前后端分离提供很好的支持。

    • 成熟的社区环境,大量现成的APP可用
    • 被广泛应用,有成功易用范例:Instagram、OpenStack

流程引擎

  • 采用Python自主开发
  • 编码同配置结合在确保使用便携性的同时确保的功能的强大
    • 表单、业务处理逻辑编码实现
      • 数据模型通常变动不大,采用配置方式实现不但实现复杂,也不会能为开发维护带来多少便利
      • 流程常用的,同意、驳回、打回、撤销等基础操作流程引擎已自动实现,不需要额外开发。
      • 如在流程流转需要进行特殊操作,需用代码给出对应的实现。
        • 比如新员工入职流程结束后需要自动在系统中创建员工账号等
      • 配合代码生成器的使用,对于标准流程编码工作流程只需要完成数据模型的设计即可。
    • 流程流转用配置实现
      • 流程的审批节点,审批人变动概率较大,采用编码方式实现既不方便又不灵活
      • 流程流转的功能需要比较清晰,使用配置方式即可比较好的满足需求
        • 流转方式:抢先,会签
        • 流程节点的审批人、周知人、权限分享。
        • 流程分支支持
    • OA上所有流程都基于流程引擎开发
  • 提供代码生成工具生成流程框架
    • 对于简单的流程,只需要实现数据模型即可生成完整的业务代码

Why

  • Why

    • Python

      • Python is powerful… and fast;
        • 这里的快更多的是开发速度快。语法丰富,简洁
        • 开发效率高是我们选择Python的一个重要原因。
          • 信息部就2人,需要负责需求整理、设计、开发、测试所有工作,对开发效率要求非常高。
        • 不需要编译,启动时间快节约开发时间
          • 一个大Java项目编译要超过一分钟,Web服务器启动又会超过一分钟
          • OA对比原有的KM。KM启动时间超过1分钟,OA可在5秒内完成重启。
        • Python本身并不慢,
        • 真正影响性能的代码所占总代码的比重很少。
          • Python可方便的同C集成,用C扩展性能
          • 注:使用Cython可直接在Python里写C代码以提高性能
          • 目前不少性能敏感的库都采用C扩展的方式进行加速,方案成熟
      • plays well with others;
        • 对C友好,使用ctypes可直接使用C接口的动态库
        • 很多软件都有提供Python接口。如:OpenCV、MATLAB
      • runs everywhere;
        • 支持几乎所有的操作系统(包括各类嵌入式系统)
      • is friendly & easy to learn;
        • 非常容易入门。对有经验的开发者,花一天时间熟悉语法就可直接使用
      • is Open.
      • Python的第三方资源足够丰富,应用也足够广泛
        • 有很多采用Python的成功应用
          • OpenStack、Dropbox、Youtube、Mercurial
        • 虽然比不上Java,但Python的资源也非常丰富。
          • Django(Web)、Cython(在Python中直接写C)、NumPy(可选计算)、PyQT(UI)、QPython(Python on Android)
      • Python无所不能,但并不适合做所有事情。比如Android移动端的开发还是用Java更合适

      • 开发效率高

        • 信息部人少,需要快速实现需求
        • Java严谨、Java有接口等概念,在大项目协作时更容易。但由此带来的开销是在小团队情况下开发效率更低。
    • Django
  • Why Not
    • Java
      • Java严谨、Java有接口等概念,在大项目协作时更容易。但由此带来的开销是在小团队情况下开发效率更低。
      • 信息部是个小团,Java带来的好处不如优点大。
      • 即使是一个大团队,也可通过模块化的方式来减少规模化带来的沟通开销。除阿里这样的超大公司外,很多时候Java都不是一个很好的选择。
      • Java在Web开发方面一直是由多个开源项目所推动,本身就缺乏一个很好的体系。
        • Java的各个开源项目独立发展,在开发初期并未仔细考虑过如何同其他项目协作。
        • Java主流实现都是围绕如何实现一个超大规模项目来设计,对小项目来说负担太重。
        • 使用Java实现一个非常小的功能也需要写大量的代码及超多的XML配置。现阶段Java开发已经简化很多,但相比Python依旧太过繁琐。
    • Node.js
      • 近年来前端技术发展非常迅速。
      • 前端开发只能用JS,因此会JS的群体非常广泛。
      • Chrome V8,Node.js将JS引入服务端,收到广大前端爱好者的支持,迅速发展。
      • Node.js天生异步,有着不错的性能。
      • 使用callback实现异步,大量的callback导致代码不容易理解。
    • redis(Cache)
      • 开发应当优先考虑功能的稳定性,然后才是性能问题。
      • 性能问题更多的是构架问题,应当优先优化构架。
      • 以我们公司的规模还远没到需要增加缓存的情况。
      • 缓存会增加系统复杂度,也可能带来一定的潜在风险。

前端技术构架

  • UI
    • AdminLTE(Bootstrap)
      • 信息部人少,缺少专业的UI及前端人员,尽可能的利用现有可用的资源。
      • AdminLTE是一套基础Bootstrap的界面框架,提供了大量基础的界面功能。
      • Bootstrap是当前非常流行的前端框架,有着丰富的资源。
  • JS
    • 使用Bower管理静态资源。
      • 静态资源的包管理工具
      • 方便静态资源的升级管理
      • 避免将静态资源直接复制到代码库,为代码库增加存储以及响应压力
    • JQuery
      • JS事实上的标准库,可极大的加速JS开发。
    • formset.js、datepicker等
      • 实现formset,日期选择等节目效果。
    • 使用Django-Compressor进行静态资源的压缩优化。
  • Why Not
    • Webpack
      • 近几年前端发展速度非常快,前端开始变的复杂。JS不仅仅是为Web页面锦上添花。为配合使用JS进行大规模项目的开发,需要相关工具进行配合。
      • 前端打包工具,可对JS库进行依赖管理,控制JS包的按需加载。可对JS/CSS编译(ES6/TypeScript/SCSS/LESS),压缩,图片优化等
      • OA前端应用相对比较简单,Django-Compressor可以满足要求现阶段需求。相比Webpack能带来的好处,没必要为项目增加不必要的复杂度。
    • React
      • 用来构建用户界面的 JavaScript 库
      • 更适合单页面的应用,如为手机提供类似APP的体验。
      • 不采用原因同Webpack一样。

LBForum后续计划

开源应当是一件很认真的事。

  • 保证持续的维护与更新,保证该项目的活力。
  • 有完善的测试用例,方便在添加功能以及merge其他人的改动后进行功能测试。保证软件的质量。
  • 完善的文档,让初次接触该项目的人可以快速的知道如何使用。

我写的一些东西基本上都是出于个人兴趣,因此有些随性,兴趣来了就写一写,兴趣过了这个项目就荒废了。
LBForum曾一度荒废,近期由于集成到公司系统,顺道做了一些更新。接下来可能还会陆陆续续做些更新。

  • 增加Python3的支持
    • 单纯的增加Python3的支持并不难。由于我的测试用例并不完善,增加Python3后测试的工作量会增加,因此一直没有做。
    • 注:现在以及可以支持Python3了。比预计的要顺利不少,只做了很少的改动就完成了Python3的支持。
  • 增加Rest接口
    • 之前的Rest接口一直都是手动实现而且也还挺方便,想试试Django REST Framework看能减少多少工作量。
  • iOS的论坛APP
    • 一直想做个移动APP,刚好用论坛来尝试一下。
    • 第一个版本应当只有浏览功能,登陆、回帖、发帖等功能将在日后逐步添加。

React

之前简单的对比过React和Vue.js。React组件化程度很高,粒度很细,“模板”分散在整个JS文件中。Vue.js模板和JS文件分离,看上去要清晰不少。当时比较倾向于Vue.js。
近期又去了解了一下两个框架。Vue.js居然也计划要支持JSX了,模板和JS分离这本是我偏好Vue.js的一个重要原因。此外就网上的评价来看Vue.js的坑也并不比React少。考虑到React的背景,以及周边成熟的生态环境,决定再给React一个机会。
把React的《QUICK START》完整的看了一遍。React的入门并不难。如果不想将系统改造成“单页面应用”,只将页面上部分功能组件化也不存在困难。React的粒度很细,但拆分完后各部分会比较简单。
按照React的说法,React会颠覆大家对传统Web开发的认知,但一旦熟悉就会发现这很棒。
React是否真的很棒?因为没真正用过,还不敢断言。但React的组件化思想还是有些意思,本身的概念也比较清晰,加上并不复杂,或许值得一试。

LBForum更新Django1.10支持

前一段时间公司需要上线一个论坛系统。公司系统采用Django开发,因此考虑集成一个论坛的App,另外出于一部分私心,最终采用了LBForum
之前LBForum很久没有维护,很多依赖包的版本已经不对,导致已无法正常运行。这次更新修正了之前的一些bug,另外对依赖进行更新。现有的依赖包都明确指定版本,避免因依赖包更新导致无法运行。

这次升级后对演示站点同步进行了更新,演示站点地址: http://lbf.haoluobo.com/

LBForum的主要更新

  • Django更新到1.10
    • 目前只测试了1.10,不确定在其他版本下是否可以正常运行
  • 出于工作量的考虑,只保留v2ex主题,不再提供FluxBB主题的支持
    • 如果你想使用FluxBB主题,可切换到v1.0分支,里面有老代码
  • 去掉django-simple-avatar,使用easy_thumbnails提供用户头像支持
  • django-helper、django-lb-attachments使用django-lbattachmentdjango-lbutils进行替代
    • 前面的两个包是我很早之前维护的工具组件,现在已不再维护。后面的是现在新维护的工具组件
  • 去掉django-onlineuser
    • 这个用户在线模块一直有些问题,在想好怎么优化前暂不增加在线用户统计功能
  • 使用django-el-pagination替代django-pagination
    • django-pagination已经近乎不维护的状态,django-el-pagination在功能以及活跃度方面都要更好一些
  • 去掉South
    • Django自带的数据库结构维护已经很成熟了
  • 使用bower管理第三方JS库
    • 使用bower,避免将大量的第三方库直接塞到代码库中。
  • 上传组件替换为jQuery-File-Upload
    • 之前的上传组件依赖Flash。在Flash越来越不流行的今天,依赖Flash不再是一个好选择。
  • 使用MediaElement增加视频支持
  • 使用Pygments提供语法高亮支持
    • 在安装Pygments后,可对代码进行语法高亮

lbforum-site的主要更新

对应的演示站点也做了相应的更新。

  • LBForumdjango-lbattachmentdjango-lbutils使用Submodule的方式导入
    • 相比采用pip方式安装,使用Submodule的方式对子模块的更新和修改起来要方便的多。
  • 使用django-allauth替代django-registration
    • django-registration老早就不再维护了。django-allauth在功能以及活跃度上都还不错。
  • 针对注册,加了一个简单的校验
    • 网络上的垃圾爬虫无处不在,之前的演示站点已成了垃圾广告的集散地。这次在注册的时候加了一个简单的校验,必须在captcha内填写captcha才可正常注册。因为刚更新,还不知道效果如何。注:现在的爬虫似乎很智能了,这个功能似乎并不太有效,还是不定期会有爬虫上去发帖。

其他一些问题

  • 一直想把文档给整“好看”一些。不过写文档并不是一件轻松的事情,面对懒癌文档的事情只能继续挂起。
  • 目前主流的Python库已经都支持Python3了,增加Python3算是挺有必要的一个工作。根据之前Python3支持的经验,要同时支持Python2和Python3还是得花费一些时间。由于我主要还是用Python2,因此也先挂起了。