这里还是基于之前针对于12306网站的车票余票信息进行爬取。经过之前对12306验证码及整个网站结构数据的分析。

可以分析出网站他其实也是有自己的车票信息的接口,只不过抓取数据的时候比较复杂一点。通过开发者工具分析其页面资源可以发现主要有两个资源接口可以供我们调用。

第一个接口:https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9110

全国所有地区的车站及相应的车站代码接口(我们平时查询车票的时候,输入的是城市汉字,其实后台会将其转化为该城市下所有车站的代码简称,并一一查询)

具体返回的内容:

可以看到页面结构非常的混乱,那么我们需要怎么取到对应车站的对应的车站代码简称。可以发现页面中所有的汉字都是车站名,这个可以通过中文匹配Unicode编码匹配得到,而车站代码简称是跟着车站汉字后面的,所有这里通过正则匹配获取。

正则获取下来为一个个元组,将其强转为字典

# 获取车站名称及对应代码
def get_station_code():url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9110'response = sess.get(url,headers=headers).textresult = re.findall(r'([\u4e00-\u9fff]+)\|([A-Z]+)',response)# 将车站与车站代码转为字典类型station = dict(result)# 将车站和车站代码位置调换,用于后面的转化 BJP:北京station_names = dict(zip(station.values(), station.keys()))# print(station)return station,station_names

第二个接口:

这个接口就是详细的车票及余票的详细信息


它传递传递4个参数:时间,出发站,目的站,还有一个固定参数;我们只需要传递不同的时间,出发站和目的站,就可以查询到具体的信息


当然如果直接请求这个接口,结果可想而知。不可能获取到数据。这里我先用postman工具请求验证一下:
会返回一下一个页面,并没有任何有用的数据。所以必须携带指定的cookie它才认为你是合法的请求。

'RAIL_EXPIRATION': '1569132689668',
'RAIL_DEVICEID': 'Ry6Q7Tkau6lvtQFj-1-qD3Mrde9MOKac4kGC5MCLRvgQ5ADb2vySV_SptrTnvjckvQxVWcocw7621ci-T2TmMlg4pChroHuQoXvciR1XyZ52i4ZSiS_dClAx8x_Ck3tg_4or7LxX15-nWH7ilOFn53WcrBup-bN8',
'route': 'c5c62a339e7744272a54643b3be5bf64'

加上上述的cookie值,请求该接口就可以获取到详细的车票信息,然后我们就需要去获取指定的数据了,抓取以下所有字段信息(17个字段)

最后我们分析返回的数据,可以看出该数据类似于json数据的,属于双层嵌套。我们需要拿到result键值数据,是一个列表,这里注意result不是在大字典中,而是在data键值下
,然后针对列表中每一条数据以‘|’拆分,最后用索引去取到具体的余票信息。
到此为止,所有数据网页分析其实已经结束了,现在就是代码实现以及数据展示的效果了。

这里需要用到两个模块,用于结构化展示数据

prettytable 模块

PrettyTable 是python中的一个第三方库,可用来生成美观的ASCII格式的表格:

使用方法:

colorama模块

colorama是一个python专门用来在控制台、命令行输出彩色文字的模块,可以跨平台使用

可用格式常数:
Fore是针对字体颜色,Back是针对字体背景颜色,Style是针对字体格式Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.
Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.
Style: DIM, NORMAL, BRIGHT, RESET_ALL
from colorama import init,Fore,Back,Style
init(autoreset=False)#autoreset是自动恢复到默认颜色,这里不使用自动恢复
class Colored(object):#  前景色:红色  背景色:默认def red(self, s):return Fore.LIGHTRED_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

完整代码实现:

import re
import json
import datetime
import requests
from prettytable import PrettyTable  # dos窗口输出美观化,pycharm没作用
from colorama import init,Fore,Back,Stylesess = requests.session()# headers = {#         'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'
# }init(autoreset=False)
class Colored():"""后面加RESET避免后面的字符串受到前面颜色渲染的影响,置为默认"""#  字体:淡红色def red(self, c):return Fore.LIGHTRED_EX + c + Fore.RESET#  字体:淡绿色def green(self, c):return Fore.LIGHTGREEN_EX + c + Fore.RESET#  字体:淡黄色def yellow(self, c):return Fore.LIGHTYELLOW_EX + c + Fore.RESET#  字体:淡白色def white(self,c):return Fore.LIGHTWHITE_EX + c + Fore.RESET#  字体:淡蓝色def blue(self,c):return Fore.LIGHTBLUE_EX + c + Fore.RESET#  字体:品红def magenta(self,c):return Fore.MAGENTA + c + Fore.RESET#  字体:绿色def green1(self,c):return Fore.GREEN + c + Fore.RESET#  字体:淡青色def cyan(self,c):return Fore.LIGHTCYAN_EX + c + Fore.RESETclass TicketCrawl():def __init__(self):# 请求头self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'}# 车站:车站代码self.station = None# 车站代码:车站self.station_names = None# 获取车站名称及对应代码def get_station_code(self):url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9110'response = sess.get(url,headers=self.headers).text# print(response)# pattern = u'([\u4e00-\u9fa5]+)\|([A-Z]+)'# result = re.findall(pattern, response)result = re.findall(r'([\u4e00-\u9fff]+)\|([A-Z]+)',response)# 将车站与车站代码转为字典类型self.station = dict(result)# 将车站和车站代码位置调换,用于后面的转化 BJP:北京西self.station_names = dict(zip(self.station.values(), self.station.keys()))# print(station)return self.station,self.station_names# 获取车票信息def get_ticket_info(self,station):# 调用系统本地时间(出发时间)# date = time.strftime("%Y-%m-%d", time.localtime())time_original = input('请输入出发日期:\n')time_format = datetime.datetime.strptime(time_original, '%Y%m%d')tomorrow_date = time_format.strftime('%Y-%m-%d')# now_date = datetime.date.today()# tomorrow_date = now_date + datetime.timedelta(days=input('请输入'))print(tomorrow_date)# 起始站from_station = station[input('请输入出发车站:\n')]# 目的站to_station = station[input('请输入到达车站:\n')]sess.cookies.update({'RAIL_EXPIRATION': '1569132689668','RAIL_DEVICEID': 'Ry6Q7Tkau6lvtQFj-1-qD3Mrde9MOKac4kGC5MCLRvgQ5ADb2vySV_SptrTnvjckvQxVWcocw7621ci-T2TmMlg4pChroHuQoXvciR1XyZ52i4ZSiS_dClAx8x_Ck3tg_4or7LxX15-nWH7ilOFn53WcrBup-bN8','route': 'c5c62a339e7744272a54643b3be5bf64'})params = {'leftTicketDTO.train_date': tomorrow_date,'leftTicketDTO.from_station': from_station,'leftTicketDTO.to_station': to_station,'purpose_codes': 'ADULT'}ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?'ticket = sess.get(url=ticket_url,headers=self.headers,params=params).content.decode('utf-8')# print(ticket)# 转化为python字典ticket = json.loads(ticket)return ticket# 展示详细车票余票信息def show_ticket(self,ticket,station_names):# 实例化一个PerttyTable对象并添加表头信息字段--余票信息字段table = PrettyTable(["\t车次","\t出发站“","到达站","\t出发时间","到达时间","历时","商务座\t","一等座","二等座","高级软卧","软卧","动卧"," 硬卧","软座","硬座","\t无座","其他","备注"])# table.align = 'l'# 从python字典数据中取出所有车次余票信息,并遍历ticket_list = ticket['data']['result']for t in ticket_list:data_dic = {}data_list = t.split('|')# for i in enumerate(data_list):#     print(i)# print(data_list)# print(len(data_list))# 车次train_num = data_list[3]# 出发站from_station_name = data_list[6]# 到达站to_station_name = data_list[7]# 出发时间start_time = data_list[8]# 到达时间arrive_time = data_list[9]# 历时took_time = data_list[10]# 商务座business = data_list[32] or data_list[25]# 一等座first = data_list[31]# 二等座second = data_list[30]# 高级软卧high_soft_sleeper = data_list[21]# 软卧soft_sleeper = data_list[23]# 动卧act_sleeper = data_list[27]# 硬卧hard_sleeper = data_list[28]# 软座soft_seat = data_list[24]# 硬座hard_seat = data_list[29]# 无座no_seat = data_list[26]# 其他other = data_list[22]# 备注remark = data_list[1]# 保存到字典data_dic['train_num'] = train_numdata_dic['from_station_name'] = from_station_namedata_dic['to_station_name'] = to_station_namedata_dic['start_time'] = start_timedata_dic['arrive_time'] = arrive_timedata_dic['took_time'] = took_timedata_dic['business'] = businessdata_dic['first'] = firstdata_dic['second'] = seconddata_dic['high_soft_sleeper'] = high_soft_sleeperdata_dic['soft_sleeper'] = soft_sleeperdata_dic['act_sleeper'] = act_sleeperdata_dic['hard_sleeper'] = hard_sleeperdata_dic['soft_seat'] = soft_seatdata_dic['hard_seat'] = hard_seatdata_dic['no_seat'] = no_seatdata_dic['other'] = otherdata_dic['remark'] = remarkcolor = Colored()  # 创建Colored对象data_dic["remark"] = color.blue(data_list[1])# 替换空白字符为--for data in data_dic:if data_dic[data] == '':data_dic[data] = '--'# print(data_dic)# 用于存储字段颜色渲染之后的每一个车次的余票信息,PrettyTable行数据添加ticket_info = []# 开始指定数据的颜色渲染for name in data_dic:# 找到出发站,渲染为淡绿色if name == "from_station_name":c = color.green(station_names[data_dic['from_station_name']])ticket_info.append(c)# 找到到达站,渲染为淡红色elif name == "to_station_name":c = color.red(station_names[data_dic["to_station_name"]])ticket_info.append(c)# 找到出发时间,渲染为淡绿色elif name == "start_time":c = color.green(data_dic['start_time'])ticket_info.append(c)# 找到到达时间,渲染为淡红色elif name == "arrive_time":c = color.red(data_dic["arrive_time"])ticket_info.append(c)# 找到车次,渲染为淡黄色elif name == "train_num":c = color.yellow(data_dic['train_num'])ticket_info.append(c)# 一等座,淡青色elif name == "first":c = color.cyan(data_dic['first'])ticket_info.append(c)# 硬卧,品红elif name == "hard_sleeper":c = color.magenta(data_dic['hard_sleeper'])ticket_info.append(c)# 硬座,绿色elif name == "hard_seat":c = color.green1(data_dic['hard_seat'])ticket_info.append(c)# 其他信息,保持默认颜色else:ticket_info.append(data_dic[name])# 按行添加数据,进行prettytable表格展示,参数为列表:列表为一条记录table.add_row(ticket_info)# 展示表格输出效果print(table)if __name__ == '__main__':# station,station_names = get_station_code()# ticket = get_ticket_info(station)# show_ticket(ticket,station_names)# 实例化车票抓取类ticket_crawl = TicketCrawl()# 返回车站与车站代码互相对应的字典station,station_names = ticket_crawl.get_station_code()# 请求车票信息接口,转化为python字典类型并返回ticket = ticket_crawl.get_ticket_info(station)# 开始解析爬取车票信息,格式化输出ticket_crawl.show_ticket(ticket,station_names)

结果展示:

12306网站车票爬取相关推荐

  1. 12306车站信息爬取(4)——添加车票的票价信息

    在前三篇文章的基础上: 12306车站信息爬取(1)--输入条件的判断,包括出发站,到达站,和出发时间,并获取车次信息的链接 12306车站信息爬取(2)--输入出发站,到达站和出发时间,获取车次信息 ...

  2. 12306车站信息爬取(1)——输入条件的判断,包括出发站,到达站,和出发时间,并获取车次信息的链接

    12306车站信息的爬取是一个比较复杂的系统,爬取需要的信息不是很难,但是要将最终的结果做的完善和美观却不是那么容易.作为一个学习Python的新手,我想把练习和整理结合起来,希望大家可以相互交流和探 ...

  3. Python3--爬取数据之911网站信息爬取

    上代码: #*************************************************** #这份代码用于从911网站上爬取信息 #其中的IP.txt文件为我本地存IP的文件 ...

  4. 实战 | WebMagic 爬取某保险经纪人网站经纪人列表之网站列表爬取

    小小,这次开始使用webmagic爬取相关的网站,这里爬取的网站为 https://member.vobao.com/  将会对该网站进行爬取,并进行实战. 分析网站 打开devtool查看网站相关的 ...

  5. [Python]网站数据爬取任务

    Python爬虫作业:网站数据爬取任务 从以下网址(包括但不限于下列网络或应用)中爬取数据,以核实的形式存储数据,并进行分析(不一定是计算机角度的分析,可写分析报告),或制作词云图. 一.文本数据 酷 ...

  6. 爬虫实战:链家租房数据爬取,实习僧网站数据爬取

    前面已经进行了爬虫基础部分的学习,于是自己也尝试爬了一些网站数据,用的策略都是比较简单,可能有些因素没有考虑到,但是也爬取到了一定的数据,下面介绍两个爬过的案例. 爬虫实战 链家网站爬取 实习僧网站爬 ...

  7. 基于python的数据爬取与分析_基于Python的网站数据爬取与分析的技术实现策略

    欧阳元东 摘要:Python为网页数据爬取和数据分析提供了很多工具包.基于Python的BeautifulSoup可以快速高效地爬取网站数据,Pandas工具能方便灵活地清洗分析数据,调用Python ...

  8. 请访问豆瓣电影网站,爬取4~10部电影信息(电影名、导 演、演员、海报url链接,预报片视频链接),并结合GUI界面展现电影信息,并可以根据选择的电影名, 下载指定预告片视频到本地并显示预告片。GUI

    请访问豆瓣电影网站,爬取4~10部电影信息(电影名.导 演.演员.海报url链接,预报片视频链接),并结合GUI界面展现电影信息,并可以根据选择的电影名, 下载指定预告片视频到本地并显示预告片.GUI ...

  9. 【EduCoder答案】Scrapy爬虫(二)热门网站数据爬取

    简介 答案查询的入口网页版 并不是所有的关卡都有答案,有些只有部分关卡有 不要直接复制答案哦 Scrapy爬虫(二)热门网站数据爬取 >>>查看 第1关:猫眼电影排行TOP100信息 ...

  10. 任选一小说网站,爬取任意一部小说,以记事本的形式保存。

    1.任选一小说网站,爬取任意一部小说,以记事本的形式保存. 第一种情况(网址可能已失效): import requests from lxml import etree def get_url():u ...

最新文章

  1. 【opencv系列07】OpenCV4.X图像基本操作
  2. c++类名字查找与类的作用域
  3. jakarta ee_Jakarta EE中的规范范围
  4. java hssfcell 单元格样式_Java使用poi进行对Excel的操作
  5. JProfiler 解决 Java 服务器的性能跟踪
  6. 参数嗅探_SQL Server 2016参数嗅探
  7. 十一款游戏教你学会 CSS!
  8. 正坐标系及矢量知识,点乘与差乘,旋转
  9. MySQL 用gourp by分组后取某一字段最大值
  10. win10系统开启扫描仪服务器,win10通用扫描仪安装步骤
  11. PHP腾讯云短信接口
  12. 问卷java_Java 问卷调查
  13. PIL Image P和L模式
  14. 英语字母演变——wsdchong
  15. 云计算技术与应用(高职组)赛题库 2019 年全国职业院校技能大赛题库
  16. 论文笔记之Understanding and Diagnosing Visual Tracking Systems
  17. 【Lesson 4】 和弦的大小增减属
  18. 如何清理占用计算机内存,告诉你如何深度清理电脑内存
  19. php微信公众号开发,入门篇(实现了关注公众号发送欢迎信息,发关键词自回复)
  20. folly库安装(4)folly依赖的重要组件安装:double-conversion, google-gflags, glog, fmt, googletest, boost等

热门文章

  1. 原生js删除节点、替换节点、复制节点
  2. 【jQWidgets】API 笔记
  3. 基于 SpringBoot 手写 RPC 框架
  4. Python提取图片中的文字信息
  5. 为了治好拖延症,我祭出了这个自虐的项目,把我搞的卧槽卧槽的
  6. thinkpad10平板电脑装linux,ThinkPad X61上经历Ubuntu 8.10(安装笔记)
  7. 计算机带不动移动硬盘,我笔记本的USB带不动移动硬盘,但另外一台电脑又可以,同样的盘盒,换一块硬盘又可以,...
  8. Linux C/C++程序员 但行好事 莫问前程 Linux系统下 解决Qt5无法连接MySQL数据库的方法
  9. Somebody Loved
  10. 酷柚易汛进销存开发进度一览表以及各版本之间区别!