当前位置:   article > 正文

python爬虫——selenium_python selenium

python selenium

目录

一、背景​编辑

1.1、selenium的发展

1.2、在爬虫中的应用

1.3selenium执行原理图

1.4、WebDriver,与WebElement

二、准备​编辑

2.1、下载驱动

2.2、安装Selenium库

2.3、简单使用

三、实用操作​编辑

3.1、查找节点

3.1.1、查找元素在网页中的位置(网址为www.baidu.com,代码中的注释很详细)

3.1.2、实现方法

​编辑

3.1.3、实现代码

3.2、获取节点属性,文本

3.3、节点交互

3.3.1、实现代码

3.3.2、实现效果​编辑​

3.3.3、常用交互操作

3.4、显示等待

3.4.1、等待页面元素

3.4.2、实现代码

3.4.3、等待条件

3.5、Cookie

3.5.1、获取cookies

2.5.2、携带cookies

3.5.3、实现效果​编辑​

3.6、截屏

3.6.1、WebDriver对象实现截屏方法

3.6.2、WebElement对象实现截屏方法

3.6.3、实现代码

3.6.4、实现效果​编辑​

3.7、反检测

3.7.1、适用场景

3.7.2、相关代码

3.8、设置无头

四、源码分析​编辑​

4.1、WebDriver的实例化源码探究

继承关系图

4.2、WebDrvierAPI原理探究

WebDrvierAPI在RemoteWebDrvier类的调用图

问题

解答

4.3、WebDriverWait的源码探究

问题

解答

总结



一、背景

1.1、selenium的发展

        Selenium最初是由Jason Huggins测试工程师为减少手工测试量做的基于JavaScript语言的代码库(这时是通过js注入的方式操作),之后不断的发展完善并合并了WebDrive项目,使之可以直接调用浏览器和操作系统内置的方法,解决了JavaScript环境的沙盒限制,发展成了现在我们经常使用的Selenium WebDriver。现在的selenium就像百度百科说的一样,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

1.2、在爬虫中的应用

      在爬取数据的时候,我们通常可以使用requests库,但是如果遇到加密的网站,就需要js逆向,相当复杂。但是我们还有一种方法,那就是使用自动化工具,实现可见即可爬,完成JavaScript动态渲染页面。

1.3selenium执行原理图

1.4、WebDriver,与WebElement

       WebDriver的核心是是一个浏览器驱动程序,他负责启动浏览器,并将控制权交个程序,同时还提供了API,直接使用并控制浏览器的内置对象,可以使用它来模拟用户的行为,如点击提交,填写文本框,键入网址等。

       WebElement表示 DOM 元素。 通常,所有与指定元素交互的操作都将通过此接口执行。如:如点击提交,填写文本框,键入网址,还包括获取文本属性等,这是不是很熟悉,原来WebElement属于WebDrvierAPI;它可以对指定网页元素进行操作。

       总结

WebElement属于WebDriver API,通常使用于对指定可见元素进行操作,一般的实现如下:通过WebDriverAPI提供的方法(如:find_element())进行元素定位并返回WebElement对象,再调用此对象对指定元素进行操作。

     

二、准备

2.1、下载驱动

查看浏览器版本,下载对应驱动,相关驱动的下载链接如下

Chrome驱动:chromedriver.storage.googleapis.com/index.html

Firefox驱动:Releases · mozilla/geckodriver (github.com)

Edge驱动:Microsoft Edge WebDriver - Microsoft Edge Developer

2.2、安装Selenium

pip install selenium

2.3、简单使用

  1. from selenium import webdriver
  2. import time
  3. driver=webdriver.Chrome('./chromedriver.exe')#初始化WebDriver对象
  4. driver.get('https://www.baidu.com')#访问百度
  5. time.sleep(20)

Chrome的参数有很多,在这里我们初始化时传入的是executable_path,代表驱动的位置

驱动文件我放在了与代码同级目录下

三、实用操作

3.1、查找节点

3.1.1、查找元素在网页中的位置(网址为www.baidu.com,代码中的注释很详细)

3.1.2、实现方法

方法作用参数说明
find_element得到首个被匹配的节点

By参数——By.ID通过标签ID属性匹配,By.CSS_SELECTOR,使用CSS选择器进行定位匹配,By.Name通过属性名进行匹配

Value参数——匹配的属性值

find_elements得到所有被匹配的节点,返回值为WebElement元素列表同上

3.1.3、实现代码

  1. from selenium import webdriver
  2. from selenium.webdriver.common.by import By
  3. import time
  4. driver=webdriver.Chrome('./chromedriver.exe')
  5. driver.get('http://www.baidu.com')
  6. #css选择器进行筛选
  7. #如果有多个元素被匹配,find_element只会获取第一个
  8. result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
  9. print(result,'\n','---------------')
  10. #匹配多个find_elements
  11. result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
  12. for item in result_list:
  13. print(item)
  14. print('---------------')
  15. result_byid=driver.find_element(by=By.NAME,value='tj_more')
  16. print(result_byid)
  1. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="bd760d4c-a045-4316-b398-7cb4ae7b6f6e")>
  2. ---------------
  3. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="bd760d4c-a045-4316-b398-7cb4ae7b6f6e")>
  4. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="4c25b06b-8dd5-4da7-b362-43965f389102")>
  5. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="43406d63-edea-4a7b-b2d2-307a7ad16714")>
  6. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="c3434610-4579-4f43-9d42-42837dc8b151")>
  7. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="fb6d11ff-f87b-4993-bad0-b35876e85c46")>
  8. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="d8388d32-f732-488b-8b15-92a003c2a217")>
  9. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="e8b99605-50d0-4679-9ef6-4a708d4d8ec8")>
  10. ---------------
  11. <selenium.webdriver.remote.webelement.WebElement (session="695c760a0bf340402875429f56903178", element="e448b794-6c02-4683-8225-25a2d647d28d")>

3.2、获取节点属性,文本

  1. driver=webdriver.Chrome('./chromedriver.exe')
  2. driver.get('http://www.baidu.com')
  3. result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
  4. print(result.text,result.get_attribute('href'),'\n','------------------------------------')
  5. result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t')
  6. for item in result_list:
  7. print(item.text,item.get_attribute('href'))
  8. print('---------------------------------')
  9. #webdriver只与可见元素交互,如果该元素被隐藏,将不会被获取文本值,但是属性仍可获取到,可通过is_displayed()进行查看
  10. result_byid=driver.find_element(by=By.NAME,value='tj_more')
  11. print({'text':result_byid.text,'href':result_byid.get_attribute('href')})
  12. print(result_byid.is_displayed())
  1. 新闻 http://news.baidu.com/
  2. ------------------------------------
  3. 新闻 http://news.baidu.com/
  4. hao123 https://www.hao123.com/?src=from_pc
  5. 地图 http://map.baidu.com/
  6. 贴吧 http://tieba.baidu.com/
  7. 视频 https://haokan.baidu.com/?sfrom=baidu-top
  8. 图片 http://image.baidu.com/
  9. 网盘 https://pan.baidu.com/?from=1026962h
  10. ---------------------------------
  11. {'text': '', 'href': 'http://www.baidu.com/more/'}
  12. False

3.3、节点交互

3.3.1、实现代码

  1. from selenium import webdriver
  2. import time
  3. driver=webdriver.Chrome('./chromedriver.exe')
  4. driver.get('https://www.baidu.com')
  5. web_element=driver.find_element(By.CSS_SELECTOR,'.s_ipt')
  6. web_element.send_keys('张三')
  7. driver.find_element(By.CSS_SELECTOR,'[id="su"]').click()
  8. time.sleep(100)

3.3.2、实现效果

3.3.3、常用交互操作

操作含义
click()点击按钮
sendkeys()输入到单选框
clear()清空输入框

3.4、显示等待

3.4.1、等待页面元素

3.4.2、实现代码

  1. from selenium.webdriver.support import expected_conditions as EC
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. driver=webdriver.Chrome('./chromedriver.exe')
  5. driver.get('http://www.baidu.com')
  6. wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间
  7. #等待节点,返回值是WebElement
  8. result_waitelement=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t')))
  9. #等待节点并判断某个节点是否满足条件,返回值是bool类型
  10. result_waittext=wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'mnav'), '新闻'))#等待节点包含的文本值
  11. result_waitattribute=wait.until(EC.text_to_be_present_in_element_attribute((By.CLASS_NAME,'mnav'),'href','http://'))#等待节点的属性值
  12. print(result_waitelement.text,result_waittext,result_waitattribute)
新闻 True True

3.4.3、等待条件

含义返回类型
title_is判断title是否出现bool
title_contains判断title页面标题是否包含某些字符bool
url_contains判断当前url是否包含某个urlbool
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_clickablebool

3.5.1、获取cookies

  1. driver=webdriver.Chrome('./chromedriver.exe')
  2. driver.get('https://login.taobao.com/member/login.jhtml')
  3. time.sleep(40)#手动登录获取cookies
  4. cookies=driver.get_cookies()
  5. print(cookies,type(cookies))
  6. with open('cookies.txt','w',encoding='utf-8') as f:
  7. json.dump(cookies,f)

2.5.2、携带cookies

  1. driver=webdriver.Chrome('chromedriver.exe')
  2. driver.get('https://www.taobao.com/')
  3. with open(r'./cookies.txt','r',encoding='utf-8') as f:
  4. cookie_data=json.load(f)
  5. for item in cookie_data:
  6. print(item)
  7. driver.add_cookie(item)
  8. driver.get('https://www.taobao.com/')
  9. time.sleep(30)

3.5.3、实现效果

3.6、截屏

3.6.1、WebDriver对象实现截屏方法

方法作用返回值
get_screenshot_as_png()获取当前窗口的屏幕截图作为二进制数据。byte
get_screenshot_as_file()将当前窗口的屏幕截图保存到 PNG 图像文件。bool
get_screenshot_as_base64获取当前窗口的屏幕截图作为 base64 编码字符串String

3.6.2、WebElement对象实现截屏方法

方法作用返回值
screenshot_as_png获取当前窗口的屏幕截图作为二进制数据。byte
screenshot()将当前窗口的屏幕截图保存到 PNG 图像文件。bool
screenshot_as_base64获取当前窗口的屏幕截图作为 base64 编码字符串String

3.6.3、实现代码

  1. driver=webdriver.Chrome('./chromedriver.exe')
  2. driver.get('https://www.baidu.com')
  3. driver.get_screenshot_as_file('./screenshot_png/1.png')#默认存储位置在当前同级目录下
  4. driver.find_element(By.ID,'lg').screenshot('./screenshot_png/2.png')#截取选定的节点图片

3.6.4、实现效果

3.7、反检测

3.7.1、适用场景

很多网站防止被恶意爬虫爬取,对selenium进行检测

3.7.2、相关代码

  1. from selenium import webdriver
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver import ChromeOptions
  4. from selenium.webdriver.common.action_chains import ActionChains
  5. from selenium.webdriver.support.ui import WebDriverWait
  6. from selenium.webdriver.support import expected_conditions as EC
  7. option=ChromeOptions()
  8. #设置无头模式
  9. # option.add_argument('--headless')
  10. #反屏蔽处理
  11. #以开发者模式启动调试chrome,可以去掉提示受到自动软件控制,隐藏提示条
  12. option.add_experimental_option('excludeSwitches',['enable-automation'])
  13. option.add_experimental_option('useAutomationExtension',False)#去掉提示以开发者模式调用,自动拓展信息
  14. driver = webdriver.Chrome('chromedriver.exe',options=option)
  15. # 将webdriver属性制为空
  16. driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{
  17. 'source':'Object.defineProperty(navigator,"webdriver",{get:()=>undefined})'
  18. })

3.8、设置无头

  1. from selenium import webdriver
  2. from selenium.webdriver import ChromeOptions
  3. #设置无头模式
  4. option=ChromeOptions()
  5. option.add_argument('--headless')
  6. driver=webdriver.Chrome('chromedriver.exe',options=option)
  7. driver.get('https://www.baidu.com')
  8. driver.get_screenshot_as_png('baidu.png')

四、源码分析

4.1、WebDriver的实例化源码探究

  1. from selenium import webdriver
  2. driver=webdriver.Chrome('./chromedriver.exe')

webdriver.Chrome()实例化WebDrvier的原理如下:

webdriver.py的部分源码

在这个文件中导入了WebDriver类并将WebDriver重命名,追溯WebDriver类可找到如下图的继承关系,WebDriver是继承了RemoteWebDriver类。

继承关系图

4.2、WebDrvierAPI原理探究

下图是webdriverAPI 在 RemoteWebDriver类的调用关系, RemoteWebDriver类的作用是向远程服务器发送命令。

WebDrvierAPI在RemoteWebDrvier类的调用图

 该类初始化了服务器连接对象,并发送执行的标准命令,如源码所示标准命令

问题

在selenium的原理执行图中我们可以知道,其实selenium底层是通过http协议来实现的,但是这些字符串是怎么转化成http请求的呢?

解答

RemoteWebDriver类是调用了RemoteConnect类实现发送http请求的

如下图在RemoteConnect类中的调用关系,在_commands字典中定义了每个命令对应的http请求,而且还是restful风格的,关于restful风格可以参考这篇文章Restful风格及实践_杜小白也想的美的博客-CSDN博客

 

4.3、WebDriverWait的源码探究

  1. from selenium.webdriver.support import expected_conditions as EC
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. driver=webdriver.Chrome('./chromedriver.exe')
  5. driver.get('http://www.baidu.com')
  6. wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间
  7. #等待节点,返回值是WebElement
  8. 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部分源码

  1. def __init__(
  2. self,
  3. driver,
  4. timeout: float,
  5. poll_frequency: float = POLL_FREQUENCY,
  6. ignored_exceptions: typing.Optional[WaitExcTypes] = None,
  7. ):
  8. :Args:
  9. - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
  10. - timeout - Number of seconds before timing out
  11. - poll_frequency - sleep interval between calls
  12. By default, it is 0.5 second.
  13. - ignored_exceptions - iterable structure of exception classes ignored during
  14. self._driver = driver
  15. self._timeout = float(timeout)
  16. def until(self, method, message: str = ""):
  17. """Calls the method provided with the driver as an argument until the \
  18. return value does not evaluate to ``False``.
  19. :param method: callable(WebDriver)
  20. :param message: optional message for :exc:`TimeoutException`
  21. :returns: the result of the last call to `method`
  22. :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs
  23. """
  24. screen = None
  25. stacktrace = None
  26. end_time = time.monotonic() + self._timeout
  27. while True:
  28. try:
  29. value = method(self._driver)
  30. if value:
  31. return value
  32. except self._ignored_exceptions as exc:
  33. screen = getattr(exc, "screen", None)
  34. stacktrace = getattr(exc, "stacktrace", None)
  35. time.sleep(self._poll)
  36. if time.monotonic() > end_time:
  37. break
  38. 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对象是干嘛的呢?

解答

源码如下:

  1. def presence_of_element_located(locator):
  2. """An expectation for checking that an element is present on the DOM
  3. of a page. This does not necessarily mean that the element is visible.
  4. locator - used to find the element
  5. returns the WebElement once it is located
  6. """
  7. def _predicate(driver):
  8. return driver.find_element(*locator)
  9. return _predicate

这个方法调用了driver.find_element()

我们在看下其他等待方法,如:text_to_be_present_in_element

源码如下

  1. def text_to_be_present_in_element(locator, text_):
  2. """An expectation for checking if the given text is present in the
  3. specified element.
  4. locator, text
  5. """
  6. def _predicate(driver):
  7. try:
  8. element_text = driver.find_element(*locator).text
  9. return text_ in element_text
  10. except StaleElementReferenceException:
  11. return False
  12. return _predicate

它也是调用的drvier.find_element方法,但返回的是bool类型

总结

WaitDriver类实际上调用的是find_element等 WebDriverAPI方法并加入时间等待,一旦在设置的时间内没有找到这个指定元素并抛出超时错误。

 

​​感谢你阅读到最后~​ 

​​期待你的关注、收藏、评论、点赞~

​​愿我们一起变强

 

本文仅用于学习交流!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/89768
推荐阅读
相关标签
  

闽ICP备14008679号