2021最新python爬取12306列车信息自动抢票并自动识别验证码

自然语言处理之 snownlp,分词、词性标注、情感分析、文本分类、提取关键词、文本相似度 情感分析的基本流程通常包括: 自定义爬虫抓取文本信息; 使用Jieba工具进行中文分词、词性标注; 定义情感词典提取每行文本的情感词; 通过情感词构建情感矩阵,并计算情感分数; 结果评估,包括将情感分数置于0.5到-0.5之间,并可视化显示。 SnowNLP SnowNLP是一个常用的Python文本分析库,是受到TextBlob启发而发明的。由于当前自然语言处理库基本都是针对英文的,而中文没有空格分割特征词,Python做中文文本挖掘较难,后续开发了一些针对中文处理的库,例如SnowNLP、J 阅读详情

项目描述

项目前言

tiebanggg又来更新了,项目——【12306-tiebanggg-master】注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除;切忌用于一切非法途径,否则后果自行承担!

 

通过分析123O6,车次列表信息无需登录即可获取,但是如果我们想要使用代码代替手动为自己进行购票时,则需要进行登录网站;为了不给对方服务器造成压力,本项目并未开启多线程。项目为全自动进行车票的购买,包括(登录、验证码识别、刷票、判断是否有票、预购、下单、邮箱通知)本项目思路——使用selenium登录网站获取到cookie(供后续购票使用),定时检查cookie是否有效,获取列车列表信息及购票流程均使用requests的方式进行。

本项目结构如图:
在这里插入图片描述

本篇技术手段

本项目思路、过程过于复杂,共分为【列车数据获取篇】【selenium登录验证篇】【购票下单篇】【项目结束】,本篇文章只讲第三点【购票下单篇】
涉及到的第三方包:
① lxml
② requests
③ lxmll

一. 抓包并编写相应函数

本次“幸运”对象地址:aHR0cHM6Ly93d3cuMTIzMDYuY24vaW5kZXgvaW5kZXguaHRtbA==

1. 抓包
①搜先进入车票搜索页面进行车票检索,选一个车次点击预定进行抓包在这里插入图片描述
当我们点击【预定】后,抓包框如图:在这里插入图片描述
我们选中XHR总共抓到三条接口,并且执行顺序为从上到下:checkUser > submitOrderRequest > getPassengerDTOs;checkUser看意思大概率可以知道是网页对我们的登录状态经行验证(就是验证登录状态)只要登陆后这条接口可以不用再次提交,此前我们第二篇登陆篇已经实现访问链接,submitOrderRequest 和getPassengerDTOs这两个接口都是需要进行提交认证的(博主试验得知)在这里就不多绕弯子,一般post购买流程大多数流程都是 一层一层进行验证往下走。下面看看submitOrderRequest这条接口需要的formdata参数:
在这里插入图片描述

可以看到secretStr类似加密的东西,这里细心的同学应该会发现和我们第一篇获取到的列车信息中返回的字段有些类似,其他的参数不过多介绍分别出发日期、出发地址等这些基本信息:在这里插入图片描述
复制出来对比一下,这里选择20:50这一列车的信息进行对比:03Z6dtSr5ZfgGUZR9R3nOVDdAwVdRhTaTfZ1%2FQ5qbxA%2BTG8Wm9jS7UhSR2AFHT8Wrmbx3DLwtgJ2%0AtQHWoFcQ2rhg93EbGiVF2DPqDFSOzf96DX7U7uxitG7FZHce7iLWpqJerbacxAWRQ7BZPDF8mOcf%0Af9QOdt%2FtipR8%2FZB8S89haCQR%2FK6ahIwtagRAC8AquzW8kXmi6Bp4CG%2B8CCY5Z3NsYOLfESCD0Paz%0AGJonq72dLRG%2F%2BMBWj626UAMLxSY6J8xaLeqI%2BCt3G8mPv9tWhSMYJAywb195JqLFLMcGTkDBXeKq%0AyTr3GpSmgnc%3D|预订|78000G534800|G5348|UMW|KQW|UMW|KQW|20:50|22:14|01:24|Y|feCBT%2FrWrwy91MXCgDsiZWf0HVdHNrDU2uYqthfRk4bOY6RP|20210228|3|W2|01|05|1|0|||||||||||有|有|10||O0M090|OM9|1|0||O007750021M0128000219023950010|0|||||1|0#0#0|"

secretStr: 03Z6dtSr5ZfgGUZR9R3nOVDdAwVdRhTaTfZ1/Q5qbxA+TG8Wm9jS7UhSR2AFHT8Wrmbx3DLwtgJ2
tQHWoFcQ2rhg93EbGiVF2DPqDFSOzf96DX7U7uxitG7FZHce7iLWpqJerbacxAWRQ7BZPDF8mOcf
f9QOdt/tipR8/ZB8S89haCQR/K6ahIwtagRAC8AquzW8kXmi6Bp4CG+8CCY5Z3NsYOLfESCD0Paz
GJonq72dLRG/+MBWj626UAMLxSY6J8xaLeqI+Ct3G8mPv9tWhSMYJAywb195JqLFLMcGTkDBXeKq
yTr3GpSmgnc=

可以看到基本上一致,但是他们并不相等,列车信息返回的字符串中包含有%2F、%2B、%0A、%3D等字符而secretStr中却没有,根据经验判断这些字符是通过url编码而成,我们拿两条字符串的最后几位进行对比(Tr3GpSmgnc%3D : Tr3GpSmgnc=)发现最后一个字符‘=’变成了%3D,这里将%3D放入工具进行解码看看:
在这里插入图片描述
没错%3D等于=,其他几个通过转换得知%2F == /,%2B == +,%0A == 换行符。我们将字符串提出用python进行替换成submitOrderRequest需要提交的secretStr 参数:

sec = '03Z6dtSr5ZfgGUZR9R3nOVDdAwVdRhTaTfZ1%2FQ5qbxA%2BTG8Wm9jS7UhSR2AFHT8Wrmbx3DLwtgJ2%0AtQHWoFcQ2rhg93EbGiVF2DPqDFSOzf96DX7U7uxitG7FZHce7iLWpqJerbacxAWRQ7BZPDF8mOcf%0Af9QOdt%2FtipR8%2FZB8S89haCQR%2FK6ahIwtagRAC8AquzW8kXmi6Bp4CG%2B8CCY5Z3NsYOLfESCD0Paz%0AGJonq72dLRG%2F%2BMBWj626UAMLxSY6J8xaLeqI%2BCt3G8mPv9tWhSMYJAywb195JqLFLMcGTkDBXeKq%0AyTr3GpSmgnc%3D'
secretStr = secretStr.replace('%2F', '/').replace('%0A', '').replace('%2B', '+').replace('%3D', '=')
12

得到参数后编写出submit函数:

def submit(self, res, cookies, read_id, item):
     url = "https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest"
     data = {
         'secretStr': res,
         'train_date': variable.date,
         'back_train_date': variable.date,
         'tour_flag': 'dc',
         'purpose_codes': 'ADULT',
         'query_from_station_name': read_id[item.split('|')[6]],
         'query_to_station_name': read_id[item.split('|')[7]],
     }
     setting.headers['User-Agent'] = random.choice(USER_AGENTS)
     print('[submit]-data:', data)
     response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies)
     try:
         messages = json.loads(response.text)['messages']
         print('[submit]-messages:', messages)
         print('[submit]-ponse.status_code:', response.status_code)
         print('[submit]-response.text:', response.text)
         if len(messages) != 0:
             if '当前时间不可以订票' in messages[0]:
                 return '当前时间不可以订票'
             elif '您还有未处理的订单' in messages[0]:
                 return '您还有未处理的订单'
             elif '提交失败,请重试...' in messages[0]:
                 return '提交失败,请重试...'
             else:
                 return 'True'
         else:
             return 'True'
123456789101112131415161718192021222324252627282930

接下来看看getPassengerDTOs这条接口的响应和data参数:
在这里插入图片描述

在这里插入图片描述
响应:登录账号的基本信息。

data参数:只有一个REPEAT_SUBMIT_TOKEN,这个token不知道是啥玩意但是看着像md5签名,这里提供思路:1,全局搜索看看服务器是否有返回REPEAT_SUBMIT_TOKEN; 2,搜索JS定位到前面位置,还原签名算法;
在这里插入图片描述
在这里插入图片描述
这里我们只用了第一种方法就找出了REPEAT_SUBMIT_TOKEN,看看Headers:在这里插入图片描述
可以看到并没有加密的表单参数,在这里只需要提交cookie验证即可返回数据,initDc函数代码如下:

def initDc(self, cookies):
     """
     请求 url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
     获取到REPEAT_SUBMIT_TOKEN, leftTicket, ticketInfoForPassengerForm
     :param cookies:
     :return:
     """
     url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
     data = {
         '_json_att': ''
     }
     setting.headers['User-Agent'] = random.choice(USER_AGENTS)
     response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies)
     # print(response.text)
     globalRepeatSubmitToken = re.search(r"globalRepeatSubmitToken = '(.*?)'", response.text)
     print('[initDc]-globalRepeatSubmitToken:', globalRepeatSubmitToken)
     return globalRepeatSubmitToken
1234567891011121314151617

接下来编写confirmPassengergetPassengerDTOs函数并返回响应信息userinfo:

def confirmPassengergetPassengerDTOs(self, REPEAT_SUBMIT_TOKEN, cookies):
    url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'
    data = {
        '_json_att': '',
        'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
    }
    setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies).text
    userinfo = json.loads(response)
    print('[confirmPassengergetPassengerDTOs]-userinfo', userinfo)
    return userinfo
123456789101112

OK,下一步选择乘车人,点击提交订单进行抓包:弹出在这里插入图片描述
弹出如图,并且抓到两条接口信息:
在这里插入图片描述

接下来看看他们的formdata表单:
checkOrderInfo在这里插入图片描述
getQueueCount在这里插入图片描述
可以看到两条接口都需要提交REPEAT_SUBMIT_TOKEN参数,在之前我们已经提取到,除了passengerTicketStr,oldPassengerStr,REPEAT_SUBMIT_TOKEN外其他的参数为固定值。接下来获取passengerTicketStr,这里给出参数说明,在这里插入图片描述
可以看到passengerTicketStr里面包含了购票人的基本信息(登录账号)和座位类型id信息,细心的童鞋应该会发现,这里的参数和上面
getPassengerDTOs接口返回的响应信息中有些类似:
在这里插入图片描述
不用多说,这里的加密参数就等于allEncStr。而oldPassengerStr中的参数分别为身份证号和电话号码。
座位类型id信息不做过多介绍,只需要进行几次抓包即可得到,然后再setting_class.py的variable类中定义字典:

# 座位类型对应id
zuoweiID = {
        '商务座': '9',
        '一等座': 'M',
        '二等座': 'O',

        '硬卧': '3',
        '硬座': '1',
        '软卧': '4'
        }
12345678910

到这已经获取到了所有的表单参数,接下来编写checkOrderInfo函数:

def checkOrderInfo(self, userinfo, REPEAT_SUBMIT_TOKEN, cookies):
    """
    :param userinfo: 通过 confirmPassengergetPassengerDTOs函数得到
    :param REPEAT_SUBMIT_TOKEN: 通过 initDc函数得到
    :param cookies:
    :return:
    """
    userinfo = userinfo
    url = "https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo"
    passenger_id_no = userinfo['data']['normal_passengers'][0]['passenger_id_no']       # 身份证
    mobile_no = userinfo['data']['normal_passengers'][0]['mobile_no']                   # 电话
    allEncStr = userinfo['data']['normal_passengers'][0]['allEncStr']
    passenger_name = userinfo['data']['normal_passengers'][0]['passenger_name']         # 姓名
    data = {
        'cancel_flag': '2',
        'bed_level_order_num': '000000000000000000000000000000',
        'passengerTicketStr': '{},0,1,{},1,{},{},N,{}'.format(variable.play_zuowei_id, passenger_name, passenger_id_no, mobile_no, allEncStr),
        'oldPassengerStr': '{},1,{},1_'.format(passenger_name, passenger_id_no),
        'tour_flag': 'dc',
        'randCode': '',
        'whatsSelect': '1',
        'sessionId': '',
        'sig': '',
        'scene': 'nc_login',
        '_json_att': '',
        'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
    }
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    print('[checkOrderInfo]-data:', data)
    setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies).text
    print('[checkOrderInfo]-response.text:', response)
    return [passenger_name, mobile_no, passenger_id_no]
123456789101112131415161718192021222324252627282930313233

再看看getQueueCount这条接口的formdata表单:
在这里插入图片描述

data = {
   'train_date': '当前星期缩写+当前月份缩写+当前日期+当前年份',
    'train_no': '通过 secretStr列车字符串得到,切割处理提取即可',
    'stationTrainCode': '通过 secretStr列车字符串得到,切割处理提取即可',
    'seatType': '3',
    'fromStationTelecode': '通过 secretStr列车字符串得到,切割处理提取即可',
    'toStationTelecode': '通过 secretStr列车字符串得到,切割处理提取即可',
    'leftTicket': '通过 initDc函数得到',
    'purpose_codes': '00',
    'train_location': '通过 secretStr列车字符串得到,切割处理提取即可',
    '_json_att': '',
    'REPEAT_SUBMIT_TOKEN': '通过 initDc函数得到',
        }
12345678910111213

当前星期缩写+当前月份缩写可以通过百度得到,得到响应数据后在setting_class.py的variable类中构造字典:

# 1-12月英文缩写
yuefen = {
        '01': 'Jan',
        '02': 'Feb',
        '03': 'Mar',
        '04': 'Apr',
        '05': 'May',
        '06': 'Jun',
        '07': 'Jul',
        '08': 'Aug',
        '09': 'Sept',
        '10': 'Oct',
        '11': 'Nov',
        '12': 'Dec',
        }
# 周1-周日英文缩写
xingqi = {
        '1': 'Mon',
        '2': 'Tues',
        '3': 'Wed',
        '4': 'Thur',
        '5': 'Fri',
        '6': 'Sat',
        '7': 'Sun',
        }
12345678910111213141516171819202122232425

前面initDc函数我们只获取到了REPEAT_SUBMIT_TOKEN,现在只需要再进行leftTicket的提取即可:

def initDc(self, cookies):
    url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    data = {
        '_json_att': ''
    }
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies)
    globalRepeatSubmitToken = re.search(r"globalRepeatSubmitToken = '(.*?)'", response.text)
    print('[initDc]-globalRepeatSubmitToken:', globalRepeatSubmitToken)
    leftTicket = re.search(r"'leftTicketStr':'(.*?)'", response.text)
    print('[initDc]-leftTicket:', leftTicket) ticketInfoForPassengerForm)

    return globalRepeatSubmitToken, leftTicket
12345678910111213

所有参数获取方式已经得知,现在构造getQueueCount函数:

def getQueueCount(self, REPEAT_SUBMIT_TOKEN, leftTicket, item, cookies, train_no, stationTrainCode, train_location):
    url = "https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount"
    data = {
        'train_date': '{} {} {} {} 00:00:00 GMT+0800 (中国标准时间)'.format(
            variable.xingqi[self.weekdays(variable.date)],
            variable.yuefen[variable.date.split('-')[1]],
            variable.date.split('-')[2],
            variable.date.split('-')[0]),
        'train_no': train_no,
        'stationTrainCode': stationTrainCode,
        'seatType': '3',
        'fromStationTelecode': item.split('|')[6],
        'toStationTelecode': item.split('|')[7],
        'leftTicket': leftTicket.group(1),
        'purpose_codes': '00',
        'train_location': train_location,
        '_json_att': '',
        'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
    }
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    print('[getQueueCount]-data:', data)
    response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies).text
    print('[getQueueCount]-response.text:', response)
1234567891011121314151617181920212223

接下来点击确认,再次进行下一步抓包:
在这里插入图片描述
在这里插入图片描述
可以看到抓到了四条接口地址,执行顺序为从上到下,到这里抢票逻辑基本上完成,并且抢到了车票,只需要在30分钟内付款即可,可以登录12306app进行付款或网页进行付款。
看看confirmSingleForQueue接口的formdata:
在这里插入图片描述
这里只说key_check_isChange和encryptedData两个参数,其他的在前面已经获取到。
key_check_isChange: 通过 initDc函数得到的ticketInfoForPassengerForm字符串,切割处理提取即可。
encryptedData:加密字符串,可以写死。如果有兴趣的童鞋想知道具体算法可以进行JS逆向,为节省时间这里不做介绍。

下面编写confirmSingleForQueue函数:

def confirmSingleForQueue(self, userinfo, key_check_isChange, leftTicketStr, REPEAT_SUBMIT_TOKEN, train_location, cookies):
    """
    :param userinfo: 通过 confirmPassengergetPassengerDTOs函数得到
    :param key_check_isChange: 通过 initDc函数得到的ticketInfoForPassengerForm字符串,切割处理提取即可
    :param leftTicketStr: 通过 initDc函数得到的对象
    :param REPEAT_SUBMIT_TOKEN: 通过 initDc函数得到
    :param train_location: 通过 secretStr列车字符串得到,切割处理提取即可
    :param cookies:
    :return:
    """
    url = "https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue"
    passenger_id_no = userinfo['data']['normal_passengers'][0]['passenger_id_no']  # 身份证
    mobile_no = userinfo['data']['normal_passengers'][0]['mobile_no']  # 电话
    allEncStr = userinfo['data']['normal_passengers'][0]['allEncStr']
    passenger_name = userinfo['data']['normal_passengers'][0]['passenger_name']  # 姓名
    data = {
        'passengerTicketStr':  '{},0,1,{},1,{},{},N,{}'.format(variable.play_zuowei_id, passenger_name, passenger_id_no, mobile_no, allEncStr),
        'oldPassengerStr': '{},1,{},1_'.format(passenger_name, passenger_id_no),
        'randCode': '',
        'purpose_codes': '00',
        'key_check_isChange': key_check_isChange.group(1),
        'leftTicketStr': leftTicketStr.group(1),
        'train_location': train_location,
        'choose_seats': '',
        'seatDetailType': '000',
        'is_jy': 'N',
        'encryptedData':'',
        'whatsSelect': '1',
        'roomType': '00',
        'dwAll': 'N',
        '_json_att': '',
        'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
    }
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    response = self.session.post(url=url, data=data, headers=setting.headers, cookies=cookies).text
    print("[confirmSingleForQueue]-response.text:", response)
    if '余票不足' in response:
        return '余票不足!'
    else:
        return 'True'
1234567891011121314151617181920212223242526272829303132333435363738394041

queryOrderWaitTime接口可以忽略,不做介绍,有兴趣的同学可以自行研究。

接下来再看resultOrderForDcQueue接口的formdata表单:
在这里插入图片描述
这里的orderSequence_no怎么来?先全局搜索一下:
在这里插入图片描述
在这里插入图片描述
没错,是服务器返回的,看看Headers:
在这里插入图片描述
这里formdata参数都是有的,只需要提交请求并且进行sequence_no的提取(sequence_no==orderSequence_no)即可, 下面编写playOrder函数:

def payOrder(self, REPEAT_SUBMIT_TOKEN, cookies):
    """
    支付必须先走这一步,服务器会记录指纹
    :param REPEAT_SUBMIT_TOKEN: 通过 initDc函数得到
    :param cookies:
    :return: sequence_no, payOrder_url
    """
    url = 'https://kyfw.12306.cn/otn//payOrder/init?'
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
    data = {
        'json_att': '',
        'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
    }
    params = {
        'random':str(int(time.time()*1000))
    }
    response = self.session.post(url=url, data=data, headers=setting.headers,
                                 cookies=cookies, params=params).text
    if len(list(response)) < 3000:
        print("[payOrder]-response.text", response)
    sequence_no = re.search(r"sequence_no = '(.*?)'", response)
    print("[payOrder]-sequence_no:", sequence_no)
    payOrder_url = url
    return sequence_no, payOrder_url + 'random=' + params['random']
12345678910111213141516171819202122232425

在payOrder函数中我们返回了两个参数,sequence_no, payOrder_url + ‘random=’ + params[‘random’],后者是支付环节需要的url,在这里提前获取。
下面编写resultOrderForDcQueue函数:

def resultOrderForDcQueue(self, sequence_no, REPEAT_SUBMIT_TOKEN, cookies):
      """
      :param sequence_no: 通过payOrder函数获得
      :param REPEAT_SUBMIT_TOKEN: 通过 initDc函数得到
      :param cookies:
      :return: None
      """
      url = "https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue"
      setting.headers['User-Agent'] = random.choice(USER_AGENTS)
      setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
      data = {
          'orderSequence_no': sequence_no.group(1),
          '_json_att': '',
          'REPEAT_SUBMIT_TOKEN': REPEAT_SUBMIT_TOKEN.group(1),
      }
      response = self.session.post(url=url, data=data, cookies=cookies, headers=setting.headers).text
      print("[resultOrderForDcQueue]-response.text:", response)
1234567891011121314151617

我们可以写两个验证函数来验证抢票是否成功:

def queryMyOrderNoComplete(self, cookies):
    """
    获取待支付订单信息
    :param cookies:
    :return:
    """
    url = "https://kyfw.12306.cn/otn/queryOrder/queryMyOrderNoComplete"
    setting.headers['User-Agent'] = random.choice(USER_AGENTS)
    setting.headers['Referer'] = 'https://kyfw.12306.cn/otn/view/train_order.html'
    data = {
        '_json_att': '',
    }

    info_dict = {}
    response = self.session.post(url=url, headers=setting.headers, cookies=cookies, data=data).text
    jsdata = json.loads(response)['data']['orderDBList'][0]
    info_dict['姓名:'] = jsdata['array_passser_name_page'][0]         # 姓名
    info_dict['出发地:'] = jsdata['from_station_name_page'][0]        # 出发地
    info_dict['目的地:'] = jsdata['to_station_name_page'][0]          # 目的地
    info_dict['出发日期:'] = jsdata['start_train_date_page'].split(' ')[0]             # 出发日期
    info_dict['订单号:'] = jsdata['sequence_no']                   # 订单号
    info_dict['价格:'] = jsdata['ticket_total_price_page']         # 价格
    info_dict['出发时间:'] = jsdata['start_time_page']             # 出发时间
    info_dict['到达时间:'] = jsdata['arrive_time_page']            # 到达时间
    info_dict['车次:'] = jsdata['train_code_page']                 # 车号
    tickets = jsdata['tickets'][0]
    a = tickets['coach_name']                   # 车厢
    b = tickets['seat_name']                    #座位号
    info_dict['列车信息:'] = a + '车' + b
    info_dict['座位性质:'] = tickets['seat_type_name']          # 座位性质
    info_dict['支付时间:'] = tickets['reserve_time']            # 支付时间
    info_dict['到期时间:'] = tickets['pay_limit_time']          # 到期时间
    return info_dict
123456789101112131415161718192021222324252627282930313233
def check_play(self, cookies):
      """
      判断是否抢购成功
      :param d_play:
      :return:
      """
      i = 0
      while True:
          time.sleep(0.3)
          i += 1
          try:
              d_play = self.queryMyOrderNoComplete(cookies=cookies)
              cc = d_play['车次:']
              rt = 'True'
              break
          except:
              if i > 5:
                  rt = 'False'
                  break

      if rt == 'True':
      	# 抢票成功
          return True
      if rt == 'False':
      	# 抢票失败
          return False

123456789101112131415161718192021222324252627

到此抢票项目已经完成%99,剩下的就是邮箱推送通知【项目介绍】篇,会尽快更新给大家。

下一章节【python爬取12306列车信息自动抢票并自动识别验证码(四)结束篇(邮箱推送通知)】 敬请期待

这里一直忘了还有一个章节:定时cookie监测服务——检测cookie是否过期,若过期服务将自动重启登录服务进行cookie的保存使用,避免抢票过程中重新登录从而失去购票机会,会在邮箱推送之后推出,谢谢大家关注。

近期有很多朋友通过私信咨询有关Python学习问题。为便于交流,点击蓝色自己加入讨论解答资源基地

​

 

python实现12306抢票,春节不用担心买不到票回家了 # 以下进行登陆操作 # 建立cookie处理 cjar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar)) urllib.request.install_opener(opener) # 以下进入自动登录部分 loginurl = &amp;amp;amp;quot;https://kyfw.12306.cn/otn/login/ini 阅读详情

相关推荐

中文自然语言处理库(SnowNLP)的简单使用

snownlp的库简单使用,中文自然语言处理。

weixin_46277779的博客 1万+

【原来python还可以这么玩】python逆向爬取网易云评论进行情感分析

遥遥微光,与我同行 好久不见,各位小伙伴们!嗐,春节真滴快啊!祝大家新年快乐! 书山有路勤为径,学海无涯苦作舟!又得开始愉快滴学习了! 小夜斗今天给大家伙分享一期干货,芜湖起飞! JS逆向网易云爬取评论并利用snownpl进行情感分析 一:逆向破解网易云参数抓取评论信息 网易云PC端url: https://music.163.com/#/song?id=1817702136 要抓取滴评论如下图所示: 老规矩,检查网页元素,找到评论信息所在的请求网址! 从xhr里面找一下子就能找到,看下面截图: 如

xtreallydance的博客 9081

利用Python爬取12306网站车次信息

采集12306官网车次信息

刘康康的博客 1704

情感分析——深入snownlp原理和实践

一、snownlp简介 snownlp是什么? SnowNLP是一个python写的类库,可以方便的处理中文文本内容,是受到了TextBlob的启发而写的,由于现在大部分的自然语言处理库基本都是针对英文的,于是写了一个方便处理中文的类库,并且和TextBlob不同的是,这里没有用NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字典。注意本程序都是处理的unicode编码,所以使...

null的专栏 13万+

ABAP动态填充Word模板:基于cl_docx_document的XML替换方案

本文详细介绍了ABAP中基于cl_docx_document类的动态Word模板填充方案。该方案通过直接操作DOCX文件的XML核心,完美解决了传统OLE/DOI方法在格式保真、性能和后台运行方面的痛点,是实现复杂、批量Word文档生成的优雅解决方案。

gpt4scribbler的博客 525

全国30米分辨率逐年植被覆盖度(FVC)数据集

植被覆盖度是描述地表植被的重要参数与生态环境的基本指标,在大气圈、土壤圈、水圈和生物圈中都占据着重要的地位,区域及全球范围的植被覆盖度估算对植被及相关领域的研究具有重要意义。分别对LANDSAT 5/7/8系列数据计算FVC,其中Landsat5 和Landsat 7NDVI计算利用 B4和B3波段,Landsat8 和Landsat9 NDVI计算利用 B5和B4波段。算法从当年所有观测数据中,以低云、低探测角度和最高NDVI值为标准,选择最佳的可用像元值,并进行换算。(3) FVC的计算。

地球资源数据云的官方博客 1808

2021最新 python爬取12306列车信息自动抢票并自动识别验证码(三)购票篇

项目前言 tiebanggg又来更新了,项目——【12306-tiebanggg-master】注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除;切忌用于一切非法途径,否则后果自行承担! 项目描述 通过分析123O6,车次列表信息无需登录即可获取,但是如果我们想要使用代码代替手动为自己进行购票时,则需要进行登录网站;为了不给对方服务器造成压力,本项目并未开启多线程。项目为全自动进行车票的购买,包括(登录、验证码识别、刷票、判断是否有票、预购、下单、邮箱通知)本项目思路——使用seleni

tiebanggg的博客 5411

C语言头文件完全解析(连“#”我都给你讲明白)

C语言头文件完全解析 引言 本文将尽量详细的介绍c语言的头文件所包含的知识,如有错误,还望指正。 萌新们肯定疑惑为什么每次打代码都要写一个所谓的头文件(如:#include<stdio.h>),这里先简单让大家有个了解,你所用的 printf("%d",a)就是这个 stdio里的东西,如果没有这个头文件,编译器都不知道 printf是个什么东东。所以头文件就是一个准备好的大仓库,你可...

CRAZY_eyes的博客 7万+

python爬取12306列车信息自动抢票并自动识别验证码(一)列车数据获取篇

项目前言 自学python差不多有一年半载了,这两天利用在甲方公司搬砖空闲之余写了个小项目——【12306-tiebanggg-master】刚好在昨天帮朋友抢了一张票(祝他一路平安)hhhhh。注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除;请勿用于一切非法行为,否则后果自行承担! 项目描述 通过分析123O6,车次列表信息无需登录即可获取,但是如果我们想要使用代码代替手动为自己进行购票时,则需要进行登录网站。项目为全自动进行车票的购买,包括(登录、验证码识别、刷票、判断是否有票、预

tiebanggg的博客 5894

Python全栈入门到实战【进阶篇 2】面向对象之封装:私有属性、私有方法与@property优雅访问

_属性名真正私有方法:双下划线开头(__方法名()),Python自动名字改写,外部无法访问;约定私有方法:单下划线开头(_方法名()),仅为编程约定,外部可访问但不推荐。实战中优先使用“真正私有方法”,隐藏核心辅助逻辑。封装的本质:隐藏对象的核心数据(私有属性)和内部逻辑(私有方法),仅对外提供规范、安全的访问接口,实现数据安全与可维护性;私有属性真正私有:双下划线开头(__属性名),Python名字改写,外部无法直接访问,仅类内部可用;约定私有:单下划线开头(_属性名。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 2913

Windows Docker + RK3588 部署 YOLO26-Pose 人体姿态检测

YOLO26-Pose 在 RK3588 上的部署流程是 Windows Docker 容器内 ONNX 导出 → RKNN 转换(INT8 量化)→ ADB 推送 → 板端 C++ 推理。YOLO26n-Pose 在 640 输入下全链路约 55 FPS,可以覆盖实时姿态检测需求。先在板端用单张图片验证关键点输出正确性,确认 C++ 后处理的解析逻辑无误后,再切换到摄像头实时推理。

m0_64661770的博客 98

python爬取12306列车信息自动抢票并自动识别验证码(二)selenium登录验证篇

项目前言 自学python差不多有一年半载了,这两天利用在甲方公司搬砖空闲之余写了个小项目——【12306-tiebanggg-master】刚好在昨天帮朋友抢了一张票(祝他一路平安)hhhhh。注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除;请勿用于一切非法行为,否则后果自行承担! 项目描述 通过分析123O6,车次列表信息无需登录即可获取,但是如果我们想要使用代码代替手动为自己进行购票时,则需要进行登录网站;为了不给对方服务器造成压力,本项目并未开启多线程。项目为全自动进行车票的购

tiebanggg的博客 3413

『MaxKB 2.x 开发环境搭建』在Windows下运行最新源码的完整步骤

本文将详细介绍如何在Windows系统中完成MaxKB最新版(2.x)开发环境的搭建,包括前端、后端以及数据库的配置,确保开发者能够顺利启动项目。

老陈聊架构 584

使用Python爬虫查询12306列车信息

Python爬虫爬取12306车次信息

Z_Vixerunt的博客 3249

基于Matlab使用雷达资源管理有效跟踪多个机动目标仿真(附源码)

多功能雷达可以搜索目标,确认新轨道,并重新访问轨道以更新状态。为了执行这些功能,多功能雷达通常由资源管理器管理,该资源管理器创建用于搜索、确认和跟踪的雷达任务。这些任务是根据优先级和时间安排的,因此,在每个时间步长中,多功能雷达都可以将其波束指向所需的方向。在此示例中,对于用于跟踪机动目标的雷达,有两个相互冲突的要求:目标的数量及其初始位置通常事先不知道。因此,雷达必须不断搜索感兴趣的区域才能找到目标。此外,雷达需要在进入雷达覆盖区域后立即检测并建立对每个目标的跟踪。目标机动的时间段事先是未知的。

珞瑜的博客 3145

各向同性、VTI、TTI以及双相介质波场数值模拟

各位读者,大家好!在今天的文章中,我将介绍关于波场数值模拟中的各向同性、VTI(垂直横向等参数介质)、TTI(倾斜横向等参数介质)以及双相介质的基本概念。同时,我也会提供一些基础的Fortran代码片段,供大家了解和学习。

qq_38334677的博客 1707

12306抢票系统无界面版本——(4)完成购票与抢票

引言 因为老师突然给了个比赛,所以就和我朋友一起参加了,我负责的工作是项目整合和界面的绘画,使用的语言是python,用pyQT5画的界面。项目完成这里我做一些笔记。 前面的爬取就直接看我朋友的文章吧 获取验证码:https://blog.youkuaiyun.com/r244925932/article/details/81227873 获取车票信息:htt...

r244925932的博客 3028

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

12306爬虫的一点笔记

引言 因为老师突然给了个比赛,所以就和我朋友一起参加了,我负责的工作是项目整合和界面的绘画,使用的语言是python,用pyQT5画的界面。项目完成这里我做一些笔记。 前面的爬去就直接看我朋友的文章吧 获取验证码:https://blog.youkuaiyun.com/r244925932/article/details/81227873 获取车票信息:https://blog.youkuaiyun.com/r2...

qq_39816322的博客 1578

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

python3 requests 12306下单环节

完成之前的登录,查票(城市编号转换之后),重头戏也是最复杂的环节来了,要完成下单,需要经过下列一系列验证,且均要通过验证,由此可见12306的反爬机制做的还是相当出色的。 1、检查用户是否保持登录成功     https://kyfw.12306.cn/otn/login/checkUser 2、点击预定    https://kyfw.12306.cn/otn/leftTicket/subm...

heccxx的博客 4554

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

NLP之中文自然语言处理工具库:SnowNLP(情感分析/分词/自动摘要)

SnowNLP是一个python写的类库,可以方便的处理中文文本内容,是受到了TextBlob的启发而写的,由于现在大部分的自然语言处理库基本都是针对英文的,于是写了一个方便处理中文的类库,并且和TextBlob不同的是,这里没有用NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字典。注意本程序都是处理的unicode编码,所以使用时请自行decode成unicode。算法基于TextRank。

编辑编辑器 1万+

python爬取网易云音乐评论并进行情感分析_使用python3爬取网易云音乐的评论

用过很多播放器,之前一直是酷我,偶尔QQ。但是网易云音乐出来后毅然变成了他的忠实用户。精确推荐和乐评都很赞!安利了不少人入坑。前些日子网易云音乐将精选用户评论搬上了地铁,使网易云音乐又火了一把。因此就想爬取一些歌曲的评论。分析网络请求如图我们可以看到有两个参数params和encSecKey。现在如何得到这两个参数就变得至关重要。参考知乎https://www.zhihu.com/question...

weixin_39981041的博客 2683

confirmSingleForQueue(确认队列中单个状态)

参数列表: passengerTicketStr:getpassengerTickets()//seat_type + ",0," + ticket_type + "," + name + "," + id_type + "," + id_no + "," + (phone_no == null  ? "" : phone_no) + "," + (save_statu

dieTicket的博客 900

python实现12306购票下单

2:进入购票页面获取到提交参数的SubmitToken,同时提交订单时候有一个加密参数,通过分析页面的js代码,发现在页面加载时候就触发的方法挂载了全局的window.json_ua.toString(),我们使用浏览迷模拟这个js执行结果获取加密参数encryptedData,最终通过调用https://kyfw.12306.cn/passport/web/auth/uamtk获取票据,然后根据票据换取全局cookie的tk。废话不多说,先人工走一遍流程,打开查询高铁的页面发现查询接口。

weixin_42496578的博客 4211

NLP_Python3——朴素贝叶斯算法

1.贝叶斯公式: P(Y|X)=P(X|Y)P(Y)/P(X) 推导公式: P(Y,X)=P(Y|X)P(X)=P(X|Y)P(Y) P(Y)为先验概率,即X发生前对Y发生的概率的一个判断(可通过大量样本统计出来);P(Y|X)为后验概率,即在X发生后,对Y发生的概率的重新评估;P(Y,X)为联合概率,即XY都发生的概率;P(Y|X)P(X)为可能性函数,这是一个调整因子,使得预估概率更接...

Loong的博客 537

解析12306订票流程

前言 每当春节临近时,因为网络的方便,访问12306购买火车票回家过年成了很多人的首选。但由于12306的种种不给力,给那些在官网刷票的人带来了很多的不便。从2011年未12306上线起,连续几年回家我都是靠网上购票,今年也不例外;我记得11年时我使用的是官网直接购票,到了12年则使用了新出的木鱼抢票助手,而今年我用了360与猎豹两款主流抢票浏览器,还发动了几位朋友一起帮忙,才买到了一张...

LzwGlory的专栏 1113

snownlp:自定义训练样本与模型保存

本文介绍了snownlp包的情感分析模型训练、保存以及如何使用自己训练的模型,从文件结构、源码设置等角度进行了描述。按照此方法,可以轻松玩转snownlp的情感分析。

AI数据工厂 1万+
上一篇: 利用Python在互动吧网站自动抢票实战分析!你学废了吗
下一篇: Python简单实现爬取快递物流实时信息!到了及时提醒!
pythonlaodi
博客等级 码龄6年 286粉丝 244原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值