2021/5/22爬虫第十五次课(自动获取12306订单)

该博客详细介绍了如何利用Python的Selenium库爬取12306网站的火车票信息,并实现预定功能。首先,通过读取stations.csv文件获取车站代码,然后进行登录、设置出发地、目的地和日期,查询车次。在解析查询结果时,遇到StaleElementReferenceException异常,通过解决方案避免了该问题。最后,根据车次和席别选择,确认乘客信息并提交订单。

经验总结:

  1. 字典的操作不太了解
  2. 老师的代码没有真正理解,就去码了,导致中途一度停止
  3. 运行前,保证代码没有明显错误(没有红线等)
  4. 特别注意有许多缩进的地方,(for try if)
  5. 一开始码的时候,分析页面(具体步骤) 一定要明确
  • 预定车票的标准:根据车次,然后是否是二等或一等(二等优先级高)
  • 选择席别的标准:二等或一等(二等优先级高)

selenium定位时 (属性 元素)
显式等待那里EC的方法 (url 属性值 元素)

完整代码:

#爬取12306订单
import csv
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
#驱动器须定义在类的外面,因为python的垃圾回收机制
driver=webdriver.Chrome()

class spider(object):

    def __init__(self,from_station,to_station,travel_date,train_rank,passengers):#train_rank={'G106':['M','O']}
        self.login_url='https://kyfw.12306.cn/otn/resources/login.html'
        self.personer_url='https://kyfw.12306.cn/otn/view/index.html'
        self.spider_url='https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
        self.confirm_url='https://kyfw.12306.cn/otn/confirmPassenger/initDc'
        self.to_station=to_station
        self.from_station=from_station
        self.travel_date=travel_date
        self.travel_rank=train_rank
        self.passengers=passengers
        self.reader_dict={}
        self.__init__csv()#一开始码的时候,这行代码没写
        self.number=None
        #需要在整个class中调用的属性,先在这里声明

     #初始化城市代号
    def __init__csv(self):
        with open('stations.csv','r',encoding='utf-8') as file_obj:
            readers=csv.DictReader(file_obj)
            for reader in readers:
                name=reader['name']
                code=reader['code']
                self.reader_dict[name]=code

    #登录
    def login(self):
        driver.get(self.login_url)

        WebDriverWait(driver,100).until(
            EC.url_contains(self.personer_url)
        )
        print('登录成功!')


    def spider_analyse(self):
        driver.get(self.spider_url)
        driver.implicitly_wait(3)
        driver.find_element_by_id('gb_closeDefaultWarningWindowDialog_id').click()

        #设置出发地
        fromTag=driver.find_element_by_id('fromStation')
        code=self.reader_dict[self.from_station]
        driver.execute_script('arguments[0].value="%s"'%code,fromTag)
        #设置目的地
        toTag = driver.find_element_by_id('toStation')
        code = self.reader_dict[self.to_station]
        driver.execute_script('arguments[0].value="%s"' % code, toTag)
        #设置日期
        date=driver.find_element_by_id('train_date')
        driver.execute_script('arguments[0].value="%s"' % self.travel_date, date)
        #点击查询
        time.sleep(3)
        query=driver.find_element_by_xpath('//*[@id="query_ticket"]')
        driver.execute_script('arguments[0].click()',query)

        WebDriverWait(driver,10).until(
            EC.presence_of_element_located((By.XPATH,'//tbody[@id="queryLeftTable"]/tr'))
        )
        trains_list=driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')#定位属性不是datatran的tr标签
        is_searched=False
        for i in trains_list:
            try:
                train_list=i.text.replace('\n',' ').split(' ')
                # print(train_list)
                # print('*'*20)
                num=train_list[0]

                if num in self.travel_rank:#判断车次是否在self.travel_rank中
                    # for rank in self.travel_rank[num]:
                    #     if rank=='O':
                    #         pd=train_list[10]
                    #         if pd =='有' or pd.isdigit():
                    #                 is_searched=True
                    #                 break
                    #     if rank=='M':
                    #         pd=train_list[9]
                    #         if pd =='有' or pd.isdigit():
                    #             is_searched=True
                    #             break
                    #关键就是这里的解析部分,代码出错集中在这里
                    pd1=train_list[10]
                    pd2=train_list[9]
                    if pd1=='有' or pd1.isdigit() or pd2=='有' or pd2.isdigit():
                        is_searched=True

                    if is_searched:
                        time.sleep(2)
                        self.number=num
                        order_btn = i.find_element_by_xpath('//*[@id="ticket_5l0000G106B2_01_10"]/td[13]/a')
                        order_btn.click()
            except:
                pass

    def confirm_information(self):
        WebDriverWait(driver,100).until(
            EC.url_contains(self.confirm_url)
        )

        #确认乘客
        labels=driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
        for label in labels:
            name=label.text
            if name in self.passengers:
                label.click()

        #确认席别
        select=Select(driver.find_element_by_id('seatType_1'))
        for i in self.travel_rank[self.number]:
            try:
                select.select_by_value(i)
            except NoSuchElementException:#可能select.select_by_value(i)找不到
                continue
            else:
                break
        submit_btn = driver.find_element_by_xpath('//*[@id="submitOrder_id"]')
        submit_btn.click()

    # 封装了基本的功能
    def run(self):
        # 登录
        self.login()
        # 车次以及余票查询并解析
        self.spider_analyse()
        # 确认乘客信息
        self.confirm_information()



def main():
    result=spider('上海','北京','2021-05-24',{'G106':['O','M']},['name1','name2'])
    result.run()


if __name__ == '__main__':
    main()

方法(细节)总结:
1.

driver.execute_script(script, *args)#调用js方法,同时执行javascript脚本

运用场景:

  • 拖动拖动条
  • (‘https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc’)页面中 设置出发地、日期、查询按钮

报错解决

trains_list=driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')#定位属性不是datatran的tr标签
        print(trains_list)
        is_searched=False
        for i in trains_list:

                train_list=i.text.replace('\n',' ').split(' ')

在这里插入图片描述
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
问题及解决:
https://www.cnblogs.com/poloyy/p/12772046.html
https://blog.youkuaiyun.com/seanyang_/article/details/106603322

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笔记本IT

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值