使用python+selenium对12306车票数据读取

一、摘要

  突发奇想想读取12306的车票信息,最开始想用requests,但是突然又想试试selenium的无界面浏览器。有部分正则没调好,写好就懒得调了。

  套用我师傅的话就是:我凭本事写的bug,凭什么要改!

二、方案思路

  url = https://kyfw.12306.cn/otn/leftTicket/init

  1、模拟用户是怎么查车票信息、然后通过selenium去操作浏览器。

  2、最后输出字典。

三、源码

#-*- coding:utf-8 -*-
#__anthor__:"Klay Zhu"
#date: 2018/9/7
import re
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
from time import sleep

class TicketQuery:
    """
    查询12306车票
    """
    def __init__(self,**parame):
        try:
            self.obj_driver = parame["browser"]
        except:
            #无界面浏览器
            options = Options()
            options.add_argument(‘-headless‘)  # 无头参数
            self.obj_driver = webdriver.Chrome(executable_path=‘chromedriver‘, chrome_options=options)
        self.str_from_station = parame["fromStation"] #出发地
        self.str_to_station = parame["toStation"]     #目的地
        self.str_train_date = parame["trainDate"]     #出发日

    def waitElement(self,value,way=By.ID):
        """等待忍耐"""
        if WebDriverWait(self.obj_driver, 10).until(expected_conditions.visibility_of_element_located((way,value))):
            return True
    def __jsOperation(self,element_id,value):
        """通过js操作界面元素"""
        if self.waitElement(element_id):
            js_value = ‘document.getElementById("{}").value="{}"‘.format(element_id,value)
            self.obj_driver.execute_script(js_value)
    def __getStation(self,element_id,string):
        """对input选择框进行选择"""
        self.obj_driver.find_element_by_id(element_id).clear()
        self.obj_driver.find_element_by_id(element_id).click()
        self.obj_driver.find_element_by_id(element_id).send_keys(string)
        __a = self.obj_driver.find_elements_by_class_name("ralign")
        for i in __a:
            if i.text == string:
                i.click()
                break
    #正则没调好 懒得调了
    pattern = r"<tr[^<>]*><td[^<>]*>\s*<div[^<>]*><div[^<>]*><div[^<>]*><a[^<>]*>(?P<train_num>[^<>]*)</a>[^<>]*<span[^<>]*></span></div><span[^<>]*><span[^<>]*>[^<>]*</span><b[^<>]*></b></span></div><div[^<>]*><strong[^<>]*>(?P<from_station>[^<>]*)</strong><strong[^<>]*>(?P<to_station>[^<>]*)</strong></div><div[^<>]*><strong[^<>]*>(?P<arrival_time>[^<>]*)</strong><strong[^<>]*>(?P<departure_time>[^<>]*)</strong></div><div[^<>]*><strong[^<>]*>(?P<over_time>[^<>]*)</strong><span[^<>]*>(?P<intraday>[^<>]*)</span></div></div></td><td[^<>]*?>(?P<param1>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param2>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param3>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param4>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param5>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param6>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param7>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param8>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param9>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param10>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>(?P<param11>([^<>]{1,4})|(<div>\d+</div>))</td>\s*<td[^<>]*?>.*?</a></td></tr>"
    __url = r"https://kyfw.12306.cn/otn/leftTicket/init"

    def run(self):
        """执行操作"""
        sleep(2)  # 不等这2秒会出现页面没刷新,数据获取不了的情况
        self.obj_driver.get(self.__url)
        self.obj_driver.maximize_window()
        self.__getStation("fromStationText",self.str_from_station)
        self.__getStation("toStationText",self.str_to_station)
        self.__jsOperation("train_date",self.str_train_date)
        try:
            self.obj_driver.find_element_by_id("a_search_ticket").click()
        except:
            self.obj_driver.find_element_by_id("query_ticket").click()
        sleep(2)  # 不等这2秒会出现页面没刷新,数据获取不了的情况
        html = self.obj_driver.find_element_by_id("queryLeftTable").get_attribute("outerHTML")
        self.obj_driver.close()
        return html

    def outData(self,string = ""):
        if not string:string=self.run()
        obj_rr=re.finditer(self.pattern, string)
        list_data=[]
        if obj_rr:
            for obj_r in obj_rr:
                dict_ticket_info = {
                    "train_num": "",       # 车次
                    "from_station": "",    # 出发站
                    "to_station": "",      # 抵达站
                    "arrival_time": "",    # 到站时间
                    "departure_time": "",  # 离站时间
                    "over_time": "",       # 历经时间
                    "intraday": True,      # 是否当日到达
                    # 车票数据[0]特等座,[1]一等座,[2]二等座,[3]高级软卧,[4]软卧,[5]动卧,[6]硬卧,[7]软座,
                    # [8]硬座,[9]无座,[10]其他,int数据代表剩余票数,Ture代表有票数量未知,False代表没票
                    "data": [],
                }
                dict_ticket_info["train_num"] = obj_r.group("train_num")
                dict_ticket_info["from_station"] = obj_r.group("from_station")
                dict_ticket_info["to_station"] = obj_r.group("to_station")
                dict_ticket_info["arrival_time"] = obj_r.group("arrival_time")
                dict_ticket_info["departure_time"] = obj_r.group("departure_time")
                dict_ticket_info["over_time"] = obj_r.group("over_time")
                if obj_r.group("intraday") == "当日到达":dict_ticket_info["intraday"] = True
                else:dict_ticket_info["intraday"] = False
                for i in range(1,11):
                    str_info = obj_r.group("param" + str(i))
                    obj_r2=re.search(r"<div>(?P<num>\d+)</div>",str_info)
                    if obj_r2:dict_ticket_info["data"].append(obj_r2.group("num"))
                    elif str_info=="有":dict_ticket_info["data"].append(True)
                    else:dict_ticket_info["data"].append(False)
                # print(dict_ticket_info)
                list_data.append(dict_ticket_info)
        return list_data

if __name__ == ‘__main__‘:
    import datetime
    m_time=(datetime.datetime.now()+datetime.timedelta(days=10)).strftime("%Y-%m-%d")
    testdata = {
        "fromStation":"北京",
        "toStation":"上海",
        "trainDate":m_time, #10天后
        # "browser":webdriver.Chrome() #调试用
    }
    data = TicketQuery(**testdata).run()
    print(data)

四、遇到的问题

1、日期输入,因为控件原因不能直接输入,使用JavaScript对元素进行操作。

from selenium import webdriver
driver = webdriver.Chrome()
element_id = "id"  #id
value = "value"    #给该标签设定的值
js_value = ‘document.getElementById("{}").value="{}"‘.format(element_id, value)#拼接成JavaScript代码
driver.execute_script(js_value)

2、input选择框,类似百度搜索这种使用ajax异步出来的数据。

from selenium import webdriver
element_id = "fromStationText"
string = "北京"
driver = webdriver.Chrome()

driver.find_element_by_id(element_id).clear()             # 清除原有的值
driver.find_element_by_id(element_id).click()             # 点击,使输入框获取焦点
driver.find_element_by_id(element_id).send_keys(string)   # 输入值
o_InputSelect=driver.find_elements_by_class_name("ralign")# 获取局部刷新的数据,然后循环比对文字
for i in o_InputSelect:                                   # 注意:如果不用这种方法,用输入回车来选择会出现  要选北京结果选到北京西  这类的
    if i.text == string:
        i.click()
        break

3、使用全局(嵌套)变量dict作为append到局部list里面,幸好出现问题就马上反应过来是深浅拷贝的问题,详情请百度!

class demo:
    dic={
        "name":"",
        "age":"",
        "data":[],
    }
    def f(self):
        lis = []
        for i in range(3):
            print("dic的地址:",id(f.dic))
            self.dic["name"]="name"+str(i)
            self.dic["age"]="age"+str(i)
            self.dic["data"].append(i)
            lis.append(self.dic)
        return lis
if __name__ == ‘__main__‘:
    f = demo()
    print("最后结果:",f.f())
    # dic的地址: 1469349351640
    # dic的地址: 1469349351640
    # dic的地址: 1469349351640
    # 最后结果: [{‘name‘: ‘name2‘, ‘age‘: ‘age2‘, ‘data‘: [0, 1, 2]}, {‘name‘: ‘name2‘, ‘age‘: ‘age2‘, ‘data‘: [0, 1, 2]},
    #        {‘name‘: ‘name2‘, ‘age‘: ‘age2‘, ‘data‘: [0, 1, 2]}]

原文地址:https://www.cnblogs.com/Klay/p/9643946.html

时间: 2024-11-06 03:55:53

使用python+selenium对12306车票数据读取的相关文章

python + selenium -- 读取配置文件内容

任何一个项目,都涉及到了配置文件和管理和读写,python 支持很多配置文件的读写.本文记录使用 python + selenium自动化过程中,学习的使用python自带的ConfigParser类读取ini配置文件的方法. 1.在所在项目新建一个文件夹,如config,在配置文件中新建一个文件,如config.ini 配置文件填写内容如下: 1 [broswer_name] 2 broswer = 'firefox' 3 4 [server] 5 server = 'http://www.b

python openpyxl模块实现excel的读取,新表创建及原数据表追加新数据

当实际工作需要把excel表的数据读取出来,或者把一些统计数据写入excel表中时,一个设计丰富,文档便于寻找的模块就会显得特别的有吸引力,本文对openpyxl模块的一些常见用法做一些记录,方便工作中查询(好记性不如烂笔头) author:he    qq:760863706    python:3.5    date:2018-9-14 1:安装openpyxl pip install openpyxl 1 2:excel表读取数据(.xlsx) import openpyxlfilepat

利用Python将excel数据读取到word表格

在工作中可能需要两者对excel和word进行转化,今天介绍例如Python 将excel转word表格 看图,我需要将这份excel文档转word表格: 思路: 1.创建需要的表格: 2.读取excel文档: 3.将excel文档数据写入word表格对应的位置: 4.循环 需要用到的模块 创建表格,由于我需要的表格需要进行合并处理,所以使用merge合并单元格 接下来,读取excel文档数据 然后,将excel数据写入到已创建的word表格中 至此我们就可以将一条excel数据读取到word表

Python+Selenium实现股票板块数据模拟抓取

selenium 是一个web的自动化测试工具,支持多平台:windows.linux.MAC ,支持多浏览器:ie.ff.safari.opera.chrome,支持多语言:例如C.JAVA.Python等,支持分布式测试用例的执行,可以把测试用例分布到不同的测试机器的执行,相当于分发机的功能. 虽然Selenium本来是应用于自动化测试领域,但是因为Selenium可以实现Web交互操作,所以可以利用Selenium模拟Web抓取一些常规方式不能抓取的数据,例如一些页面生成后才会动态加载的数

WEB自动化(Python+selenium)的API

在做Web自动化过程中,汇总了Python+selenium的API相关方法,给公司里的同事做了第二次培训,分享给大家                                                                                                                     WEB自动化测试培训2 课程目的 一.Webdriver API 的使用 课程内容 1    控制浏览器 Selenium 主要提供的是操作页面上各

Python Selenium Cookie 绕过验证码实现登录

Python Selenium Cookie 绕过验证码实现登录 之前介绍过博客园的通过cookie 绕过验证码实现登录的方法.这里并不多余,会增加分析和另外一种方法实现登录. 1.思路介绍 1.1.直接看代码,内有详细注释说明 # FileName : Wm_Cookie_Login.py # Author : Adil # DateTime : 2018/3/20 19:47 # SoftWare : PyCharm from selenium import webdriver import

java调用Linux执行Python爬虫,并将数据存储到elasticsearch--(环境脚本搭建)

java调用Linux执行Python爬虫,并将数据存储到elasticsearch中 一.以下博客代码使用的开发工具及环境如下: 1.idea: 2.jdk:1.8 3.elasticsearch:5.2.0 4.Linux 5.Python 6.maven 二.maven坐标: <!--java连接ulinix脚本架包--> <dependency> <groupId>ch.ethz.ganymed</groupId> <artifactId>

转 Python Selenium设计模式-POM

前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享,以便大家在实践中对POM的特点.应用场景和核心思想有一定的理解和掌握. 为什么要用POM 基于python selenium2开始UI级自动化测试并不是多么艰巨的任务.只需要定位到元素,执行对应的操作即可.下面我们看一下这个简单的脚本实现百度搜索. from selenium import webdriver import time driver = webdriver.Firefox() driver.i

Python+selenium自动化公共逻辑步骤封装

开篇 个人博客"Python+selenium的GUI自动化实现"提到的chrome与IE浏览器调用插件已上传至51CTO下载,对应链接分别为:chrome,http://down.51cto.com/data/2171584:IE,http://down.51cto.com/data/2171585:有需要的直接下载即可:  正文 关于自动化,其实质就是用机器操作代替手工执行,从而减少人力投入.节约项目运营成功.优秀的自动化框架,可能的一个发展过程,前期自动化用例写作实现过程,可能需