脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python爬虫实战之12306抢票开源

Python爬虫实战之12306抢票开源

2021-05-22 00:15Python新世界 Python

今天小编就为大家分享一篇关于Python爬虫实战之12306抢票开源,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

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

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

Python爬虫实战之12306抢票开源

余票查询界面

可以看到红框框中的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

Python爬虫实战之12306抢票开源

站点编码对应

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

?
1
2
3
4
5
6
7
8
9
10
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': '长沙南',}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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进行打印,看看我们请求之后,返回了什么样的信息,然后决定我们应该如何解析

Python爬虫实战之12306抢票开源

运行结果

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

Python爬虫实战之12306抢票开源

请求返回的结果信息

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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)

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

Python爬虫实战之12306抢票开源

运行结果

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

Python爬虫实战之12306抢票开源

终端运行结果

Python爬虫实战之12306抢票开源

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

main.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# -*- 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

?
1
2
3
4
5
6
7
8
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)

总结

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

原文链接:https://blog.csdn.net/qq_41841569/article/details/86570150

延伸 · 阅读

精彩推荐