2021/5/20爬虫第十四次课(selenium页面等待,打开多窗口)

一、页面等待

现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。为了解决这个问题。所以 Selenium 提供了两种等待方式:一种是隐式等待、一种是显式等待

为什么要等?
1 selenium比较慢 网站打开了 元素没有加载出来
2 有些数据是通过ajax加载的。加载需要时间

如何解决?
1 time.sleep() 靠谱 Python提供的
2 selenium也提供了页面等待的方式

  • 隐式等待:调用driver.implicitly_wait。
  • 显式等待:
    显示等待是表明某个条件成立后才执行获取元素的操作。也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就抛出一个异常。显示等待应该使用selenium.webdriver.support.excepted_conditions期望的条件和selenium.webdriver.support.ui.WebDriverWait来配合完成
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()

# 隐式等待
# driver.get('https://www.baidu.com/')
# time.sleep(2) # 我们一定要等2秒吧
# driver.implicitly_wait(10)  # 隐式等待 只要找到元素就立即执行
# driver.find_element_by_id('kwwww').send_keys('高合')

# 显示等待 gb_closeDefaultWarningWindowDialog_id
driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')
driver.implicitly_wait(3)
# 千万不要忘记click() 这一步是去掉那个提示框
driver.find_element_by_id('gb_closeDefaultWarningWindowDialog_id').click()

# 等待出发地加载出来
WebDriverWait(driver,1000).until(
    EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),'北京')
)

# 等待目的地加载出啦
WebDriverWait(driver,1000).until(
    EC.text_to_be_present_in_element_value((By.ID,'toStationText'),'长沙')
)

btn = driver.find_element_by_id('query_ticket')
# 按钮不能够被点击,注意这时应这么做
driver.execute_script('arguments[0].click()',btn)

总结
一些其他的等待条件
• presence_of_element_located:某个元素已经加载完毕了。
• presence_of_all_elements_located:网页中所有满足条件的元素都加载完毕了。
• element_to_be_clickable:某个元素是可以点击了。
更多条件请参考:http://selenium-python.readthedocs.io/waits.html

显式等待的模板
WebDriverWait(driver,1000).until(
    EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),'北京')
)# 查询按钮不能够被点击
driver.execute_script('arguments[0].click()',btn)

解剖隐式等待与显式等待的区别:
隐式等待:

driver.implicitly_wait(10)  # 隐式等待 只要找到元素就立即执行
driver.find_element_by_id('kw').send_keys('高合')  #B

(翻译)wait until B(找到标签并输入值)且 最多找10秒,若over 10s 则报错
显式等待:

WebDriverWait(driver,10).until(
    EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),'北京') #A
)

driver.execute_script('arguments[0].click()',btn)  #B

(翻译)wait until A (判断某个元素中的value属性是否包含了预期的字符串)且 最多找10秒,若over 10s 则报错,若是,则执行B

二、打开多窗口和切换页面

有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。selenium提供了一个叫做switch_to_window来进行切换,具体切换到哪个页面,可以从driver.window_handles中找到

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')  #1

# driver.get('https://www.douban.com/')
# 单纯的打开了另一个窗口
driver.execute_script('window.open("https://www.douban.com/")')  #2
time.sleep(1)

# driver.close()  #关闭的是第一个页面
# driver.find_element_by_id('kw').send_keys('brkalsy')   #操作的是百度
# print(driver.current_url) # https://www.baidu.com/
driver.switch_to_window(driver.window_handles[1])
# driver.switch_to.window(driver.window_handles[1])
time.sleep(1)
print(driver.current_url)

三、案例(获取12306购票订单)

问题:获取12306购票订单

案例的学习目标 : 1 通过这个案例来自测一下目前自己的一个真实的水平 2 练习我们最近学习的知识点selenium 3 如何通过selenium抓取ajax数据

具体步骤(分析网页,选择合适的技术点)
1 登录 2 车次以及余票查询 3 解析车次列表 4 确认乘客信息及席别 5 核对信息

本次只码到登录成功

from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()

# 面向对象来实现
# 类是一个创建对象的对象 希望必须做一些事情 不做这个类就创建不成功
class TrainSpider(object):
    login_url = 'https://kyfw.12306.cn/otn/resources/login.html' # 登录的url
    personal_url = 'https://kyfw.12306.cn/otn/view/index.html' # 个人中心的url

    def __init__(self,from_station,to_station,train_data):
        self.from_station = from_station
        self.to_station = to_station
        self.train_data = train_data

    def login(self):
        driver.get(self.login_url)

        # 登录也是一个耗时的操作  本次采用手机扫码登录
        WebDriverWait(driver, 1000).until(
            EC.url_contains(self.personal_url)
        )

        print('登录成功!')



    # 封装了我们基本的功能
    def run(self):
        # 登录
        self.login()


def main():
    spider = TrainSpider('北京','长沙','2021-05-19')# 日期格式需要注意2021-05-19
    spider.run()
    
if __name__ == '__main__':
    main()

四、类知识点回顾

class A:
    # 类属性 直接在类中定义的属性就是类属性
    # 类属性可以通过类或类的实例来访问,无法通过实例对象来修改
    count = 3

    def __init__(self):
        # 实例属性,通过实例对象添加的属性都是实例属性
        # 实例属性 只能通过实例对象来访问和修改,类对象无法访问和修改
        self.name = '葫芦娃'


    # 实例方法
    # 在类中定义,以self为第一个参数的方法都是实例方法
    # 通过实例对象来调用,会自动将当期对象作为self传入 a.test()
    # 当通过类对象来调用,不会自动传递self。此时我们必须手动传递self
    def test(self):
        print('我是实例方法....')

    # 类方法
    # 在类的内容部 使用@classmethod 来修饰的方法就是类方法
    # 类方法的第一个参数是cls 也会被自动传递 cls就是当前的类对象
    # 类方法可以通过类来调用也可以通过类的实例来调用,没有区别
    @classmethod
    def test2(cls):
        print('我是类方法....')

a = A()
# a.count = 100 # 实例属性 注意:当使用实例对象对类方法进行赋值时,a这个实例对象也拥有的实例属性count  
A.count = 1
print('A',A.count)
print('a',a.count)
# print('a',a.name)
# print('A',A.name) # AttributeError: type object 'A' has no attribute 'name'

# a.test() 等价于 A.test(a)
# a.test()
# A.test(a)

# A.test2() 等价于 a.test2()
# A.test2()
# a.test2()

技巧:记忆类属性、类方法、实例属性、实例方法:分别可以被谁调用与修改

五、补充小知识点

遇到 type=“hidden” 的标签:是不能send_keys 的
在这里插入图片描述
爬取数据(包括解析)

  • selenium爬取数据
  • selenium中的page_source+(三个方法)
  • requests+(三个方法)
    其中(三个方法 指正则、xpath、bs4)

输入信息的方式:

  1. send_keys类
  2. 下拉框
  3. 执行js

input标签的特殊所在:(无</>)
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笔记本IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值