2023年11月25日发(作者:)
python-selenium库详解
python-selenium库详解
Selenium 是⼀个⾃动化测试⼯具,利⽤它可以驱动浏览器执⾏特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页⾯
的源代码,做到可见即可爬。对于⼀些 JavaScript 动态渲染的页⾯来说,此种抓取⽅式⾮常有效。
um库的安装
pip3 install selenium
um库的基本⽤法
1)声明浏览器对象
Selenium ⽀持⾮常多的浏览器,如 Chrome、Firefox、Edge 等,还有 Android、BlackBerry 等⼿机端的浏览器。另外,也⽀持⽆界⾯
浏览器 PhantomJS,我们可以⽤如下⽅式初始化:
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
这样就完成了浏览器对象的初始化并将其赋值为 browser 对象。
2)访问页⾯
可以⽤ get() ⽅法来请求⽹页,参数传⼊链接 URL 即可
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('')
print(browser.page_source)
browser.close()
运⾏后发现,弹出了 Chrome 浏览器并且⾃动访问了淘宝,然后控制台输出了淘宝页⾯的源代码,随后浏览器关闭。
3)查找结点
想要从淘宝页⾯中提取搜索框这个节点,可以发现,它的 id 是 q,name 也是 q
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('')
input_first = browser.find_element_by_id('q')
input_second = browser.find_element_by_css_selector('#q')
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first, input_second, input_third)
browser.close()
运⾏结果
所有获取单个节点的⽅法:
find_element_by_id find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
另外,Selenium 还提供了通⽤⽅法 find_element(),它需要传⼊两个参数:查找⽅式 By 和值。实际上,它就是 find_element_by_id()
这种⽅法的通⽤函数版本,⽐如 find_element_by_id(id) 就等价于 find_element(, id),⼆者得到的结果完全⼀致。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('')
input_first = browser.find_element(By.ID, 'q')
print(input_first)
browser.close()
多个节点
如果查找的⽬标在⽹页中只有⼀个,那么完全可以⽤ find_element() ⽅法。如果要查找所有满⾜条件的节点,需要⽤ 这
find_elements()
样的⽅法。
注意,在这个⽅法的名称中,element 多了⼀个 s。
要查找淘宝左侧导航条的所有条⽬
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('')
lis = browser.find_elements_by_css_selector('.service-bd li')
print(lis)
browser.close()
所有获取多个节点的⽅法:
find_elements_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
我们也可以直接⽤ find_elements() ⽅法来选择
lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')
4)节点交互
Selenium 可以驱动浏览器来执⾏⼀些操作,也就是说可以让浏览器模拟执⾏⼀些动作。⽐较常见的⽤法有:输⼊⽂字时⽤ send_keys ⽅
法,清空⽂字时⽤ clear ⽅法,点击按钮时⽤ click ⽅法。
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get('')
input=browser.find_element_by_id('q')
input.send_keys('iphone')
time.sleep(1)
input.clear()
input.send_keys('ipad')
button=browser.find_element_by_class_name('btn-search')
button.click()
这⾥⾸先驱动浏览器打开淘宝,然后⽤ find_element_by_id() ⽅法获取输⼊框,然后⽤ send_keys() ⽅法输⼊ iPhone ⽂字,等待⼀秒后
⽤ clear() ⽅法清空输⼊框,再次调⽤ send_keys() ⽅法输⼊ iPad ⽂字,之后再⽤ find_element_by_class_name() ⽅法获取搜索按
钮,最后调⽤ click() ⽅法完成搜索动作。
5)动作链
⼀些交互动作都是针对某个节点执⾏的。⽐如,对于输⼊框,我们就调⽤它的输⼊⽂字和清空⽂字⽅法;对于按钮,就调⽤它的点击⽅法。
还有另外⼀些操作,它们没有特定的执⾏对象,⽐如⿏标拖曳、键盘按键等,这些动作⽤另⼀种⽅式来执⾏,那就是动作链。
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = '/try/?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
打开⽹页中的⼀个拖曳实例,然后依次选中要拖曳的节点和拖曳到的⽬标节点,接着声明 ActionChains 对象并将其赋值为 actions 变
量,然后通过调⽤ actions 变量的 drag_and_drop() ⽅法,再调⽤ perform() ⽅法执⾏动作,此时就完成了拖曳操作
6)执⾏ JavaScript
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('/explore')
browser.execute_script('To(0, Height)')
browser.execute_script('alert("To Bottom")')
这⾥就利⽤ execute_script() ⽅法将进度条下拉到最底部,然后弹出 alert 提⽰框。
3.获取节点信息
通过 page_source 属性可以获取⽹页的源代码,接着就可以使⽤解析库(如正则表达式、Beautiful Soup、pyquery 等)来提取信息。
1)获取属性
我们可以使⽤ get_attribute() ⽅法来获取节点的属性,但是其前提是先选中这个节点。
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = '/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class'))
运⾏之后,程序便会驱动浏览器打开知乎页⾯,然后获取知乎的 logo 节点,最后打印出它的 class。
2)获取⽂本值
每个 WebElement 节点都有 text 属性,直接调⽤这个属性就可以得到节点内部的⽂本信息,这相当于 Beautiful Soup 的 get_text() ⽅
法、pyquery 的 text() ⽅法。
from selenium import webdriver
browser = webdriver.Chrome()
url = '/explore'
browser.get(url)
input = browser.find_element_by_class_name('ExploreSpecialCard-title')
print(input.text)
运⾏结果
科⽐意外离世,你对他有哪些回忆?
3)获取 ID、位置、标签名、⼤⼩
from selenium import webdriver
browser = webdriver.Chrome()
url = '/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)
这⾥⾸先获得 “提问” 按钮这个节点,然后调⽤其 id、location、tag_name、size 属性来获取对应的属性值。
4.切换 Frame
⽹页中有⼀种节点叫作 iframe,也就是⼦ Frame,相当于页⾯的⼦页⾯,它的结构和外部⽹页的结构完全⼀致。Selenium 打开页⾯后,
它默认是在⽗级 Frame ⾥⾯操作,⽽此时如果页⾯中还有⼦ Frame,它是不能获取到⼦ Frame ⾥⾯的节点的。这时就需要使⽤
switch_() ⽅法来切换 Frame
5.前进后退
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
browser = webdriver.Chrome()
url = '/try/?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
try:
logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)
⾸先通过 switch_() ⽅法切换到⼦ Frame ⾥⾯,然后尝试获取⼦ Frame ⾥的 logo 节点(这是不能找到的),如果找不到的
话,就会抛出 NoSuchElementException 异常,异常被捕捉之后,就会输出 NO LOGO。接下来,重新切换回⽗级 Frame,然后再次重
新获取节点,发现此时可以成功获取了。
所以,当页⾯中包含⼦ Frame 时,如果想获取⼦ Frame 中的节点,需要先调⽤ switch_() ⽅法切换到对应的 Frame,然后再进
⾏操作。
6.延时等待
在 Selenium 中,get() ⽅法会在⽹页框架加载结束后结束执⾏,此时如果获取 page_source,可能并不是浏览器完全加载完成的页⾯,
如果某些页⾯有额外的 Ajax 请求,我们在⽹页源代码中也不⼀定能成功获取到。所以,这⾥需要延时等待⼀定时间,确保节点已经加载出
来。
这⾥等待的⽅式有两种:
隐式等待
当使⽤隐式等待执⾏测试的时候,如果 Selenium 没有在 DOM 中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异
常。换句话说,当查找节点⽽节点并没有⽴即出现的时候,隐式等待将等待⼀段时间再查找 DOM,默认的时间是 0。
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
在这⾥我们⽤ implicitly_wait() ⽅法实现了隐式等待。
显式等待
隐式等待的效果其实并没有那么好,因为我们只规定了⼀个固定时间,⽽页⾯的加载时间会受到⽹络条件的影响。
这⾥还有⼀种更合适的显式等待⽅法,它指定要查找的节点,然后指定⼀个最长等待时间。如果在规定时间内加载出来了这个节点,就
返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超时异常。
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
browser = webdriver.Chrome()
browser.get('/')
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)
这⾥⾸先引⼊ WebDriverWait 这个对象,指定最长等待时间,然后调⽤它的 until() ⽅法,传⼊要等待条件 expected_conditions。⽐
如,这⾥传⼊了 presence_of_element_located 这个条件,代表节点出现的意思,其参数是节点的定位元组,也就是 ID 为 q 的节点搜索
框。
这样可以做到的效果就是,在 10 秒内如果 ID 为 q 的节点(即搜索框)成功加载出来,就返回该节点;如果超过 10 秒还没有加载出来,
就抛出异常。
对于按钮,可以更改⼀下等待条件,⽐如改为 element_to_be_clickable,也就是可点击,所以查找按钮时查找 CSS 选择器为.btn-
search 的按钮,如果 10 秒内它是可点击的,也就是成功加载出来了,就返回这个按钮节点;如果超过 10 秒还不可点击,也就是没有加
载出来,就抛出异常。
关于等待条件,其实还有很多,⽐如判断标题内容,判断某个节点内是否出现了某⽂字等。
title_is 标题是某内容
title_contains 标题包含某内容
presence_of_element_located 节点加载出,传⼊定位元组,如 (, ‘p’)
visibility_of_element_located 节点可见,传⼊定位元组
visibility_of 可见,传⼊节点对象
presence_of_all_elements_located 所有节点加载出
text_to_be_present_in_element 某个节点⽂本包含某⽂字
text_to_be_present_in_element_value 某个节点值包含某⽂字
frame_to_be_available_and_switch_to_it frame 加载并切换
invisibility_of_element_located 节点不可见 element_to_be_clickable 节点可点击
staleness_of 判断⼀个节点是否仍在 DOM,可判断页⾯是否已经刷新
element_to_be_selected 节点可选择,传节点对象
element_located_to_be_selected 节点可选择,传⼊定位元组
element_selection_state_to_be 传⼊节点对象以及状态,相等返回 True,否则返回 False
element_located_selection_state_to_be 传⼊定位元组以及状态,相等返回 True,否则返回
False alert_is_present 是否出现 Alert
更多详细的等待条件的参数及⽤法介绍可以参考官⽅⽂档:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': '', 'value': 'germey'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
⾸先,我们访问了知乎。加载完成后,浏览器实际上已经⽣成 Cookies 了。接着,调⽤ get_cookies() ⽅法获取所有的 Cookies。然后,
我们添加⼀个 Cookie,这⾥传⼊⼀个字典,有 name、domain 和 value 等内容。接下来,再次获取所有的 Cookies。可以发现,结果就
多了这⼀项新加的 Cookie。最后,调⽤ delete_all_cookies() ⽅法删除所有的 Cookies。再重新获取,发现结果就为空了。
8.选项卡管理
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('')
browser.execute_script('()')
print(browser.window_handles)
browser.switch_to_window(browser.window_handles[1])
browser.get('')
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get('')
⾸先访问了百度,然后调⽤了 execute_script() ⽅法,这⾥传⼊ () 这个 JavaScript 语句新开启⼀个选项卡。接下来,我们
想切换到该选项卡。这⾥调⽤ window_handles 属性获取当前开启的所有选项卡,返回的是选项卡的代号列表。要想切换选项卡,只需要
调⽤ switch_to_window() ⽅法即可,其中参数是选项卡的代号。这⾥我们将第⼆个选项卡代号传⼊,即跳转到第⼆个选项卡,接下来在第
⼆个选项卡下打开⼀个新页⾯,然后切换回第⼀个选项卡重新调⽤ switch_to_window() ⽅法,再执⾏其他操作即可。
9.异常处理
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException
browser = webdriver.Chrome()
try:
browser.get('')
except TimeoutException:
print('Time Out')
try:
browser.find_element_by_id('hello')
except NoSuchElementException:
print('No Element')
finally:
browser.close()
这⾥我们使⽤ try except 来捕获各类异常。⽐如,我们对 find_element_by_id() 查找节点的⽅法捕获 NoSuchElementException 异
常,这样⼀旦出现这样的错误,就进⾏异常处理,程序也不会中断了。
发布评论