#author("2023-11-22T10:54:32+08:00","default:Admin","Admin") #author("2023-11-22T10:55:44+08:00","default:Admin","Admin") [[Python]] &color(red){※This article is based on Python 3.7.3}; #contents * 环境 [#dd3c02c3] ** webdriver [#tc23454f] *** Microsoft Edge浏览器 [#le6d78da] 推荐使用Edge浏览器,因为Chrome的版本问题,webdrive总是没有最新的 浏览器下载地址: https://www.microsoft.com/zh-cn/edge 驱动器下载地址: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ *** Firefox(火狐)浏览器 [#ha861d6f] 浏览器下载地址: http://www.firefox.com.cn 驱动器下载地址: https://github.com/mozilla/geckodriver/releases *** Chrome(google)浏览器 [#if7ca860] 浏览器下载地址: https://www.google.cn/chrome 驱动器下载地址: http://chromedriver.storage.googleapis.com/index.html 下载路径 http://npm.taobao.org/mirrors/chromedriver/ 要和本地的Chrome的版本一致,否则报错 #codeprettify{{ selenium.common.exceptions.WebDriverException: Message: unknown error: cannot connect to chrome at 127.0.0.1:9527 from session not created: This version of ChromeDriver only supports Chrome version 99 Current browser version is 116.0.5845.142 Stacktrace: Backtrace: Ordinal0 [0x007B9943+2595139] Ordinal0 [0x0074C9F1+2148849] Ordinal0 [0x00644528+1066280] Ordinal0 [0x006642C3+1196739] Ordinal0 [0x0065D83B+1169467] Ordinal0 [0x0065D606+1168902] Ordinal0 [0x00690530+1377584] }} * 等待 [#x1696d98] ** 显示等待 [#jead09ae] WebDriverWait(driver,timeout=10).until(ec.presence_of_element_located(locator)) 超时时间内定位到locator后执行下一步,否则超时异常 ** 隐式等待 [#zba3cd2f] driver.implicitly_wait(timeout=10) 等待页面完全加载好才能执行下一步,只需要获取某个元素时,有点浪费时间,配一个限制一下避免部分页面加载慢 ** 强制等待 [#pf4bb74a] time.sleep(10) 不要用这种,不稳定 * 打开页面 [#sfb72490] driver.set_page_load_timeout(timeout=20) 执行get(url)方法,页面等待超时时间 ** 新窗口 [#lc8f2f64] 在新窗口打开页面 #codeprettify{{ from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get("https://www.baidu.com") sleep(2) newWin = "window.open('https://www.baidu.com')" driver.execute_script(newWin) # 句柄切换到新窗口 handles = driver.window_handles # driver.switch_to.window(handles[-1])# -1为最新打开的窗口 driver.switch_to_window(handles[0])# 0为第一个打开的窗口 driver.find_element_by_id("kw").send_keys("python") }} * 退出 [#s053b007] 退出有两种方式 + close 用于关闭当前窗口,当打开的窗口较多时,就可以用close关闭部分窗口 + quit 用于结束进程,关闭所有的窗口,即关闭当前浏览器进程 最后结束测试,要用quit。quit可以回收c盘的临时文件。 * 元素定位 [#pbbb88e1] Html Code <input type="text" class="s_ipt" name="wd" id="kw" /> |定位方式|By|h |id|By.ID| |name|By.NAME| |class_name|By.CLASS_NAME| |tag_name|By.TAG_NAME| |link_text|By.LINK_TEXT| |partial_link_text|By.PARTIAL_LINK_TEXT| |css_selector|By.CSS_SELECTOR| |xpath|By.XPATH| ** ID定位 [#k9a98108] find_element_by_id(id) #id参数表示的是id的属性值;(定位的元素必须有ID属性) #codeprettify{{ driver.find_element_by_id("kw") }} ** NAME定位 [#w6688dec] find_element_by_name(name) #name参数表示的是name的属性值;(定位元素必须有NAME属性) driver.find_element_by_name("wd") ** CLASS_NAME定位 [#sfdf6aa0] find_element_by_class_name(class_name) #class_name参数表示的是class的属性值;(定位元素必须有class属性) driver.find_element_by_class_name("s_ipt") #新的用法 driver.find_element(by=By.CLASS_NAME, value="s_ipt") #列举多个 driver.find_elements(by=By.CLASS_NAME, value="s_ipt") 注意:class属性值有多个时(用空格隔开),仅需要其中一个属性值:(但若是使用Xpath属性定位时,需要用到全部属性值) ** TAG_NAME定位 [#we1e80e2] find_element_by_tag_name(tag_name) #tag_name参数表示的是元素的标签名;(定位元素必须有标签名)如果有重复的元素定位到的元素默认都是第一个; driver.find_element_by_tag_name("input") ** XPATH定位 [#y0ad1e43] #codeprettify{{ <?xml version="1.0"?> <root> <child attr="attr" /> <child> <a><desc /></a> </child> </root> {针对上面的XML文档的XPath结果,当前节点为document /root {选取root root {选取root child {空,因为child不是document的子元素 //child {选取两个child元素,//表示后代 //@attr {选取attr属性节点 /root/child//desc {返回child的后代元素desc }} *** 使用class定位 [#z391c356] driver.find_element_by_xpath('//input[@class="s_ipt"]') ***路径定位 [#ga85e80e] 定位方法:find_element_by_xpath(xpath) #xpath表达式 绝对路径:表达式以/html开头,元素的层级之间是以/分隔,相同层级的元素可以使用下标,下标从1开始;需要列出元素所经过的所有层级元素,在工作中,一般不使用绝对路径。 /html/body/div/div/div/div/div 路径定位 定位方法:find_element_by_xpath(xpath) #xpath表达式 相对路径:匹配任意层级的元素,是以//tag_name或者//*开头,也可以使用下标,下标从1 开始。 //div[10]//button *** 属性定位 [#da43638d] #codeprettify{{ <input type="text" class="s_ipt" name="wd" id="kw" /> driver.find_element_by_xpath(//input[@id='kw']) }} ** 通过父元素查找子元素 [#z5deb3d8] 在Selenium中,我们可以使用find_element_by_xpath()方法来查找子元素。例如,假设我们要查找一个div元素下面的第二个a元素,可以使用以下代码: #codeprettify{{ div_element = driver.find_element_by_xpath("//div[@class='example']") a_element = div_element.find_element_by_xpath(".//a[2]") }} 上面的代码首先使用driver.find_element_by_xpath()方法查找到class属性为'example'的div元素,然后使用div_element.find_element_by_xpath()方法查找div元素下面的第二个a元素。在这里,'.//'表示相对路径,表示在当前元素下查找子元素。 ** 通过子元素找到父元素 [#gf0cd54c] 在Selenium中,我们也可以使用parent属性来查找父元素。例如,假设我们要查找一个a元素的父元素,可以使用以下代码: #codeprettify{{ a_element = driver.find_element_by_xpath("//a[@id='example']") div_element = a_element.find_element_by_xpath("..") }} 上面的代码首先使用driver.find_element_by_xpath()方法查找id属性为'example'的a元素,然后使用a_element.find_element_by_xpath("..")方法查找a元素的父元素。在这里,'..'表示父节点。 ** 兄弟节点定位 [#q1212fde] 兄弟节点定位是指在HTML中,同一级别的元素之间存在兄弟关系。例如,一个ul元素下面有多个li元素,这些li元素就是ul元素的兄弟节点。在Selenium中,我们可以使用兄弟节点定位来查找特定的元素。 *** 查找前一个兄弟节点 [#xc395122] 在Selenium中,我们可以使用preceding-sibling轴来查找前一个兄弟节点。例如,假设我们要查找一个ul元素下面的第一个li元素的前一个兄弟节点,可以使用以下代码: #codeprettify{{ ul_element = driver.find_element_by_xpath("//ul[@class='example']") li_element = ul_element.find_element_by_xpath("./li[1]") previous_li_element = li_element.find_element_by_xpath("preceding-sibling::li[1]") }} 上面的代码首先使用driver.find_element_by_xpath()方法查找class属性为'example'的ul元素,然后使用ul_element.find_element_by_xpath()方法查找ul元素下面的第一个li元素,最后使用li_element.find_element_by_xpath("preceding-sibling::li[1]")方法查找li元素的前一个兄弟节点。 *** 查找后一个兄弟节点 [#t9c920b2] 在Selenium中,我们可以使用following-sibling轴来查找后一个兄弟节点。例如,假设我们要查找一个ul元素下面的第一个li元素的后一个兄弟节点,可以使用以下代码: #codeprettify{{ ul_element = driver.find_element_by_xpath("//ul[@class='example']") li_element = ul_element.find_element_by_xpath("./li[1]") next_li_element = li_element.find_element_by_xpath("following-sibling::li[1]") }} 上面的代码首先使用driver.find_element_by_xpath()方法查找class属性为'example'的ul元素,然后使用ul_element.find_element_by_xpath()方法查找ul元素下面的第一个li元素,最后使用li_element.find_element_by_xpath("following-sibling::li[1]")方法查找li元素的后一个兄弟节点。 * 基本操作 [#t3244061] ** 浏览器相关操作 [#a52aa1bd] 创建浏览器对象 driver = http://webdriver.xxx() 窗口最大化 maximize_window() 获取浏览器尺寸 get_window_size() 设置浏览器尺寸 set_window_size() 获取浏览器位置 get_window_position() 设置浏览器位置 set_window_position(x,y) 关闭当前标签/窗口 close() 关闭所有标签/窗口 quit() ** 页面相关操作 [#tf82b85f] 请求某个url driver.get(url) 刷新页面操作 refresh() 回退到之前的页面 back() 前进到之后的页面 forward() 获取当前访问页面url current_url 获取当前浏览器标题 title 保存图片 get_screenshot_as_png()/get_screenshot_as_file(file) 网页源码 page_source ** 元素的操作 [#r747b5fe] 点击操作 element.click() 清空输入框 element.clear() 输入框输入数据 element.send_keys(data) 获取文本内容(既开闭标签之间的内容) element.text 获取属性值 #codeprettify{{ element = driver.find_element_by_id('user') print(element.get_attribute('class')) element = driver.find_element_by_class_name('input') print(element.get_attribute('value')) }} 获取 HTML 内容(整个元素 HTML 或 元素内部的 HTML): #codeprettify{{ element = driver.find_element_by_id('id') print(element.get_attribute('outerHTML')) // 获取整个元素对应的 HTML print(element.get_attribute('innerHTML')) // 获取元素内部分HTML }} ** 鼠标和键盘操作 [#ub04688b] 鼠标操作需要导入类,见第一部分,然后创建对象ActionChains(driver),键盘操作导入类 鼠标右击 el = driver.find_element_by_xxx(value) context_click(el) 鼠标双击 el = driver.find_element_by_xxx(value) ActionChains(driver).double_click(el).perform() 鼠标悬停 el = driver.find_element_by_xxx(value) ActionChains(driver).move_to_element(el).perform() ** 常用键盘操作 [#jc6f76c1] send_keys(Keys.BACK_SPACE) 删除键(BackSpace) send_keys(Keys.SPACE) 空格键(Space) send_keys(Keys.TAB) 制表键(Tab) send_keys(Keys.ESCAPE) 回退键(Esc) send_keys(Keys.ENTER) 回车键(Enter) send_keys(Keys.CONTROL,‘a’) 全选(Ctrl+A) send_keys(Keys.CONTROL,‘c’) 复制(Ctrl+C) send_keys(Keys.CONTROL,‘x’) 剪切(Ctrl+X) send_keys(Keys.CONTROL,‘v’) 粘贴(Ctrl+V) ** 弹出框操作 [#gf59935f] 进入到弹出框中 driver.switch_to.alert() 接收警告 accept() 关闭警告 dismiss() 发送文本到警告框 send_keys(data) ** 下拉框操作 [#y0846917] 将定位到的下拉框元素传入Select类中 selobj = Select(element) 通过索引选择,index 索引从 0 开始 select_by_index() 通过值选择(option标签的一个属性值) select_by_value() 通过文本选择(下拉框的值) select_by_visible_text() 查看所有已选 all_selected_options 查看第一个已选 first_selected_option 查看是否是多选 is_multiple 查看选项元素列表 options 取消选择 deselect_by_index() /deselect_by_value()/ deselect_by_visible_text() ** 滚动条操作 [#zdcad984] x为水平拖动距离,y为垂直拖动举例 js = "window.scrollTo(x,y) " driver.execute_script(js) js= “var q=document.documentElement.scrollTop=n” n为从顶部往下移动滚动举例 driver.execute_script(js) ** cookies操作 [#ofe7f075] 获取所有cookies get_cookies() 获取key对应的值 get_cookie(key) 设置cookies add_cookie(cookie_dict) 删除指定名称的cookie delete_cookie(name) 删除所有cookie delete_all_cookies() ** 多标签/多窗口、多表单/多框架切换 [#f3f4fedb] 多表单/多框架切换 直接使用id值切换进表单 driver.switch_to.frame(value) 定位到表单元素,再切换进入 el = driver.find_element_by_xxx(value) driver.switch_to.frame(el) 跳回最外层的页面 driver.switch_to.default_content() 跳回上层的页面 driver.switch_to.parent_frame() 多标签/多窗口之间的切换 获取所有窗口的句柄 handles = driver.window_handlers 通过窗口的句柄进入的窗口 driver.switch_to.window(handles[n]) * 例程 [#gf8f73cd] #codeprettify{{ from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException, NoSuchElementException from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.common.keys import Keys import time class SeleniumHelper: def __init__(self, driver): self.driver = driver def find_element(self, locator, timeout=10): """ 查找单个元素 :param locator: 元素定位信息,如(By.ID, 'element_id') :param timeout: 超时时间,默认为10秒 :return: WebElement对象或None """ try: element = WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located(locator) ) return element except (TimeoutException, NoSuchElementException): return None def find_elements(self, locator, timeout=10): """ 查找多个元素 :param locator: 元素定位信息,如(By.CLASS_NAME, 'element_class') :param timeout: 超时时间,默认为10秒 :return: WebElement对象列表或空列表 """ try: elements = WebDriverWait(self.driver, timeout).until( EC.presence_of_all_elements_located(locator) ) return elements except (TimeoutException, NoSuchElementException): return [] # Edge浏览器 https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ s=Service('F:\Temp\edgedriver_win64\msedgedriver.exe') options = webdriver.EdgeOptions() options.use_chromium = True # 屏蔽inforbar options.add_experimental_option('useAutomationExtension', False) options.add_experimental_option('excludeSwitches', ['enable-automation', 'enable-logging']) options.add_argument("start-maximized") # options.add_argument('--headless') options.binary_location=r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe' driver = webdriver.Edge(service=s, options=options) driver.get('https://www.baidu.com') # 创建SeleniumHelper对象 helper = SeleniumHelper(driver) search_box = helper.find_element((By.ID, 'kw')) if search_box: search_box.send_keys("aaaaaa") search_box.send_keys(Keys.RETURN) time.sleep(6) #driver.quit() }} * Troubleshooting [#mddadd03] ** pip install win32api [#d7298cab] ERROR: Could not find a version that satisfies the requirement win32api (from versions: none) ERROR: No matching distribution found for win32api 使用pip install pypiwin32 安装成功 E:\python>pip install pypiwin32 ** button is not clickable at point [#ncc7ae24] 错误现象 #codeprettify{{ selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <button type="button" class="lvc2-grey-btn" elementtiming="element-timing">...</button> is not clickable at point (569, 903). Other element would receive the click: <div class="index-module__goodsFooterContainer___3poOW " elementtiming="element-timing" style="left: 526.156px; width: 621.328px;">...</div> (Session info: MicrosoftEdge=115.0.1901.183) }} 原因有四种可能性 + 没加载出来就等待元素加载出来,再往下执行。最好还是使用selenium自带WebDriverWait + 如果元素在iframe里,在窗口里找是找不到元素的,更是无法点击。所以,要切换到iframe里去找元素。 + 不在视窗里,需要拉滚动条 + 要点击的元素被覆盖 + 要点击的元素被遮挡 * find_element_by_id 找不到要素的处理 [#k247b620] #codeprettify{{ import unittest from selenium import webdriver from selenium.common.exceptions import NoSuchElementException #导入NoSuchElementException class ExceptionTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.get("https://www.baidu.com") def test_exception(self): driver = self.driver try: search_text = driver.find_element_by_id("ss") self.assertEqual('百度一下', search_text.get_attribute("value")) except NoSuchElementException: }} #hr(); コメント: #comment_kcaptcha