上一篇博文简要
在上一篇博文中已得知:使用 execute 向远程服务器发送请求会通过 webdriver 与浏览器交互,且发送已定义的命令常量可获得一些相关信息。
其中 execute 方法实现已经在上一篇博文中有实现说明。并且在我们已经知道 webdriver 基类(selenium.webdriver.remote.webdriver)中,实现了操作页面元素的基本方法。
通过简单运用全面学习
假设现在需要打开百度,搜索“CSDN A757291228”该如何进行操作呢?
通过查找 webdriver 基类(selenium.webdriver.remote.webdriver)找到了以下几个查找元素的方法:
def find_element_by_id(self, id_):
"""Finds an element by id.
:Args:
- id\_ - The id of the element to be found.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_id('foo')
"""
return self.find_element(by=By.ID, value=id_)
def find_elements_by_id(self, id_):
"""
Finds multiple elements by id.
:Args:
- id\_ - The id of the elements to be found.
:Returns:
- list of WebElement - a list with elements if any was found. An
empty list if not
:Usage:
elements = driver.find_elements_by_id('foo')
"""
return self.find_elements(by=By.ID, value=id_)
def find_element_by_xpath(self, xpath):
"""
Finds an element by xpath.
:Args:
- xpath - The xpath locator of the element to find.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_xpath('//div/td[1]')
"""
return self.find_element(by=By.XPATH, value=xpath)
def find_elements_by_xpath(self, xpath):
"""
Finds multiple elements by xpath.
:Args:
- xpath - The xpath locator of the elements to be found.
:Returns:
- list of WebElement - a list with elements if any was found. An
empty list if not
:Usage:
elements = driver.find_elements_by_xpath("//div[contains(@class,'foo')]")
"""
return self.find_elements(by=By.XPATH, value=xpath)
def find_element_by_link_text(self, link_text):
"""
Finds an element by link text.
:Args:
- link_text: The text of the element to be found.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_link_text('Sign In')
"""
return self.find_element(by=By.LINK_TEXT, value=link_text)
def find_elements_by_link_text(self, text):
"""
Finds elements by link text.
:Args:
- link_text: The text of the elements to be found.
:Returns:
- list of webelement - a list with elements if any was found. an
empty list if not
:Usage:
elements = driver.find_elements_by_link_text('Sign In')
"""
return self.find_elements(by=By.LINK_TEXT, value=text)
def find_element_by_partial_link_text(self, link_text):
"""
Finds an element by a partial match of its link text.
:Args:
- link_text: The text of the element to partially match on.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_partial_link_text('Sign')
"""
return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
def find_elements_by_partial_link_text(self, link_text):
"""
Finds elements by a partial match of their link text.
:Args:
- link_text: The text of the element to partial match on.
:Returns:
- list of webelement - a list with elements if any was found. an
empty list if not
:Usage:
elements = driver.find_elements_by_partial_link_text('Sign')
"""
return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
def find_element_by_name(self, name):
"""
Finds an element by name.
:Args:
- name: The name of the element to find.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_name('foo')
"""
return self.find_element(by=By.NAME, value=name)
def find_elements_by_name(self, name):
"""
Finds elements by name.
:Args:
- name: The name of the elements to find.
:Returns:
- list of webelement - a list with elements if any was found. an
empty list if not
:Usage:
elements = driver.find_elements_by_name('foo')
"""
return self.find_elements(by=By.NAME, value=name)
def find_element_by_tag_name(self, name):
"""
Finds an element by tag name.
:Args:
- name - name of html tag (eg: h1, a, span)
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_tag_name('h1')
"""
return self.find_element(by=By.TAG_NAME, value=name)
def find_elements_by_tag_name(self, name):
"""
Finds elements by tag name.
:Args:
- name - name of html tag (eg: h1, a, span)
:Returns:
- list of WebElement - a list with elements if any was found. An
empty list if not
:Usage:
elements = driver.find_elements_by_tag_name('h1')
"""
return self.find_elements(by=By.TAG_NAME, value=name)
def find_element_by_class_name(self, name):
"""
Finds an element by class name.
:Args:
- name: The class name of the element to find.
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_class_name('foo')
"""
return self.find_element(by=By.CLASS_NAME, value=name)
def find_elements_by_class_name(self, name):
"""
Finds elements by class name.
:Args:
- name: The class name of the elements to find.
:Returns:
- list of WebElement - a list with elements if any was found. An
empty list if not
:Usage:
elements = driver.find_elements_by_class_name('foo')
"""
return self.find_elements(by=By.CLASS_NAME, value=name)
def find_element_by_css_selector(self, css_selector):
"""
Finds an element by css selector.
:Args:
- css_selector - CSS selector string, ex: 'a.nav#home'
:Returns:
- WebElement - the element if it was found
:Raises:
- NoSuchElementException - if the element wasn't found
:Usage:
element = driver.find_element_by_css_selector('#foo')
"""
return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
def find_elements_by_css_selector(self, css_selector):
"""
Finds elements by css selector.
:Args:
- css_selector - CSS selector string, ex: 'a.nav#home'
:Returns:
- list of WebElement - a list with elements if any was found. An
empty list if not
:Usage:
elements = driver.find_elements_by_css_selector('.foo')
"""
return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
def find_element(self, by=By.ID, value=None):
"""
Find an element given a By strategy and locator. Prefer the find_element_by_* methods when
possible.
:Usage:
element = driver.find_element(By.ID, 'foo')
:rtype: WebElement
"""
if self.w3c:
if by == By.ID:
by = By.CSS_SELECTOR
value = '[id="%s"]' % value
elif by == By.TAG_NAME:
by = By.CSS_SELECTOR
elif by == By.CLASS_NAME:
by = By.CSS_SELECTOR
value = ".%s" % value
elif by == By.NAME:
by = By.CSS_SELECTOR
value = '[name="%s"]' % value
return self.execute(Command.FIND_ELEMENT, {
'using': by,
'value': value})['value']
def find_elements(self, by=By.ID, value=None):
"""
Find elements given a By strategy and locator. Prefer the find_elements_by_* methods when
possible.
:Usage:
elements = driver.find_elements(By.CLASS_NAME, 'foo')
:rtype: list of WebElement
"""
if self.w3c:
if by == By.ID:
by = By.CSS_SELECTOR
value = '[id="%s"]' % value
elif by == By.TAG_NAME:
by = By.CSS_SELECTOR
elif by == By.CLASS_NAME:
by = By.CSS_SELECTOR
value = ".%s" % value
elif by == By.NAME:
by = By.CSS_SELECTOR
value = '[name="%s"]' % value
# Return empty list if driver returns null
# See https://github.com/SeleniumHQ/selenium/issues/4555
return self.execute(Command.FIND_ELEMENTS, {
'using': by,
'value': value})['value'] or []
从以上实现的方法中,execute 方法实现在这里不在赘述实现,上一节已有说明,本节主要介绍方法使用。
首先查看 find_element_by_id 方法的使用,在方法说明中已经介绍使用方法:
element = driver.find_element_by_id('foo')
该方法注释说明为(以下为了清晰说明,使用截图展示注释):
通过注释说明得知,find_element_by_id 方法找到 id 为指定值的元素,并返回这个元素。
查看具体实现为:
self.find_element(by=By.ID, value=id_)
以上实现调用了 find_element 方法,并且传入 by 的值为 By.ID,随后传入具体值;首先查看 By 类(selenium.webdriver.common.by):
class By(object):
"""Set of supported locator strategies."""
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
这个类与 Command(selenium.webdriver.remote.command)类作用类似,上节已说明 Command 在这里也不过多说明 By。
在这里查看 find_element 方法实现:
def find_element(self, =By.ID, value=None):
"""
Find an element given a By strategy and locator. Prefer the find_element_by_* methods when
possible.
:Usage:
element = driver.find_element(By.ID, 'foo')
:rtype: WebElement
"""
if self.w3c:
if by == By.ID:
by = By.CSS_SELECTOR
value = '[id="%s"]' % value
elif by == By.TAG_NAME:
by = By.CSS_SELECTOR
elif by == By.CLASS_NAME:
by = By.CSS_SELECTOR
value = ".%s" % value
elif by == By.NAME:
by = By.CSS_SEhj0ECTOR
value = '[name="%s"]' % value
return self.execute(Command.FIND_ELEMENT, {
'using': by,
'value': value})['value']
以上类首先判断查找类型,随后进行值的拼接,最后把查找方式和值传入 execute 方法中,随后返回元素对象。
几乎所有的元素查找方法,实现相同,我们简单实用这个函数。
写代码前,我们需要打开百度网址,审查元素查找 id 值:
得到输入框的 id 值为 kw,那么代码应该如下:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
input = driver.find_element_by_id('kw')
# print('作者博客:https://blog.csdn.net/A757291228')
#支持原创,转载请贴上链接
由于查到到元素后返回的是元素对象:
在元素类(selenium.webdriver.remote.webelement)中查找方法,找到如下方法:
def send_keys(self, *value):
"""Simulates typing into the element.
:Args:
- value - A string for typing, or setting form fields. For setting
file inputs, this could be a local file path.
Use this to send simple key events or to fill out form fields::
form_textfield = driver.find_element_by_name('username')
form_textfield.send_keys("admin")
This can also be used to set file inputs.
::
file_input = driver.find_element_by_name('profilePic')
file_input.send_keys("path/to/profilepic.gif")
# Generally it's better to wrap the file path in one of the methods
# in os.path to return the actual path to support cross OS testing.
# file_input.send_keys(os.path.abspath("path/to/profilepic.gif"))
"""
# transfer file to another machine only if remote driver is used
# the same behaviour as for java binding
if self.parent._is_remote:
local_file = self.parent.file_detector.is_local_file(*value)
if local_file is not None:
value = self._upload(local_file)
self._execute(Command.SEND_KEYS_TO_ELEMENT,
{'text': "".join(keys_to_typing(value)),'value': keys_to_typing(value)})
# Private Methods
def _execute(self, command, params=None):
"""Executes a command against the underlying HTML element.
Args:
command: The name of the command to _execute as a string.
params: A dictionary of named parameters to send with the command.
Returns:
The command's JSON response loaded into a dictionary object."""
if not params:
params = {}
params['id'] = self._id
return self._parent.execute(command, params)
得知 send_keys 也是通过 execute 发送命令得到结果。在注释说明中得到了 send_keys 的使用方法为:
form_textfield.send_keys("admin")
我们修改之前的代码:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
input = driver.find_element_by_id('kw')
input.send_keys("CSDN A757291228")
# print('作者博客:https://blog.csdn.net/A757291228')
#支持原创,转载请贴上链接
最后还查个点击即可完成自动化搜索功能;我们继续查看元素类,找到如下方法:
def click(self):
"""Clicks the element."""
self._execute(Command.CLICK_ELEMENT)
click 方法与 send_keys 方法实现相同,不在赘述。直接使用 click 方法即可进行元素的点击。查找百度搜索点击按钮的 id:
修改代码如下:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
input = driver.find_element_by_id('kw')
input.send_keys("CSDN A757291228")
enter = driver.find_element_by_id('su')
enter.click()
# print('作者博客:https://blog.csdn.net/A757291228')
#支持原创,转载请贴上链接
运行结果如下:
总结
我们简单的学习了使用 selenium 打开浏览器搜索 了“CSDN A757191228”,在这个简单的例子的学习中,学习到的不仅是这个例子原本的那几行代码;通过实现分析,了解了其它功能函数所在的位置,可以通过这些功能函数,实现自己想要的功能!
从框架实现上分析可以事半功倍的学习框架的使用,以及了解框架的实现原理,更加利于我们的开发使用。