• Python + selenium + requests实现12306全自动抢票,验证码破解加自动点击!!!(转自https://blog.csdn.net/jay_wonder/article/details/82529973 )


    Python + selenium + requests实现12306全自动抢票,验证码破解加自动点击!!!!!

    测试结果: 
    这里写图片描述

    整个买票流程可以再快一点,不过为了稳定起见,有些地方等待了一些时间

    完整程序,拿去可用 
    整个程序分了三个模块:购票模块(主体)、验证码识别模块、余票查询模块 
    购票模块:

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, ElementNotVisibleException
    import time
    import requests
    from urllib.parse import urlencode
    from pyquery import PyQuery as pq
    from check_ticket import Check
    from verify import Code
    import json

    class Buy_Ticket():
    def __init__(self, start_station, end_station, date, username, password, purpose):
    self.num = 1
    self.start = start_station
    self.end = end_station
    self.date = date
    self.username = username
    self.password = password
    self.purpose = purpose
    self.login_url = 'https://kyfw.12306.cn/otn/login/init'
    self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'

    def login(self):
    browser.get(self.login_url)
    try:
    input_name = browser.find_element_by_id('username')
    input_pd = browser.find_element_by_id('password')
    button = browser.find_element_by_id('loginSub')
    time.sleep(1)
    input_name.send_keys(self.username)
    input_pd.send_keys(self.password)
    c = Code(browser) #调用验证码识别模块
    c.main()
    button.click()
    time.sleep(2)
    #等待页面跳转,如果验证码识别错误,就执行下面的while语句
    while browser.current_url == self.login_url + '#':
    c = Code(browser)
    c.main()
    button.click()
    time.sleep(2)
    #self.get_passenger()
    self.check()
    except NoSuchElementException:
    self.login()

    def check(self):
    #调用余票查询模块
    check = Check(self.date, self.start, self.end, self.purpose)
    start_end = check.look_up_station()
    self.num = check.get_info()
    #cookie的添加,json.dumps把以汉字形式呈现的起始、终点站转化成unicode编码,可在审查元素里查看cookie
    browser.add_cookie({'name':'_jc_save_fromStation', 'value':json.dumps(self.start).strip('"').replace('\', '%') + '%2C' + start_end[0]})
    browser.add_cookie({'name':'_jc_save_toStation', 'value':json.dumps(self.end).strip('"').replace('\', '%') + '%2C' + start_end[1]})
    browser.add_cookie({'name':'_jc_save_fromDate', 'value':self.date})
    browser.get(self.ticket_url)
    if self.purpose == '学生':
    btn = browser.find_element_by_id('sf2')
    time.sleep(1)
    btn.click()
    button = browser.find_element_by_id('query_ticket')
    time.sleep(1)
    button.click()

    def book_ticket(self):
    print('开始预订车票...')
    #先查找出所有车次对应的预订按钮,再根据余票查询模块返回的车次序号,点击相应的预订按钮
    button = browser.find_elements_by_class_name('btn72')
    button[self.num-1].click()
    time.sleep(3)
    button2 = browser.find_element_by_id('normalPassenger_0') #按实际情况,可自行修改,这里就选择的第一个常用联系人,
    #第二个是normalPassenger_1,依此类推
    button2.click()
    button3 = browser.find_element_by_id('submitOrder_id')
    time.sleep(1)
    button3.click()
    time.sleep(3) #等待页面加载完毕,不然后面可能会报错,等待时间自行决定
    try:
    button4 = browser.find_element_by_id('qr_submit_id')
    button4.click()
    except ElementNotVisibleException:
    button4 = browser.find_element_by_id('qr_submit_id')
    button4.click()
    print('车票预定成功!请在30分钟内完成付款!')

    def main(self):
    self.login()
    self.book_ticket()

    if __name__ == '__main__':
    begin = time.time()
    browser = webdriver.Chrome()
    b = Buy_Ticket('上海', '重庆', '2018-09-18', '账号', '密码', 'ADULT') #账号、密码自行修改
    b.main()
    end = time.time()
    print('总耗时:%d秒' % int(end-begin))
    #browser.close()
    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
    验证码识别模块:

    import requests
    from PIL import Image
    from selenium.webdriver import ActionChains
    import time
    from io import BytesIO

    class Code():
    def __init__(self, browser):
    self.browser = browser
    self.verify_url = 'http://littlebigluo.qicp.net:47720/' #验证码识别网址,返回识别结果

    #确定验证码的位置
    def get_position(self):
    time.sleep(3)
    element = self.browser.find_element_by_class_name('touclick-img-par')
    time.sleep(2)
    location = element.location
    size = element.size
    position= (location['x'], location['y'], location['x'] + size['width'], location['y'] + size['height'])
    return position

    #截取整个网页页面
    def get_screenshot(self):
    screenshot = self.browser.get_screenshot_as_png()
    screenshot = Image.open(BytesIO(screenshot))
    return screenshot

    #从截取的网页,裁剪出验证码图片,并保存到本地
    def get_touclick_img(self, name = 'captcha.png'):
    position = self.get_position()
    print('验证码的位置:', position)
    screenshot = self.get_screenshot()
    captcha = screenshot.crop(position)
    captcha.save('captcha.png')

    #验证码解析
    def parse_img(self):
    files = {'file': open('captcha.png', 'rb')} #打开保存到本地的验证码图片
    response = requests.post(self.verify_url, files=files)
    num = response.text.split('<B>')[1].split('<')[0]
    print('验证码识别成功!图片位置:%s' % num)
    try:
    if int(num):
    return [int(num)]
    except ValueError:
    num = list(map(int,num.split()))
    return num

    #识别结果num都以列表形式返回,方便后续验证码的点击

    #实现验证码自动点击
    def move(self):
    num = self.parse_img()
    try:
    element = self.browser.find_element_by_class_name('touclick-img-par')
    for i in num:
    if i <= 4:
    ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),73).click().perform()
    else :
    i -= 4
    ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),145).click().perform()
    except:
    print('元素不可选!')

    def main(self):
    self.get_touclick_img()
    self.move()
    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
    余票查询模块:

    import requests
    from urllib.parse import urlencode

    class Check():
    def __init__(self, date, start, end, purpose):
    self.base_url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?'
    self.url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9018'
    self.date = date
    self.start_station = start
    self.end_station = end
    if purpose == '学生':
    self.purpose = '0X00'
    else:
    self.purpose = purpose

    #查找出车站的英文简称,用于构造cookie、完整的余票查询链接
    def look_up_station(self):
    response1 = requests.get(self.url)
    a = response1.text.split('@')
    a.pop(0)
    for each in a:
    i = each.split('|')
    if self.start_station == i[1]:
    self.start_station = i[2]
    elif self.end_station == i[1]:
    self.end_station = i[2]
    return [self.start_station, self.end_station]

    def get_info(self):
    start_end = self.look_up_station()
    #构造请求参数
    data = {
    'leftTicketDTO.train_date':self.date,
    'leftTicketDTO.from_station':start_end[0],
    'leftTicketDTO.to_station':start_end[1],
    'purpose_codes':self.purpose
    }
    url = self.base_url + urlencode(data)
    response = requests.get(url)
    json = response.json()
    maps = json['data']['map']
    count = 0 #用于对车次编号
    for each in json['data']['result']:
    count += 1
    s = each.split('|')[3:]
    info = {
    'train':s[0],
    'start_end':maps[s[3]] + '-' + maps[s[4]],
    'time':s[5] + '-' + s[6],
    '历时':s[7],
    '一等座':s[-5],
    '二等座':s[-6]
    }
    try:
    #余票的结果有3种:有、一个具体的数字(如:18、6等)、无,判断如果余票是有或者一个具体的数字就直接输出对应的车次信息,然后返回
    if info['二等座'] == '有' or int(info['二等座']):
    print('[%d]' % count, info)
    return count
    except ValueError:
    continue

    曾经梦想仗剑走天涯,然而bug太多,没时间去
  • 相关阅读:
    NoSQL学习1
    inno setup 软件打包
    cmapx 保存绘制好的图层
    qt之菜单栏的创建
    qt 软件打包
    可恶的 0xc0000005异常
    成长
    msChart组件安装与编程
    qt 工具下的dump工具导出文档出现异常解决方案
    qt 环境下mapx组件的鼠标跟踪
  • 原文地址:https://www.cnblogs.com/wulilou/p/10280456.html
Copyright © 2020-2023  润新知