赞
踩
目录
3.1.1、查找元素在网页中的位置(网址为www.baidu.com,代码中的注释很详细)
WebDrvierAPI在RemoteWebDrvier类的调用图
Selenium最初是由Jason Huggins测试工程师为减少手工测试量做的基于JavaScript语言的代码库(这时是通过js注入的方式操作),之后不断的发展完善并合并了WebDrive项目,使之可以直接调用浏览器和操作系统内置的方法,解决了JavaScript环境的沙盒限制,发展成了现在我们经常使用的Selenium WebDriver。现在的selenium就像百度百科说的一样,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
在爬取数据的时候,我们通常可以使用requests库,但是如果遇到加密的网站,就需要js逆向,相当复杂。但是我们还有一种方法,那就是使用自动化工具,实现可见即可爬,完成JavaScript动态渲染页面。
WebDriver的核心是是一个浏览器驱动程序,他负责启动浏览器,并将控制权交个程序,同时还提供了API,直接使用并控制浏览器的内置对象,可以使用它来模拟用户的行为,如点击提交,填写文本框,键入网址等。
WebElement表示 DOM 元素。 通常,所有与指定元素交互的操作都将通过此接口执行。如:如点击提交,填写文本框,键入网址,还包括获取文本属性等,这是不是很熟悉,原来WebElement属于WebDrvierAPI;它可以对指定网页元素进行操作。
总结
WebElement属于WebDriver API,通常使用于对指定可见元素进行操作,一般的实现如下:通过WebDriverAPI提供的方法(如:find_element())进行元素定位并返回WebElement对象,再调用此对象对指定元素进行操作。
查看浏览器版本,下载对应驱动,相关驱动的下载链接如下
Chrome驱动:chromedriver.storage.googleapis.com/index.html
Firefox驱动:Releases · mozilla/geckodriver (github.com)
Edge驱动:Microsoft Edge WebDriver - Microsoft Edge Developer
pip install selenium
-
- from selenium import webdriver
- import time
- driver=webdriver.Chrome('./chromedriver.exe')#初始化WebDriver对象
- driver.get('https://www.baidu.com')#访问百度
- time.sleep(20)
-
-
Chrome的参数有很多,在这里我们初始化时传入的是executable_path,代表驱动的位置
驱动文件我放在了与代码同级目录下
方法 | 作用 | 参数说明 | |
find_element | 得到首个被匹配的节点 | By参数——By.ID通过标签ID属性匹配,By.CSS_SELECTOR,使用CSS选择器进行定位匹配,By.Name通过属性名进行匹配 Value参数——匹配的属性值 | |
find_elements | 得到所有被匹配的节点,返回值为WebElement元素列表 | 同上 |
- from selenium import webdriver
- from selenium.webdriver.common.by import By
- import time
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('http://www.baidu.com')
- #css选择器进行筛选
- #如果有多个元素被匹配,find_element只会获取第一个
- result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
- print(result,'\n','---------------')
- #匹配多个find_elements
- result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
- for item in result_list:
- print(item)
- print('---------------')
- result_byid=driver.find_element(by=By.NAME,value='tj_more')
- print(result_byid)
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="bd760d4c-a045-4316-b398-7cb4ae7b6f6e")>
- ---------------
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="bd760d4c-a045-4316-b398-7cb4ae7b6f6e")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="4c25b06b-8dd5-4da7-b362-43965f389102")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="43406d63-edea-4a7b-b2d2-307a7ad16714")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="c3434610-4579-4f43-9d42-42837dc8b151")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="fb6d11ff-f87b-4993-bad0-b35876e85c46")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="d8388d32-f732-488b-8b15-92a003c2a217")>
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="e8b99605-50d0-4679-9ef6-4a708d4d8ec8")>
- ---------------
- <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="e448b794-6c02-4683-8225-25a2d647d28d")>
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('http://www.baidu.com')
- result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
- print(result.text,result.get_attribute('href'),'\n','------------------------------------')
- result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
- for item in result_list:
- print(item.text,item.get_attribute('href'))
- print('---------------------------------')
- #webdriver只与可见元素交互,如果该元素被隐藏,将不会被获取文本值,但是属性仍可获取到,可通过is_displayed()进行查看
- result_byid=driver.find_element(by=By.NAME,value='tj_more')
- print({'text':result_byid.text,'href':result_byid.get_attribute('href')})
- print(result_byid.is_displayed())
- 新闻 http://news.baidu.com/
- ------------------------------------
- 新闻 http://news.baidu.com/
- hao123 https://www.hao123.com/?src=from_pc
- 地图 http://map.baidu.com/
- 贴吧 http://tieba.baidu.com/
- 视频 https://haokan.baidu.com/?sfrom=baidu-top
- 图片 http://image.baidu.com/
- 网盘 https://pan.baidu.com/?from=1026962h
- ---------------------------------
- {'text': '', 'href': 'http://www.baidu.com/more/'}
- False
- from selenium import webdriver
- import time
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('https://www.baidu.com')
- web_element=driver.find_element(By.CSS_SELECTOR,'.s_ipt')
- web_element.send_keys('张三')
- driver.find_element(By.CSS_SELECTOR,'[id="su"]').click()
- time.sleep(100)
操作 | 含义 |
click() | 点击按钮 |
sendkeys() | 输入到单选框 |
clear() | 清空输入框 |
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.ui import WebDriverWait
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('http://www.baidu.com')
- wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间
- #等待节点,返回值是WebElement
- result_waitelement=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t')))
- #等待节点并判断某个节点是否满足条件,返回值是bool类型
- result_waittext=wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'mnav'), '新闻'))#等待节点包含的文本值
- result_waitattribute=wait.until(EC.text_to_be_present_in_element_attribute((By.CLASS_NAME,'mnav'),'href','http://'))#等待节点的属性值
- print(result_waitelement.text,result_waittext,result_waitattribute)
新闻 True True
含义 | 返回类型 | |
title_is | 判断title是否出现 | bool |
title_contains | 判断title页面标题是否包含某些字符 | bool |
url_contains | 判断当前url是否包含某个url | bool |
url_matches | 判断当前url是否符合某种格式 | bool |
presence_of_element_located | 判断某个元素是否被加载到了dom树里,但是并不代表这个元素可见 | WebElement |
presence_of_all_elements_located | 判断至少有一个元素存在于dom树中,返回所有定位到的元素 | List[WebElement] |
visibility_of_all_elements_located | 判断是否所有元素都在页面中可见 | bool |
visibility_of_element_located | 某个节点可见 | bool |
text_to_be_present_in_element | 判断指定的节点文本值中是否包含了预期的字符串 | bool |
text_to_be_present_in_element_value | 判断指定的节点值中是否包含了预期的字符串 | bool |
text_to_be_present_in_element_attribute | 判断指定节点值中指定属性是否包含预期字符串 | bool |
alert_is_present | 是否出现警告提示框 | bool |
element_to_be_clickable | 按 | bool |
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('https://login.taobao.com/member/login.jhtml')
- time.sleep(40)#手动登录获取cookies
- cookies=driver.get_cookies()
- print(cookies,type(cookies))
- with open('cookies.txt','w',encoding='utf-8') as f:
- json.dump(cookies,f)
- driver=webdriver.Chrome('chromedriver.exe')
- driver.get('https://www.taobao.com/')
- with open(r'./cookies.txt','r',encoding='utf-8') as f:
- cookie_data=json.load(f)
- for item in cookie_data:
- print(item)
- driver.add_cookie(item)
- driver.get('https://www.taobao.com/')
- time.sleep(30)
方法 | 作用 | 返回值 |
get_screenshot_as_png() | 获取当前窗口的屏幕截图作为二进制数据。 | byte |
get_screenshot_as_file() | 将当前窗口的屏幕截图保存到 PNG 图像文件。 | bool |
get_screenshot_as_base64 | 获取当前窗口的屏幕截图作为 base64 编码字符串 | String |
方法 | 作用 | 返回值 |
screenshot_as_png | 获取当前窗口的屏幕截图作为二进制数据。 | byte |
screenshot() | 将当前窗口的屏幕截图保存到 PNG 图像文件。 | bool |
screenshot_as_base64 | 获取当前窗口的屏幕截图作为 base64 编码字符串 | String |
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('https://www.baidu.com')
- driver.get_screenshot_as_file('./screenshot_png/1.png')#默认存储位置在当前同级目录下
- driver.find_element(By.ID,'lg').screenshot('./screenshot_png/2.png')#截取选定的节点图片
很多网站防止被恶意爬虫爬取,对selenium进行检测
- from selenium import webdriver
- from selenium.webdriver.common.by import By
- from selenium.webdriver import ChromeOptions
- from selenium.webdriver.common.action_chains import ActionChains
- from selenium.webdriver.support.ui import WebDriverWait
- from selenium.webdriver.support import expected_conditions as EC
- option=ChromeOptions()
- #设置无头模式
- # option.add_argument('--headless')
- #反屏蔽处理
- #以开发者模式启动调试chrome,可以去掉提示受到自动软件控制,隐藏提示条
- option.add_experimental_option('excludeSwitches',['enable-automation'])
- option.add_experimental_option('useAutomationExtension',False)#去掉提示以开发者模式调用,自动拓展信息
-
- driver = webdriver.Chrome('chromedriver.exe',options=option)
- # 将webdriver属性制为空
- driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{
- 'source':'Object.defineProperty(navigator,"webdriver",{get:()=>undefined})'
- })
- from selenium import webdriver
- from selenium.webdriver import ChromeOptions
- #设置无头模式
- option=ChromeOptions()
- option.add_argument('--headless')
- driver=webdriver.Chrome('chromedriver.exe',options=option)
- driver.get('https://www.baidu.com')
- driver.get_screenshot_as_png('baidu.png')
- from selenium import webdriver
- driver=webdriver.Chrome('./chromedriver.exe')
webdriver.Chrome()实例化WebDrvier的原理如下:
webdriver.py的部分源码
在这个文件中导入了WebDriver类并将WebDriver重命名,追溯WebDriver类可找到如下图的继承关系,WebDriver是继承了RemoteWebDriver类。
下图是webdriverAPI 在 RemoteWebDriver类的调用关系, RemoteWebDriver类的作用是向远程服务器发送命令。
该类初始化了服务器连接对象,并发送执行的标准命令,如源码所示标准命令
在selenium的原理执行图中我们可以知道,其实selenium底层是通过http协议来实现的,但是这些字符串是怎么转化成http请求的呢?
RemoteWebDriver类是调用了RemoteConnect类实现发送http请求的
如下图在RemoteConnect类中的调用关系,在_commands字典中定义了每个命令对应的http请求,而且还是restful风格的,关于restful风格可以参考这篇文章Restful风格及实践_杜小白也想的美的博客-CSDN博客
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.ui import WebDriverWait
- driver=webdriver.Chrome('./chromedriver.exe')
- driver.get('http://www.baidu.com')
- wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间
- #等待节点,返回值是WebElement
- result_waitelement=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t')))
在上面的一段代码中,实现了对cass属性值为mnav c-font-normal c-color-t元素的等待,如果此节点出现在doc元素树中,将此节点返回封装成WebElement对象返回,那这些是如何实现的呢?
查看WebDriver部分源码
- def __init__(
- self,
- driver,
- timeout: float,
- poll_frequency: float = POLL_FREQUENCY,
- ignored_exceptions: typing.Optional[WaitExcTypes] = None,
- ):
-
- :Args:
- - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
- - timeout - Number of seconds before timing out
- - poll_frequency - sleep interval between calls
- By default, it is 0.5 second.
- - ignored_exceptions - iterable structure of exception classes ignored during
- self._driver = driver
- self._timeout = float(timeout)
- def until(self, method, message: str = ""):
- """Calls the method provided with the driver as an argument until the \
- return value does not evaluate to ``False``.
- :param method: callable(WebDriver)
- :param message: optional message for :exc:`TimeoutException`
- :returns: the result of the last call to `method`
- :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs
- """
- screen = None
- stacktrace = None
-
- end_time = time.monotonic() + self._timeout
- while True:
- try:
- value = method(self._driver)
- if value:
- return value
- except self._ignored_exceptions as exc:
- screen = getattr(exc, "screen", None)
- stacktrace = getattr(exc, "stacktrace", None)
- time.sleep(self._poll)
- if time.monotonic() > end_time:
- break
- raise TimeoutException(message, screen, stacktrace)
在until方法中的method(self._driver)实际上使用了闭包将
EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t'))作为内部方法返回,而且还调用了driver对象。
那么什么是EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t'))呢?调用的这个driver对象是干嘛的呢?
源码如下:
- def presence_of_element_located(locator):
- """An expectation for checking that an element is present on the DOM
- of a page. This does not necessarily mean that the element is visible.
- locator - used to find the element
- returns the WebElement once it is located
- """
-
- def _predicate(driver):
- return driver.find_element(*locator)
-
- return _predicate
这个方法调用了driver.find_element()
我们在看下其他等待方法,如:text_to_be_present_in_element
源码如下
- def text_to_be_present_in_element(locator, text_):
- """An expectation for checking if the given text is present in the
- specified element.
- locator, text
- """
-
- def _predicate(driver):
- try:
- element_text = driver.find_element(*locator).text
- return text_ in element_text
- except StaleElementReferenceException:
- return False
-
- return _predicate
它也是调用的drvier.find_element方法,但返回的是bool类型
WaitDriver类实际上调用的是find_element等 WebDriverAPI方法并加入时间等待,一旦在设置的时间内没有找到这个指定元素并抛出超时错误。
感谢你阅读到最后~
期待你的关注、收藏、评论、点赞~
愿我们一起变强
本文仅用于学习交流!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。