selenium用法详解【从入门到实战】【Python爬虫】【篇二】

网友投稿 983 2022-05-28

键盘控制

webdriver 中 Keys 类几乎提供了键盘上的所有按键方法,我们可以使用 send_keys + Keys 实现输出键盘上的组合按键如 “Ctrl + C”、“Ctrl + V” 等。

from selenium.webdriver.common.keys import Keys # 定位输入框并输入文本 driver.find_element_by_id('xxx').send_keys('Dream丶killer') # 模拟回车键进行跳转(输入内容后) driver.find_element_by_id('xxx').send_keys(Keys.ENTER) # 使用 Backspace 来删除一个字符 driver.find_element_by_id('xxx').send_keys(Keys.BACK_SPACE) # Ctrl + A 全选输入框中内容 driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'a') # Ctrl + C 复制输入框中内容 driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'c') # Ctrl + V 粘贴输入框中内容 driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'v')

其他常见键盘操作:

设置元素等待

很多页面都使用 ajax 技术,页面的元素不是同时被加载出来的,为了防止定位这些尚在加载的元素报错,可以设置元素等来增加脚本的稳定性。webdriver 中的等待分为 显式等待 和 隐式等待。

显式等待

显式等待:设置一个超时时间,每个一段时间就去检测一次该元素是否存在,如果存在则执行后续内容,如果超过最大时间(超时时间)则抛出超时异常(TimeoutException)。显示等待需要使用 WebDriverWait,同时配合 until 或 not until 。下面详细讲解一下。

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)

driver:浏览器驱动

timeout:超时时间,单位秒

poll_frequency:每次检测的间隔时间,默认为0.5秒

ignored_exceptions:指定忽略的异常,如果在调用 until 或 until_not 的过程中抛出指定忽略的异常,则不中断代码,默认忽略的只有 NoSuchElementException 。

until(method, message=’ ‘)

until_not(method, message=’ ')

method:指定预期条件的判断方法,在等待期间,每隔一段时间调用该方法,判断元素是否存在,直到元素出现。until_not 正好相反,当元素消失或指定条件不成立,则继续执行后续代码

message: 如果超时,抛出 TimeoutException ,并显示 message 中的内容

method 中的预期条件判断方法是由 expected_conditions 提供,下面列举常用方法。

先定义一个定位器

from selenium.webdriver.common.by import By from selenium import webdriver driver = webdriver.Chrome() locator = (By.ID, 'kw') element = driver.find_element_by_id('kw')

下面写一个简单的例子,这里定位一个页面不存在的元素,抛出的异常信息正是我们指定的内容。

from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Chrome() element = WebDriverWait(driver, 5, 0.5).until( EC.presence_of_element_located((By.ID, 'kw')), message='超时啦!')

隐式等待

隐式等待也是指定一个超时时间,如果超出这个时间指定元素还没有被加载出来,就会抛出 NoSuchElementException 异常。

除了抛出的异常不同外,还有一点,

隐式等待是全局性的,即运行过程中,如果元素可以定位到,它不会影响代码运行,但如果定位不到,则它会以轮询的方式不断地访问元素直到元素被找到,若超过指定时间,则抛出异常

使用 implicitly_wait() 来实现隐式等待,使用难度相对于显式等待要简单很多。

示例:打开个人主页,设置一个隐式等待时间 5s,通过 id 定位一个不存在的元素,最后打印 抛出的异常 与 运行时间。

from selenium import webdriver from time import time driver = webdriver.Chrome() driver.get('https://blog.csdn.net/qq_43965708') start = time() driver.implicitly_wait(5) try: driver.find_element_by_id('kw') except Exception as e: print(e) print(f'耗时:{time()-start}')

代码运行到 driver.find_element_by_id('kw') 这句之后触发隐式等待,在轮询检查 5s 后仍然没有定位到元素,抛出异常。

selenium用法详解【从入门到实战】【Python爬虫】【篇二】

强制等待

使用 time.sleep() 强制等待,设置固定的休眠时间,对于代码的运行效率会有影响。以上面的例子作为参照,将 隐式等待 改为 强制等待。

from selenium import webdriver from time import time, sleep driver = webdriver.Chrome() driver.get('https://blog.csdn.net/qq_43965708') start = time() sleep(5) try: driver.find_element_by_id('kw') except Exception as e: print(e) print(f'耗时:{time()-start}')

值得一提的是,对于定位不到元素的时候,从耗时方面隐式等待和强制等待没什么区别。但如果元素经过 2s 后被加载出来,这时隐式等待就会继续执行下面的代码,但 sleep还要继续等待 3s。

定位一组元素

上篇讲述了定位一个元素的 8 种方法,定位一组元素使用的方法只需要将 element 改为 elements 即可,它的使用场景一般是为了批量操作元素。

find_elements_by_id()

find_elements_by_name()

find_elements_by_class_name()

find_elements_by_tag_name()

find_elements_by_xpath()

find_elements_by_css_selector()

find_elements_by_link_text()

find_elements_by_partial_link_text()

这里以 CSDN 首页的一个 博客专家栏 为例。

下面使用 find_elements_by_xpath 来定位三位专家的名称。

这是专家名称部分的页面代码,不知各位有没有想到如何通过 xpath 定位这一组专家的名称呢?

from selenium import webdriver # 设置无头浏览器 option = webdriver.ChromeOptions() option.add_argument('--headless') driver = webdriver.Chrome(options=option) driver.get('https://blog.csdn.net/') p_list = driver.find_elements_by_xpath("//p[@class='name']") name = [p.text for p in p_list] name

切换操作

窗口切换

在 selenium 操作页面的时候,可能会因为点击某个链接而跳转到一个新的页面(打开了一个新标签页),这时候 selenium 实际还是处于上一个页面的,需要我们进行切换才能够定位最新页面上的元素。

窗口切换需要使用 switch_to.windows() 方法。

首先我们先看看下面的代码。

代码流程:先进入 【CSDN首页】,保存当前页面的句柄,然后再点击左侧 【CSDN官方博客】跳转进入新的标签页,再次保存页面的句柄,我们验证一下 selenium 会不会自动定位到新打开的窗口。

from selenium import webdriver handles = [] driver = webdriver.Chrome() driver.get('https://blog.csdn.net/') # 设置隐式等待 driver.implicitly_wait(3) # 获取当前窗口的句柄 handles.append(driver.current_window_handle) # 点击 python,进入分类页面 driver.find_element_by_xpath('//*[@id="mainContent"]/aside/div[1]/div').click() # 获取当前窗口的句柄 handles.append(driver.current_window_handle) print(handles) # 获取当前所有窗口的句柄 print(driver.window_handles)

可以看到第一个列表 handle 是相同的,说明 selenium 实际操作的还是 CSDN首页 ,并未切换到新页面。

下面使用 switch_to.windows() 进行切换。

from selenium import webdriver handles = [] driver = webdriver.Chrome() driver.get('https://blog.csdn.net/') # 设置隐式等待 driver.implicitly_wait(3) # 获取当前窗口的句柄 handles.append(driver.current_window_handle) # 点击 python,进入分类页面 driver.find_element_by_xpath('//*[@id="mainContent"]/aside/div[1]/div').click() # 切换窗口 driver.switch_to.window(driver.window_handles[-1]) # 获取当前窗口的句柄 handles.append(driver.current_window_handle) print(handles) print(driver.window_handles)

上面代码在点击跳转后,使用 switch_to 切换窗口,window_handles 返回的 handle 列表是按照页面出现时间进行排序的,最新打开的页面肯定是最后一个,这样用 driver.window_handles[-1] + switch_to 即可跳转到最新打开的页面了。

那如果打开的窗口有多个,如何跳转到之前打开的窗口,如果确实有这个需求,那么打开窗口是就需要记录每一个窗口的 key(别名) 与 value(handle),保存到字典中,后续根据 key 来取 handle 。

表单切换

很多页面也会用带 frame/iframe 表单嵌套,对于这种内嵌的页面 selenium 是无法直接定位的,需要使用 switch_to.frame() 方法将当前操作的对象切换成 frame/iframe 内嵌的页面。

switch_to.frame() 默认可以用的 id 或 name 属性直接定位,但如果 iframe 没有 id 或 name ,这时就需要使用 xpath 进行定位。下面先写一个包含 iframe 的页面做测试用。

现在我们定位红框中的 CSDN 按钮,可以跳转到 CSDN 首页。

from selenium import webdriver from pathlib import Path driver = webdriver.Chrome() # 读取本地html文件 driver.get('file:///' + str(Path(Path.cwd(), 'iframe测试.html'))) # 1.通过id定位 driver.switch_to.frame('CSDN_info') # 2.通过name定位 # driver.switch_to.frame('Dream丶Killer') # 通过xpath定位 # 3.iframe_label = driver.find_element_by_xpath('/html/body/iframe') # driver.switch_to.frame(iframe_label) driver.find_element_by_xpath('//*[@id="csdn-toolbar"]/div/div/div[1]/div/a/img').click()

这里列举了三种定位方式,都可以定位 iframe 。

Python Selenium

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:200_mysql_innodb_1_ Row_Format _page_聚簇_二级索引
下一篇:关系型数据库vs非关系型数据库
相关文章