导入需要的模块
import requests
import re
import ssl
a = input("出发地:")
b = input("目的地:")
c = input("出发日期:")
#表示忽略未经核实的SSL证书认证,防止因为https认证导致访问失败
ssl._create_default_https_context=ssl._create_unverified_context
当然我们还有另一种的方法绕过ssl认证
当网页需要ssl验证的时候,正常爬取会出现SSLError报错,表示证书错误,我们通过设置 verity 参数 为 False 来避免这个错误
import requests
a = requests.get(“[https://www.12306.cn](https://www.12306.cn)”,verify=False)
print(a.status_code)
不过我们会发现一个警告,我们可以通过日志捕获警告的方式,屏蔽警告
import requests
import logging
logging.captureWarnings(True)
a = requests.get(“[https://www.12306.cn](https://www.12306.cn)”,verify=False)
print(a.status_code)
构造requests请求包
由于12306列车查询界面使用的是GET传输,所以我们直接构造url
def get_station():
#12306的城市名和城市代码js文件和URL
url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9143'
r = requests.get(url)
pattern = u'([\u4e00-\u9fa5]+)\|([A-Z]+)'#\u4e00-\u9fa5是所有汉字的Unicode编码范围
result = re.findall(pattern,r.text)#按正则表达式匹配
station=dict(result)
#print(station)
return station
#生成查询的URL
def get_query_url(text):
#城市名代码查询字典
#key:城市名 value:城市代码,如:{'北京北': 'VAP', '北京东': 'BOP', '北京': 'BJP'}
try:
from_station_name= a
to_station_name= b
date= c
from_station = text[from_station_name] #将城市名转换为城市代码
to_station = text[to_station_name]
except:
date,from_station,to_station = '--','--','--'
#API URL构造
url = (
'https://kyfw.12306.cn/otn/leftTicket/query?'
'leftTicketDTO.train_date={}&'
'leftTicketDTO.from_station={}&'
'leftTicketDTO.to_station={}&'
'purpose_codes=ADULT'
).format(date,from_station,to_station)
return url
#print (url)
发送请求,并将爬取到的信息进行整理
#获取车次信息
def query_train_info(url,text):
#headers部分请务必参照自己的浏览器填写,以下参数少一个都会被12306判定为爬虫
headers = {
'Host':'kyfw.12306.cn',
'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E6%B2%88%E9%98%B3,SYT&ts=%E9%9E%8D%E5%B1%B1,AST&date=2020-06-24&flag=N,Y,Y',
'Pragma': 'no-cache',
'Accept': '*/*',
'Connection': 'keep-alive',
'Accept-Language': 'zh-cn',
'Accept-Encoding': 'br, gzip, deflate',
'Cookie':'RAIL_DEVICEID=JPQw57vzB656fgPjLHskLw9ssSt400F26k4-Z1PKlzY-Zn5nk1sjEWvuyBUCsq2Tc8FFmYD4OXSTlTxjm0tOf_0ZDzbjqMRIzwTUA-bGOmVccwg9K4x7zj7ZTrrDPsjvsXeUeQjdylKWVNREuZAZ46VS0nViglny; RAIL_EXPIRATION=1592564633156; BIGipServerindex=1138295050.43286.0000',
'If-Modified-Since': '0',
'Cache-Control': 'no-cache',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36'
}
try:
r = requests.get(url,headers = headers)
#print(r.json())
#获取返回json数据中data字段的result结果
raw_trains = r.json()['data']['result']
for raw_train in raw_trains:
#循环遍历每辆列车的信息
data_list = raw_train.split('|')
#车次号码
train_no = data_list[3]
#出发站
from_station_code = data_list[6]
from_station_name = a
#终点站
to_station_code = data_list[7]
to_station_name = b
#出发时间
start_time = data_list[8]
#到达时间
arrive_time = data_list[9]
#总耗时
time_fucked_up = data_list[10]
#一等座
first_class_seat = data_list[31] or '--'
#二等座
second_class_seat = data_list[30] or '--'
# 软卧
soft_sleep = data_list[23] or '--'
# 硬卧
hard_sleep = data_list[28] or '--'
# 硬座
hard_seat = data_list[29] or '--'
# 无座
no_seat = data_list[26] or '--'
# 打印查询结果
info = (
'-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n'
'|车次:{} | 出发站:{} | 目的地:{} | 出发时间:{} | 到达时间:{} | 消耗时间:{} | '
'| 一等座:「{}」| 二等座:「{}」| 软卧:「{}」| 硬卧:「{}」| 硬座:「{}」| 无座:「{}」|\n'
'-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------'.format(train_no,from_station_name,to_station_name,start_time,arrive_time,
time_fucked_up,first_class_seat,
second_class_seat,soft_sleep,hard_sleep,hard_seat,no_seat)
)
print(info)
except Exception as e:
print(e)
if __name__ == '__main__':
text = get_station()
url = get_query_url(text)
#循环查询,知道查询到想要的车次有票终止
'''while True:
time.sleep(1)#刷票频率
if query_train_info(url,text):
break'''
query_train_info(url,text)
效果如下