Python爬虫实战之12306抢票开源

今天就和大家一起来讨论一下python实现12306余票查询(pycharm+python3.7),一起来感受一下python爬虫的简单实践

我们说先在浏览器中打开开发者工具(F12),尝试一次余票的查询,通过开发者工具查看发出请求的包

余票查询界面

可以看到红框框中的URL就是我们向12306服务器发出的请求,那么具体是什么呢?我们来看看
https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-21&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=SZQ&purpose_codes=ADULT
可以看到发出请求的几个字段:

leftTicketDTO.train_date:查询的日期
leftTicketDTO.from_station:查询的出发地
leftTicketDTO.to_station:查询的目的地
purpose_codes:不太清楚这个字段是用来做什么的,就默认吧

可以从我们递交的URL请求看出,我们输入的成都,深圳都变成了对应的编号,比如,成都(CDW)、深圳(SZQ),所以当我们程序进行输入的时候要进行一下处理,12306的一个地方存储着这些城市名与编码对应的文档:

https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971

站点编码对应

下面我们就编写一个小程序,将这些城市名与编号提取出来:

import re,requests
url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971"
response = requests.get(url,verify=False)
#将车站的名字和编码进行提取
chezhan = re.findall(r'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
chezhan_code = dict(chezhan)
#进行交换
chezhan_names = dict(zip(chezhan_code.values(),chezhan_code.keys()))
#打印出得到的车站字典
print(chezhan_names)

得到的打印结果如下(只截取部分显示):

{'VAP': '北京北', 'BOP': '北京东', 'BJP': '北京', 'VNP': '北京南', 'BXP': '北京西', 'IZQ': '广州南', 'CUW': '重庆北', 'CQW': '重庆', 'CRW': '重庆南', 'CXW': '重庆西', 'GGQ': '广州东', 'SHH': '上海', 'SNH': '上海南', 'AOH': '上海虹桥', 'SXH': '上海西', 'TBP': '天津北', 'TJP': '天津', 'TIP': '天津南', 'TXP': '天津西', 'XJA': '香港西九龙', 'CCT': '长春', 'CET': '长春南', 'CRT': '长春西', 'ICW': '成都东', 'CNW': '成都南', 'CDW': '成都', 'CSQ': '长沙', 'CWQ': '长沙南',}

接下来我们就动手开始程序的主要代码编写:

def main():
  date     = input("请输入时间(如2019-01-22):\n")
  from_station = chezhan_code[input("请输入起始站点:\n")]
  to_station  = chezhan_code[input("请输入目的站点:\n")]
  url     = "https://kyfw.12306.cn/otn/leftTicket/queryZ?"
  headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5702.400 QQBrowser/10.2.1893.400"
  }
  url=url+"leftTicketDTO.train_date="+date+"&leftTicketDTO.from_station="+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT"
  #print(url) 已经检查过生成的URL是正确的
  #request请求获取主页
  r = requests.get(url,headers=headers)
  r.raise_for_status()  #如果发送了一个错误的请求,会抛出异常
  r.encoding = r.apparent_encoding
  showTicket(r.text)

用户输入时间、起始站点、目的站点,然后通过get来请求,然后我们对返回的网页信息进行解析。我们现将上面代码的r.text进行打印,看看我们请求之后,返回了什么样的信息,然后决定我们应该如何解析

运行结果

这样看着不方便,我们粘贴到记事本中,进行详细的分析:

请求返回的结果信息

可以与12306显示的信息进行对比,K829是车次,CDW与BJQ是出发地和目的地,10:10是出发时间,06:13是到达时间,44:21是历时时间,20190123为查询的日期,剩下的就是一系列票的各种信息。

下面就是对这些返回的信息进行解析,其实这也是python爬虫的关键,就是解析!!!

我们先把信息转化为json格式,可以看到都是用“|”隔开的,那么我们就用split函数分割出来,下面是主要功能代码:

def showTicket(html):
  html = json.loads(html)
  table = PrettyTable([" 车次 ","出发车站","到达车站","出发时间","到达时间"," 历时 ","商务座"," 一等座","二等座","高级软卧","软卧","动卧","硬卧","软座","硬座","无座","其他","备注"])
  for i in html['data']['result']:
    name = [
          "station_train_code",
          "from_station_name",
          "to_station_name",
          "start_time",
          "arrive_time",
          "lishi",
          "swz_num",
          "zy_num",
          "ze_num",
          "dw_num",
          "gr_num",
          "rw_num",
          "yw_num",
          "rz_num",
          "yz_num",
          "wz_num",
          "qt_num",
          "note_num"
        ]
    data = {
          "station_train_code": '',
          "from_station_name": '',
          "to_station_name": '',
          "start_time": '',
          "arrive_time": '',
          "lishi": '',
          "swz_num": '',
          "zy_num": '',
          "ze_num": '',
          "dw_num": '',
          "gr_num": '',
          "rw_num": '',
          "yw_num": '',
          "rz_num": '',
          "yz_num": '',
          "wz_num": '',
          "qt_num": '',
          "note_num": ''
        }
    #将各项信息提取并赋值
    item = i.split('|')                 #使用“|”进行分割
    data["station_train_code"] = item[3]        #获取车次信息,在3号位置
    data["from_station_name"]  = item[6]        #始发站信息在6号位置
    data["to_station_name"]   = item[7]        #终点站信息在7号位置
    data["start_time"]     = item[8]        #出发时间在8号位置
    data["arrive_time"]     = item[9]        #抵达时间在9号位置
    data["lishi"]        = item[10]       #经历时间在10号位置
    data["swz_num"]       = item[32] or item[25] #特别注意,商务座在32或25位置
    data["zy_num"]       = item[31]       #一等座信息在31号位置
    data["ze_num"]       = item[30]       #二等座信息在30号位置
    data["gr_num"]       = item[21]       #高级软卧信息在21号位置
    data["rw_num"]       = item[23]       #软卧信息在23号位置
    data["dw_num"]       = item[27]       #动卧信息在27号位置
    data["yw_num"]       = item[28]       #硬卧信息在28号位置
    data["rz_num"]       = item[24]       #软座信息在24号位置
    data["yz_num"]       = item[29]       #硬座信息在29号位置
    data["wz_num"]       = item[26]       #无座信息在26号位置
    data["qt_num"]       = item[22]       #其他信息在22号位置
    data["note_num"]      = item[1]        #备注信息在1号位置
    color = Colored()
    data["note_num"] = color.white(item[1])
    #如果没有信息,那么就用“-”代替
    for pos in name:
      if data[pos] == "":
        data[pos] = "-"
    tickets = []
    cont = []
    cont.append(data)
    for x in cont:
      tmp = []
      for y in name:
        if y == "from_station_name":
          s = color.green(chezhan_names[data["from_station_name"]])
          tmp.append(s)
        elif y == "to_station_name":
          s = color.red(chezhan_names[data["to_station_name"]])
          tmp.append(s)
        elif y == "start_time":
          s = color.green(data["start_time"])
          tmp.append(s)
        elif y == "arrive_time":
          s = color.red(data["arrive_time"])
          tmp.append(s)
        elif y == "station_train_code":
          s = color.yellow(data["station_train_code"])
          tmp.append(s)
        else:
          tmp.append(data[y])
      tickets.append(tmp)
    for ticket in tickets:
      table.add_row(ticket)
  print(table)

那么我们程序就成功啦!!!

运行结果

但是在编译器里面Prettytable的格子没有对齐,不要担心,我们到终端运行一下脚本,就可以看到很好看的输出啦:

终端运行结果

完成!!!下面是完整代码

main.py

# -*- coding: utf-8 -*-
import re,requests,datetime,time,json
from prettytable import PrettyTable
from colorama import init,Fore
from stationinfo import chezhan_code,chezhan_names
init(autoreset=False)
class Colored(object):
  def yeah(self,s):
    return Fore.LIGHTCYAN_EX + s + Fore.RESET
  def green(self,s):
    return Fore.LIGHTGREEN_EX + s + Fore.RESET
  def yellow(self,s):
    return Fore.LIGHTYELLOW_EX + s + Fore.RESET
  def white(self,s):
    return Fore.LIGHTWHITE_EX + s + Fore.RESET
  def blue(self,s):
    return Fore.LIGHTBLUE_EX + s + Fore.RESET
def showTicket(html):
  html = json.loads(html)
  table = PrettyTable([" 车次 ","出发车站","到达车站","出发时间","到达时间"," 历时 ","商务座"," 一等座","二等座","高级软卧","软卧","动卧","硬卧","软座","硬座","无座","其他","备注"])
  for i in html['data']['result']:
    name = [
          "station_train_code",
          "from_station_name",
          "to_station_name",
          "start_time",
          "arrive_time",
          "lishi",
          "swz_num",
          "zy_num",
          "ze_num",
          "dw_num",
          "gr_num",
          "rw_num",
          "yw_num",
          "rz_num",
          "yz_num",
          "wz_num",
          "qt_num",
          "note_num"
        ]
    data = {
          "station_train_code": '',
          "from_station_name": '',
          "to_station_name": '',
          "start_time": '',
          "arrive_time": '',
          "lishi": '',
          "swz_num": '',
          "zy_num": '',
          "ze_num": '',
          "dw_num": '',
          "gr_num": '',
          "rw_num": '',
          "yw_num": '',
          "rz_num": '',
          "yz_num": '',
          "wz_num": '',
          "qt_num": '',
          "note_num": ''
        }
    #将各项信息提取并赋值
    item = i.split('|')                 #使用“|”进行分割
    data["station_train_code"] = item[3]        #获取车次信息,在3号位置
    data["from_station_name"]  = item[6]        #始发站信息在6号位置
    data["to_station_name"]   = item[7]        #终点站信息在7号位置
    data["start_time"]     = item[8]        #出发时间在8号位置
    data["arrive_time"]     = item[9]        #抵达时间在9号位置
    data["lishi"]        = item[10]       #经历时间在10号位置
    data["swz_num"]       = item[32] or item[25] #特别注意,商务座在32或25位置
    data["zy_num"]       = item[31]       #一等座信息在31号位置
    data["ze_num"]       = item[30]       #二等座信息在30号位置
    data["gr_num"]       = item[21]       #高级软卧信息在21号位置
    data["rw_num"]       = item[23]       #软卧信息在23号位置
    data["dw_num"]       = item[27]       #动卧信息在27号位置
    data["yw_num"]       = item[28]       #硬卧信息在28号位置
    data["rz_num"]       = item[24]       #软座信息在24号位置
    data["yz_num"]       = item[29]       #硬座信息在29号位置
    data["wz_num"]       = item[26]       #无座信息在26号位置
    data["qt_num"]       = item[22]       #其他信息在22号位置
    data["note_num"]      = item[1]        #备注信息在1号位置
    color = Colored()
    data["note_num"] = color.white(item[1])
    #如果没有信息,那么就用“-”代替
    for pos in name:
      if data[pos] == "":
        data[pos] = "-"
    tickets = []
    cont = []
    cont.append(data)
    for x in cont:
      tmp = []
      for y in name:
        if y == "from_station_name":
          s = color.green(chezhan_names[data["from_station_name"]])
          tmp.append(s)
        elif y == "to_station_name":
          s = color.yeah(chezhan_names[data["to_station_name"]])
          tmp.append(s)
        elif y == "start_time":
          s = color.green(data["start_time"])
          tmp.append(s)
        elif y == "arrive_time":
          s = color.yeah(data["arrive_time"])
          tmp.append(s)
        elif y == "station_train_code":
          s = color.yellow(data["station_train_code"])
          tmp.append(s)
        else:
          tmp.append(data[y])
      tickets.append(tmp)
    for ticket in tickets:
      table.add_row(ticket)
  print(table)
def main():
  date     = input("请输入时间:\n")
  from_station = chezhan_code[input("请输入起始站点:\n")]
  to_station  = chezhan_code[input("请输入目的站点:\n")]
  url     = "https://kyfw.12306.cn/otn/leftTicket/queryZ?"
  headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5702.400 QQBrowser/10.2.1893.400"
  }
url=url+"leftTicketDTO.train_date="+date+"&leftTicketDTO.from_station="+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT"
  #print(url) 已经检查过生成的URL是正确的
  #request请求获取主页
  r = requests.get(url,headers=headers)
  r.raise_for_status()  #如果发送了一个错误的请求,会抛出异常
  r.encoding = r.apparent_encoding
  showTicket(r.text)
  #print(r.text)
main()

stationinfo.py

import re,requests
url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971"
response = requests.get(url,verify=False)
#将车站的名字和编码进行提取
chezhan = re.findall(r'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
chezhan_code = dict(chezhan)
chezhan_names = dict(zip(chezhan_code.values(),chezhan_code.keys()))
#print(chezhan_names)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Python3网络爬虫中的requests高级用法详解

    本节我们再来了解下 Requests 的一些高级用法,如文件上传,代理设置,Cookies 设置等等. 1. 文件上传 我们知道 Reqeuests 可以模拟提交一些数据,假如有的网站需要我们上传文件,我们同样可以利用它来上传,实现非常简单,实例如下: import requests files = {'file': open('favicon.ico', 'rb')} r = requests.post('http://httpbin.org/post', files=files) print

  • python3.7简单的爬虫实例详解

    python3.7简单的爬虫,具体代码如下所示: #https://www.runoob.com/w3cnote/python-spider-intro.html #Python 爬虫介绍 import urllib.parse import urllib.request from http import cookiejar url = "http://www.baidu.com" response1 = urllib.request.urlopen(url) print("

  • python爬虫之验证码篇3-滑动验证码识别技术

    滑动验证码介绍 本篇涉及到的验证码为滑动验证码,不同于极验证,本验证码难度略低,需要的将滑块拖动到矩形区域右侧即可完成. 这类验证码不常见了,官方介绍地址为:https://promotion.aliyun.com/ntms/act/captchaIntroAndDemo.html 使用起来肯定是非常安全的了,不是很好通过机器检测 如何判断验证码类型 这个验证码的标识一般比较明显,在页面源码中一般存在一个 nc.js 基本可以判定是阿里云的验证码了 <script type="text/j

  • Python 3实战爬虫之爬取京东图书的图片详解

    前言 最近工作中遇到一个需求,需要将京东上图书的图片下载下来,假如我们想把京东商城图书类的图片类商品图片全部下载到本地,通过手工复制粘贴将是一项非常庞大的工程,此时,可以用Python网络爬虫实现,这类爬虫称为图片爬虫,接下来,我们将实现该爬虫. 实现分析 首先,打开要爬取的第一个网页,这个网页将作为要爬取的起始页面.我们打开京东,选择图书分类,由于图书所有种类的图书有很多,我们选择爬取所有编程语言的图书图片吧,网址为:https://list.jd.com/list.html?cat=1713

  • 33个Python爬虫项目实战(推荐)

    今天为大家整理了32个Python爬虫项目. 整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快~O(∩_∩)O WechatSogou [1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典. DouBanSpider [2]- 豆瓣读书爬虫.可以爬下豆瓣读书标签下的所有图书,按评分排名依次存储,存储到Excel中,可方便大家筛选搜罗,比如筛选评价人数>1

  • Python3简单爬虫抓取网页图片代码实例

    现在网上有很多python2写的爬虫抓取网页图片的实例,但不适用新手(新手都使用python3环境,不兼容python2), 所以我用Python3的语法写了一个简单抓取网页图片的实例,希望能够帮助到大家,并希望大家批评指正. import urllib.request import re import os import urllib #根据给定的网址来获取网页详细信息,得到的html就是网页的源代码 def getHtml(url): page = urllib.request.urlope

  • Python3.x爬虫下载网页图片的实例讲解

    一.选取网址进行爬虫 本次我们选取pixabay图片网站 url=https://pixabay.com/ 二.选择图片右键选择查看元素来寻找图片链接的规则 通过查看多个图片路径我们发现取src路径都含有 https://cdn.pixabay.com/photo/ 公共部分且图片格式都为.jpg 因此正则表达式为 re.compile(r'^https://cdn.pixabay.com/photo/.*?jpg$') 通过以上的分析我们可以开始写程序了 #-*- coding:utf-8 -

  • Python爬虫实战之12306抢票开源

    今天就和大家一起来讨论一下python实现12306余票查询(pycharm+python3.7),一起来感受一下python爬虫的简单实践 我们说先在浏览器中打开开发者工具(F12),尝试一次余票的查询,通过开发者工具查看发出请求的包 余票查询界面 可以看到红框框中的URL就是我们向12306服务器发出的请求,那么具体是什么呢?我们来看看 https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-2

  • python爬虫实现最新12306抢票

    1.环境 python 3.7谷歌浏览器chromedriver.exe(浏览器驱动程序,要与浏览器版本对应,并将其添加到环境变量或放到当前py文件所在目录下) 2.相关模块 time (用于某些地方对程序的强制等待)datatime (用于获取当前时间)selenium 3.1 自动化测试模块,这里用于操作浏览器) 3.思路 首先进行登录(支持手机扫码),登录完成进入页面之后,我们会看到有“温馨提示”的弹窗,即当前界面,我们需要处理第一次弹窗, 然后进入到菜单栏车票下的单程中(鼠标移动触发事件

  • Python爬虫 12306抢票开源代码过程详解

    今天就和大家一起来讨论一下python实现12306余票查询(pycharm+python3.7),一起来感受一下python爬虫的简单实践 我们说先在浏览器中打开开发者工具(F12),尝试一次余票的查询,通过开发者工具查看发出请求的包 可以看到红框框中的URL就是我们向12306服务器发出的请求,那么具体是什么呢?我们来看看 https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-21&leftT

  • python自动12306抢票软件实现代码

    昨天我发的是抓取的12306数据包,然后分析了一下,今天按照昨天的分析 用代码实现了,如果有需要的同学们可以看一下,实现的功能有,登录,验证码识别,自动查票,有余票点击预定, 差了最后一步提交订单.同学们可以自己研究一下. import requests import time import dmpt import re import random from copyheaders import headers_raw_to_dict DEFAULT_HEADERS={ 'Host':'kyfw

  • python实现12306抢票及自动邮件发送提醒付款功能

    #写在前面,这个程序我已经弄出来了,但是因为黄牛泛滥以及懒人太多,整个程序的代码就不贴出来了,这里纯粹就是技术交流. 只做技术交流..... 嗯,程序结束后,自己还是得手动付款. 废话不多说,下面就直接开始技术主要部分阐述. 先讲理论部分:首先我们需要代码实现一个浏览器功能,那么模块基本上可以确定urllib.parse.urllib.request,这两个包都是和网址有关的模块,那么咱们去登录一个网址,特别是有验证码这些的网址,我们登录进去是不是就行了?答案是对的,但是我们用代码实现的话,这个

  • python+Splinter实现12306抢票功能

    本文实例为大家分享了python实现12306抢票功能的具体代码,供大家参考,具体内容如下 源码记录如下: #!/usr/bin/env python # _*_ coding:utf-8 _*_ #!/usr/bin/env python # _*_ coding:utf-8 _*_ from splinter.browser import Browser from time import sleep import os # from selenium.webdriver.chrome.opt

  • 利用python代码写的12306订票代码

    本文实例讲述了python代码写的12306订票代码,分享给大家供大家参考. 具体实现方法如下: import datetime import json import re import sys import time import Image import PyV8 import requests import tools.email_helper as emailHelper reload(sys) sys.setdefaultencoding('utf-8') # @UndefinedVa

  • Python爬虫实战之爬取京东商品数据并实实现数据可视化

    一.开发工具 Python版本:3.6.4 相关模块: DecryptLogin模块: argparse模块: 以及一些python自带的模块. 二.环境搭建 安装Python并添加到环境变量,pip安装需要的相关模块即可. 三.原理简介 原理其实挺简单的,首先,我们利用之前开源的DecryptLogin库来实现一下微博的模拟登录操作: '''模拟登录京东''' @staticmethod def login(): lg = login.Login() infos_return, session

  • Python爬虫实战:分析《战狼2》豆瓣影评

    刚接触python不久,做一个小项目来练练手.前几天看了<战狼2>,发现它在最新上映的电影里面是排行第一的,如下图所示.准备把豆瓣上对它的影评做一个分析. 目标总览 主要做了三件事: 抓取网页数据 清理数据 用词云进行展示 使用的python版本是3.5. 一.抓取网页数据 第一步要对网页进行访问,python中使用的是urllib库.代码如下: from urllib import request resp = request.urlopen('https://movie.douban.co

  • Python爬虫实战案例之爬取喜马拉雅音频数据详解

    前言 喜马拉雅是专业的音频分享平台,汇集了有声小说,有声读物,有声书,FM电台,儿童睡前故事,相声小品,鬼故事等数亿条音频,我最喜欢听民间故事和德云社相声集,你呢? 今天带大家爬取喜马拉雅音频数据,一起期待吧!! 这个案例的视频地址在这里 https://v.douyu.com/show/a2JEMJj3e3mMNxml 项目目标 爬取喜马拉雅音频数据 受害者地址 https://www.ximalaya.com/ 本文知识点: 1.系统分析网页性质 2.多层数据解析 3.海量音频数据保存 环境

随机推荐