爬虫之Selenium的等待及定位

2019-09-20 14:38:59 浏览数 (1)

爬虫之Selenium的等待及定位

0.导语

1.selenium的三种等待方式

1.1 强制等待

1.2 隐性等待

1.3 显性等待

2. selenium之定位以及切换frame

2.1 切frame操作

2.2 切回主文档

2.3 嵌套frame的操作

2.4 总结

3.学习文章

0.导语

关于昨天的机器学习文章,希望能够亲自码一下,将会学到很多东西,如果觉得很好,欢迎转发,谢谢! 有关翻译贡献,可点击公众号右下角联系我,备注:翻译,或者昨日文章的阅读原文,pr到仓库中来! 关于今天的爬虫文章,则是一篇之前练习爬虫碰到的问题解决策略,希望可以帮助大家,下面一起来看吧,欢迎留言与转发!

1.selenium的三种等待方式

Selenium自动化处理时,这个下拉框定位不到、那个弹出框定位不到…各种定位不到,其实大多数情况下就是两种问题:1 有frame,2 没有加等待。浏览器的加载速度太慢。代码速度太快。这就造成了定位不准确的问题。

1.1 强制等待

代码语言:javascript复制
# -*- coding: utf-8 -*-
from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get('https://light-city.me')

sleep(3)  # 强制等待3秒再执行下一步

print driver.current_url
driver.quit()

这种叫强制等待,不管浏览器是否加载完毕,程序都得等待3秒。3秒后,程序继续执行。

1.2 隐性等待

第二种办法叫隐形等待,implicitly_wait(xx),隐形等待表示代码给浏览器等待设定一个最长时间,不管代码速度多块,都要等浏览器xx秒,如果浏览器这段时间内来了,则两个同步运行,否则,如果浏览器在规定时间内没到,则代码继续运行,接着抛出异常。

代码语言:javascript复制
# -*- coding: utf-8 -*-
from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(30)  # 隐性等待,最长等30秒
driver.get('https://light-city.me')

print driver.current_url
driver.quit()

隐形等待是设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截至,然后执行下一步。弊端:程序会一直等待整个页面加载完成,也就是一般情况下看到的浏览器标签栏小圈不转,才执行下一步。如果想等到我要的元素出来直接进入下一步,就需要用显示等待了。

隐性等待对整个driver的周期都起作用,所以只要设置一次即可,整个跟sleep不一样,不能多次使用。

1.3 显性等待

第三种办法就是显性等待,WebDriverWait,配合该类的until()until_not()方法。显性等待表示程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过了设置的最长时间,然后抛出TimeoutException。

代码语言:javascript复制
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.implicitly_wait(10)  # 隐性等待和显性等待可以同时用,但要注意:等待的最长时间取两者之中的大者
driver.get('https://xxxx.com')
locator = (By.LINK_TEXT, 'xxx') # 用By类定位

try:
    WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator))
    print driver.find_element_by_link_text('xxx').get_attribute('href')
finally:
    driver.close()

selenium.webdriver.common.by.By支持的定位器分类

代码语言:javascript复制
CLASS_NAME = 'class name'
CSS_SELECTOR = 'css selector'
ID = 'id'
LINK_TEXT = 'link text'
NAME = 'name'
PARTIAL_LINK_TEXT = 'partial link text'
TAG_NAME = 'tag name'
XPATH = 'xpath'

expected_conditions

代码语言:javascript复制
selenium.webdriver.support.expected_conditions(模块)

WebDriverWait参数与方法

代码语言:javascript复制
selenium.webdriver.support.wait.WebDriverWait(类)
__init__
    driver: 传入WebDriver实例,即我们上例中的driver
    timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
    poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
    ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常,
    则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException。
until
    method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
    message: 如果超时,抛出TimeoutException,将message传入异常
until_not 与until相反,until是当某元素出现或什么条件成立则继续执行,until_not是当某元素消失或什么条件不成立则继续执行,参数也相同,不再赘述。

调用方法

代码语言:javascript复制
WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)

这里需要特别注意的是until或until_not中的可执行方法method参数,很多人传入了WebElement对象,如下:

代码语言:javascript复制
WebDriverWait(driver, 10).until(driver.find_element_by_id('kw'))  # 错误

在这里,可以用selenium提供的 expected_conditions 模块中的各种条件,也可以用WebElement的 is_displayed()is_enabled()is_selected() 方法,或者用自己封装的方法都可以。

2. selenium之定位以及切换frame

frameset不用切,frame需层层切!

frame标签有frameset、frame、iframe三种,frameset跟其他普通标签没有区别,不会影响到正常的定位,而frame与iframe对selenium定位而言是一样的,selenium有一组方法对frame进行操作。

2.1 切frame操作

switch_to.frame()

代码语言:javascript复制
from selenium import webdriver
driver = webdriver.Firefox()
driver.switch_to.frame(0)  # 1.用frame的index来定位,第一个是0
# driver.switch_to.frame("frame1")  # 2.用id来定位
# driver.switch_to.frame("myframe")  # 3.用name来定位
# driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))  # 4.用WebElement对象来定位

2.2 切回主文档

switch_to.default_content() 如果想继续操作主文档的元素,则需要切回主文档。

代码语言:javascript复制
driver.switch_to.default_content()

2.3 嵌套frame的操作

代码语言:javascript复制
<html>
    <iframe id="frame1">
        <iframe id="frame2" / >
    </iframe>
</html>

从主文档切到frame2,一层层切进去

代码语言:javascript复制
driver.switch_to.frame("frame1")
driver.switch_to.frame("frame2")

从frame2再切回frame1

代码语言:javascript复制
driver.switch_to.parent_frame()  # 如果当前已是主文档,则无效果

2.4 总结

代码语言:javascript复制
driver.switch_to.frame(reference)
driver.switch_to.parent_frame()
driver.switch_to.default_content()

3.学习文章

(1)Python selenium —— 一定要会用selenium的等待,三种等待方式解读

https://huilansame.github.io/huilansame.github.io/archivers/sleep-implicitlywait-wait

(2)selenium之 定位以及切换frame(iframe)

(https://blog.csdn.net/huilan_same/article/details/52200586)

0 人点赞