Selenium 是一套完整的 Web 应用程序测试系统, 包含了测试的录制 (Selenium IDE), 编写及运行 (Selenium Remote Control) 和测试的并行处理 (Selenium Grid)。
Selenium 的核心 Selenium Core 基于 JsUnit, 完全由 JavaScript 编写, 因此可以用于任何支持 JavaScript 的浏览器上。
Selenium 可以模拟真实浏览器, 自动化测试工具, 支持多种浏览器, 爬虫中主要用来解决 JavaScript Selenium 用于爬虫时, 相当于模拟人操作浏览器。
具有以下特点:
Selenium 是什么?
相关链接:
from selenium import webdriver
# 构造模拟浏览器
# firefox_login=webdriver.Ie() # Firefox()
firefox_login=webdriver.Chrome()
这一步可设定无界面模式, 即操作浏览器时, 隐层浏览器
options = webdriver.ChromeOptions()
options.add_argument('--headless') # 设置无界面 可选
firefox_login=webdriver.Chrome(chrome_options=options)
firefox_login.get('http://www.renren.com/')
# firefox_login.maximize_window() # 窗口最大化, 可有可无, 看情况
firefox_login.minimize_window()
firefox_login.find_element_by_id('email').clear()
firefox_login.find_element_by_id('email').send_keys('xxx@sina.com')
元素查找方法汇总
find_element_by_name
find_element_by_id
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
以上是单元素查找, 多元素把 element
变成 elements
即可。
还有一种较通用的方法
from selenium.webdriver.common.by import By 注意这里要导入
browser = webdriver.Chrome()
browser.get("http://www.taobao.com")
input_first = browser.find_element(By.ID,"q") ID 可以换成其他
firefox_login.find_element_by_id('login').click()
可将操作放入动作链中串行执行
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?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()
上面实现了一个元素拖拽的功能
执行 js 命令
直接用 js 命令操作浏览器
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.zhihu.com/explore")
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')
print(firefox_login.current_url)
print(firefox_login.page_source)
# 浏览器退出
# firefox_login.close()
firefox_login.quit()
获取元素属性: get_attribute('class')
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo.get_attribute('class'))
logo.text
logo.id
logo.location
logo.tag_name
logo.size
除了基础的操作外, 还有很多特殊的应用场景需要处理。
1.frame 标签
很多网页中存在 frame 标签, 要处理 frame 里面的数据, 首先要切入 frame, 处理完了还要切出来。
切入 用 switch_to.frame
, 切出 用 switch_to.parent_frame
示例
# encoding:utf-8
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult') # iframeResult 是 iframe 的 id 进入 frame
source = browser.find_element_by_css_selector('#draggable')
print(source)
try:
logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
print('NO LOGO')
browser.switch_to.parent_frame() # 退出 frame
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(100) #
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
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('https://www.taobao.com/')
wait = WebDriverWait(browser, 100) #
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)
显式等待和隐式等待都是无阻塞的, 即响应就继续, 不同的是, 显示等待需要设定响应条件, 如获取某元素。
title_is: 判断当前页面的 title 是否等于预期
title_contains: 判断当前页面的 title 是否包含预期字符串
presence_of_element_located: 判断某个元素是否被加到了 dom 树里, 并不代表该元素一定可见
visibility_of_element_located: 判断某个元素是否可见。可见代表元素非隐藏, 并且元素的宽和高都不等于 0
visibility_of: 跟上面的方法做一样的事情, 只是上面的方法要传入 locator, 这个方法直接传定位到的 element 就好了
presence_of_all_elements_located: 判断是否至少有 1 个元素存在于 dom 树中。举个例子, 如果页面上有 n 个元素的 class 都是'column-md-3', 那么只要有 1 个元素存在, 这个方法就返回 True
text_to_be_present_in_element: 判断某个元素中的 text 是否 包含 了预期的字符串
text_to_be_present_in_element_value: 判断某个元素中的 value 属性是否包含了预期的字符串
frame_to_be_available_and_switch_to_it: 判断该 frame 是否可以 switch 进去, 如果可以的话, 返回 True 并且 switch 进去, 否则返回 False
invisibility_of_element_located: 判断某个元素中是否不存在于 dom 树或不可见
element_to_be_clickable - it is Displayed and Enabled: 判断某个元素中是否可见并且是 enable 的, 这样的话才叫 clickable
staleness_of: 等某个元素从 dom 树中移除, 注意, 这个方法也是返回 True 或 False
element_to_be_selected: 判断某个元素是否被选中了, 一般用在下拉列表
element_located_to_be_selected
element_selection_state_to_be: 判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be: 跟上面的方法作用一样, 只是上面的方法传入定位到的 element, 而这个方法传入 locator
alert_is_present: 判断页面上是否存在 alert
更多参考: WebDriver API
wait.until(EC.text_to_be_present_in_element_value(('id', 'inputSearchCity'), u'西安'))
forward/back
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()
6.cookie 操作
get_cookies()
delete_all_cookies()
add_cookie()
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
暂略
暂略
在使用 selenium 进行自动化登录的过程中已经获取到 cookie 后, 依旧报错: selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain
获取 cookie 和添加 cookie 原代码如下:
# 获取 cookie
dr = webdriver.Chrome("D:softwareProBrowserDriverchromedriver.exe")
dr.maximize_window()
dr.get(url)
c = dr.get_cookie('JSESSIONID')
print(c)
# 添加 cookie
dr = webdriver.Chrome("D:softwareProBrowserDriverchromedriver.exe")
dr.maximize_window()
dr.add_cookie({'domain': '192.168.2.211', 'httpOnly': True, 'name': 'JSESSIONID', 'path': '/smartcommty', 'sameSite': 'Lax', 'secure': False, 'value': '5574c24a-dbc4-4a7d-9607-cc24f5653ebf'})
dr.get(url)
dr.refresh()
得到的页面一直是域名为 data 的白页面。
经过网上查找资料, 自我分析得知: selenium 的默认域名为 data, cookie 中带域名, 在设置 cookie 时发现当前域名不包含在 cookie 中, 所以设置失败, 一直都是 data 的这个页面。
解决方法就是: 在设置 cookies 前, 先访问需要登录的地址, 然后设置 cookies 登录跳转, 就 OK 了。
如下:
# 添加 cookie
dr = webdriver.Chrome("D:softwareProBrowserDriverchromedriver.exe")
dr.maximize_window()
dr.get(url)
dr.add_cookie({'domain': '192.168.2.211', 'httpOnly': True, 'name': 'JSESSIONID', 'path': '/smartcommty', 'sameSite': 'Lax', 'secure': False, 'value': '5574c24a-dbc4-4a7d-9607-cc24f5653ebf'})
dr.get(url)
dr.refresh()
在创建 webdriver 时, 将 firefox.exe 可执行文件路径当做参数传递给 webdriver。如下:
geckodriver
加入环境变量;Error message: selenium.common.exceptions.ElementNotInteractableException: Message: Element
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
mySelectElement = browser.find_element_by_id('providerTypeDropDown')
dropDownMenu = Select(mySelectElement)
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//select[@id='providerTypeDropDown']//options[contains(.,'Professional')]")))
dropDownMenu.select_by_visible_text('Professional')
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
mySelectElement = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "providerTypeDropDown")))
mySelectElement.click()
If your use case is to validate the presence of any element, you need to induce WebDriverWait setting the expected_conditions as presence_of_element_located() which is the expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. So the effective line of code will be:
WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".reply-button"))).click()
If your use case is to extract any attribute of any element you need to induce WebDriverWait setting the expected_conditions as visibility_of_element_located(locator) which is an expectation for checking that an element is present on the DOM of a page and visible. Visibility means that the element is not only displayed, but it also has a height and width that is greater than 0. So in your use case, effectively the line of code will be:
email = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "element_css"))).get_attribute("value")
If your use case is to invoke click()
on any element you need to induce WebDriverWait setting the expected_conditions as element_to_be_clickable() which is an expectation for checking an element is visible and enabled such that you can click it. So in your use case, effectively the line of code will be:
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".reply-button"))).click()
References
You can find a couple of detailed discussion in: