About
重新认识alert
首先,不是所有的alert都能叫做alert框。
JavaScript中,关于消息提示框的方法有三个(虽然都跟alert差不多):
- alert(message)方法用于显示带有一条指定消息和一个 OK 按钮的警告框。
- confirm(message)方法用于显示一个带有指定消息和 OK 及取消按钮的对话框。如果用户点击确定按钮,则 confirm() 返回 true。如果点击取消按钮,则 confirm() 返回 false。
- prompt(text,defaultText)方法用于显示可提示用户进行输入的对话框。如果用户单击提示框的取消按钮,则返回 null。如果用户单击确认按钮,则返回输入字段当前显示的文本。
来看个示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>alert</title> </head> <body> <input type="button" id="alertButton" value="alert" onclick="alertButton()"> <input type="button" id="confirmButton" value="confirm" onclick="confirmButton()"> <input type="button" id="promptButton" value="prompt" onclick="promptButton()"> <script> function alertButton() { alert('我是普通的alert提示框'); }; function confirmButton() { var msg = confirm('点击[确定]或者[取消]按钮'); if (msg) { alert('你点击的是[确定按钮]'); } else { alert('你点击的是[取消按钮]'); } }; function promptButton() { var msg = prompt('输入一个值:', '我是默认值'); if (msg) { alert('输入的值为: ' + msg); } else { alert('输入值为空'); } }; </script> </body> </html>
selenium如何处理?
selenium操作上面三种提示框有以下几种方法:
- alertObject.text:获取提示的文本值。
- alertObject.accept():点击『确认』按钮。
- alertObject.dismiss():点击『取消』或者叉掉对话框。
- alertObject.send_keys(message):输入文本,仅适用于prompt方法,因为alert和confirm的提示框没有输入框!!!并且,如果在非prompt类型的提示框使用alertObject.send_keys(message),会报错!
whatever,因为这些消息提示框的特性,我们『检查 or F12』都无法选中提示框。所以,selenium在处理起来,首先要经过一个switch_to
的过程。
另外,当你看到提示框只有提示信息和一个确定按钮时,它就是alert提示框;当你看到提示框中有提示信息和确定/取消按钮都在时,它就是confirm提示框;当你看到提示信息和input框,并且确定和取消按钮都在时,它就是prompt提示框。
至于,为什么不提提示框中右上角的叉掉图标,这是根据浏览器的不同,有的有这个图标,有的没有,比如Chrome和Firefox就没有,而IE就有。
selenium处理alert提示框
selenium在处理alert时,要经过:
switch_to.alert
方法将webdriver作用域切换到alert提示框上。- 现在,我们可以使用text获取提示文本信息、accept()点击确认按钮、dismiss()点击取消或者叉掉提示框。
import time from selenium import webdriver driver = webdriver.Chrome() try: driver.get(url='file:///M:/tests.html') time.sleep(2) driver.find_element_by_id('alertButton').click() time.sleep(1) # alertObject = driver.switch_to_alert() # 不要使用这个方法了,因为该方法即将被弃用,当然,暂时还是可以使用,或者selenium版本较低也可以使用。 alertObject = driver.switch_to.alert # 这里,alert方法不加括号,以为该方法被 @property 伪装成属性了,具体参考源码 print(alertObject.text) # text方法也被 @property 伪装成属性了 alertObject.accept() # 点击确定按钮 time.sleep(2) driver.find_element_by_id('alertButton').click() time.sleep(1) alertObject = driver.switch_to.alert time.sleep(2) alertObject.dismiss() # 叉掉提示框 time.sleep(2) driver.find_element_by_id('alertButton').click() time.sleep(1) alertObject = driver.switch_to.alert alertObject.send_keys('这一行会报错') # selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable: User dialog does not have a text box input field. finally: time.sleep(10) driver.quit()
由最后的报错可以看到,alert提示框中不能使用alertObject.send_keys(message)
方法。
selenium处理confirm提示框
selenium在处理confirm时,与处理alert一样:
switch_to.alert
方法将webdriver作用域切换到alert提示框上。- 现在,我们可以使用text获取提示文本信息、accept()点击确认按钮、dismiss()点击取消或者叉掉提示框。
import time from selenium import webdriver driver = webdriver.Chrome() try: driver.get(url='file:///M:/tests.html') time.sleep(2) driver.find_element_by_id('confirmButton').click() time.sleep(1) alertObject = driver.switch_to.alert print(alertObject.text) # 打印提示信息 time.sleep(1) alertObject.accept() # 点击确定按钮 time.sleep(1) alertObject.accept() # 根据前端js代码逻辑,当点击确定按钮后会再弹出一个提示框,我们再次点击确定 time.sleep(2) driver.find_element_by_id('confirmButton').click() time.sleep(1) alertObject = driver.switch_to.alert alertObject.send_keys('这一行会报错') # selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable: User dialog does not have a text box input field. finally: time.sleep(10) driver.quit()
同样的,confirm提示框中也不能使用alertObject.send_keys(message)
方法。
selenium处理prompt提示框
selenium在处理prompt时,与处理alert/confirm一样:
switch_to.alert
方法将webdriver作用域切换到alert提示框上。- 现在,我们可以使用text获取提示文本信息、accept()点击确认按钮、dismiss()点击取消或者叉掉提示框。
- 现在可以使用
alertObject.send_keys(message)
方法了。
import time from selenium import webdriver driver = webdriver.Chrome() try: driver.get(url='file:///M:/tests.html') time.sleep(2) driver.find_element_by_id('promptButton').click() time.sleep(1) alertObject = driver.switch_to.alert print(alertObject.text) # 打印提示信息 time.sleep(1) alertObject.send_keys('send keys msg') print(alertObject.text) # 打印提示信息 alertObject.accept() # 点击确定按钮 print(alertObject.text) # 打印提示信息 time.sleep(1) alertObject.accept() # 根据前端js代码,当点击确定按钮后会再弹出一个提示框,我们再次点击确定 time.sleep(2) driver.find_element_by_id('promptButton').click() time.sleep(1) alertObject = driver.switch_to.alert alertObject.send_keys('') time.sleep(1) alertObject.dismiss() # 什么都不管,直接点击取消,会在弹出一个提示框 time.sleep(1) # 现在弹出的是一个普通的提示框,点击确定和取消都无所谓,具体根据业务场景来决定 # alertObject.accept() alertObject.dismiss() finally: time.sleep(10) driver.quit()
在prompt提示框中,要看到input框才能send keys!
see also:alert | confirm | prompt | 自动化测试基础篇--Selenium弹出框alert
before
我们日常使用浏览器的步骤为:启动浏览器、打开一个网页、进行交互。而无头浏览器指的是我们使用脚本来执行以上过程的浏览器,能模拟真实的浏览器使用场景。
有了无头浏览器,我们就能做包括但不限于以下事情:
- 对网页进行截图保存为图片或 pdf。
- 抓取单页应用(SPA)执行并渲染(解决传统 HTTP 爬虫抓取单页应用难以处理异步请求的问题)。
- 做表单的自动提交、UI的自动化测试、模拟键盘输入等。
- 用浏览器自带的一些调试工具和性能分析工具帮助我们分析问题。
- 在最新的无头浏览器环境里做测试、使用最新浏览器特性。
- 写爬虫做你想做的事情。
无头浏览器很多,包括但不限于:
- PhantomJS, 基于 Webkit
- SlimerJS, 基于 Gecko
- HtmlUnit, 基于 Rhnio
- TrifleJS, 基于 Trident
- Splash, 基于 Webkit
这里我们简单来说,在selenium中使用无头浏览器。
PhantomJS
PhantomJS是一个无界面的、可脚本编程的WebKit浏览器引擎,其快速,原生支持各种Web标准: DOM 处理, CSS 选择器, JSON, Canvas, 和 SVG。
- PhantomJS是一个基于webkit内核、无界面的浏览器,即它就是一个浏览器,只是其内的点击、翻页等人为相关操作需要程序设计实现;
- PhantomJS提供Javascript API接口,可以通过编写JS程序直接与webkit内核交互;
- PhantomJS的应用:无需浏览器的 Web 测试、网页截屏、页面访问自动化、网络监测。
安装
下载安装
根据自己的系统平台,下载相应的包,我这里是Windows 64位系统,所以,我选择下载windows版本的,phantomjs-2.1.1版本下载地址:
https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-windows.zip
在压缩包解压后,将其中的bin目录添加到环境变量中:
测试
import time from selenium import webdriver path = r'C:python36Scriptsphantomjs-2.1.1-windowsinphantomjs.exe' driver = webdriver.PhantomJS(executable_path=path) driver.implicitly_wait(10) driver.get('https://www.baidu.com') print(driver.title) # 百度一下,你就知道 time.sleep(1) driver.quit()
但是有时候,虽然添加了path,但还是不好用,会报这个错误:
selenium.common.exceptions.WebDriverException: Message: 'phantomjs' executable needs to be in PATH.
解决办法是如我上例中那样,执行上驱动的path就好了。
模拟登陆示例
现在来一个示例,就是模拟登陆网站,在输入用户名、密码和验证码都错误的情况下,网站会给出一个提示信息,我们根据提示信息来判断,如果有提示信心,那么说明登录失败,我们就截图记录下有提示信息的界面。
import time from selenium import webdriver path = r'C:python36Scriptsphantomjs-2.1.1-windowsinphantomjs.exe' driver = webdriver.PhantomJS(executable_path=path) driver.implicitly_wait(10) try: driver.get('https://pythonav.com/login/') driver.find_element_by_id('id_username').send_keys('123') driver.find_element_by_id('id_password').send_keys('123') driver.find_element_by_id('id_code').send_keys('123') driver.find_element_by_xpath('//*[@id="fm"]/div[5]/div/input').click() time.sleep(1) result = driver.find_element_by_xpath('//*[@id="fm"]/div[1]/span').text if result: # 如果提示信息有值,说明登录失败,需要截图 driver.save_screenshot('./error.png') else: print('登录成功......') except Exception as e: print(e) driver.save_screenshot('./error.png') finally: time.sleep(3) driver.quit()
当脚本执行完毕后,在脚本的同级目录,会有一个error.png
图片:
OK,完美!
谷歌无头浏览器
因为phantomjs暂停开发,我们选择使用(并且优先推荐)谷歌的无头浏览器。
更多关于phantomjs暂停开发信息,参见:https://github.com/ariya/phantomjs/issues/15344
什么是无头浏览器(headless browser)?
无头浏览器是指可以在图形界面情况下运行的浏览器。我可以通过编程来控制无头浏览器自动执行各种任务,比如做测试,给网页截屏等。
为什么叫“无头”浏览器?
“无头”这个词来源于最初的“无头计算机(Headless computer)”。维基百科关于的“无头计算机”词条:
无头系统(headless system)是指已配置为无须显示器(即“头”)、键盘和鼠标操作的计算机系统或设备。无头系统通常通过网络连接控制,但也有部分无头系统的设备需要通过RS-232串行连接进行设备的管理。服务器通常采用无头模式以降低运作成本。
配置无头的相关参数
import time from selenium import webdriver from selenium.webdriver.chrome.options import Options # 创建一个参数对象,用来控制chrome以无界面模式打开 chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') # 创建浏览器对象 driver = webdriver.Chrome(chrome_options=chrome_options) driver.implicitly_wait(10) # 访问URL driver.get('https://www.baidu.com') print(driver.title) # 百度一下,你就知道 time.sleep(1) driver.quit()
模拟登录示例
再来一个示例,跟phantomjs一样的模拟登陆的示例:
import time from selenium import webdriver from selenium.webdriver.chrome.options import Options # 创建一个参数对象,用来控制chrome以无界面模式打开 chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') # 创建浏览器对象 driver = webdriver.Chrome(chrome_options=chrome_options) driver.implicitly_wait(10) try: driver.get('https://pythonav.com/login/') driver.find_element_by_id('id_username').send_keys('123') driver.find_element_by_id('id_password').send_keys('123') driver.find_element_by_id('id_code').send_keys('123') driver.find_element_by_xpath('//*[@id="fm"]/div[5]/div/input').click() time.sleep(1) result = driver.find_element_by_xpath('//*[@id="fm"]/div[1]/span').text if result: # 如果提示信息有值,说明登录失败,需要截图 driver.save_screenshot('./error.png') else: print('登录成功......') except Exception as e: print(e) driver.save_screenshot('./error.png') finally: time.sleep(3) driver.quit()
除了无头,其他用法没有变化。
see also:无头浏览器 Puppeteer 初探 | PhantomJs的用法(一)——下载与安装 | 什么是「无头浏览器」 (Headless browser),它有什么应用场景?
规避网站监测
现在不少大网站有对selenium采取了监测机制。比如正常情况下我们用浏览器访问淘宝等网站的 window.navigator.webdriver的值为
undefined。而使用selenium访问则该值为true。那么如何解决这个问题呢?
只需要设置Chromedriver的启动参数即可解决问题。在启动Chromedriver之前,为Chrome开启实验性功能参数excludeSwitches
,它的值为['enable-automation']
,完整代码如下:
import time from selenium import webdriver from selenium.webdriver import ChromeOptions # 需要导入的类 # 创建 option 对象 option = ChromeOptions() option.add_experimental_option('excludeSwitches', ['enable-automation']) # 创建浏览器对象 driver = webdriver.Chrome(options=option) driver.implicitly_wait(10) driver.get('https://www.taobao.com/') print(driver.title) # 淘宝网 - 淘!我喜欢 time.sleep(2) driver.quit()