python爬虫 |
您所在的位置:网站首页 › 篮球南派打法 › python爬虫 |
目录 一、背景 1.1、selenium的发展 1.2、在爬虫中的应用 1.3selenium执行原理图 1.4、WebDriver,与WebElement 二、准备 2.1、下载驱动 2.2、安装Selenium库 2.3、简单使用 三、实用操作 3.1、查找节点 3.1.1、查找元素在网页中的位置 3.1.2、实现代码 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.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的源码探究 问题 解答 总结 一、背景![]() Selenium最初是由Jason Huggins测试工程师为减少手工测试量做的基于JavaScript语言的代码库(这时是通过js注入的方式操作),之后不断的发展完善并合并了WebDrive项目,使之可以直接调用浏览器和操作系统内置的方法,解决了JavaScript环境的沙盒限制,发展成了现在我们经常使用的Selenium WebDriver。现在的selenium就像百度百科说的一样,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。 1.2、在爬虫中的应用在爬取数据的时候,我们通常可以使用requests库,但是如果遇到加密的网站,就需要js逆向,相当复杂。但是我们还有一种方法,那就是使用自动化工具,实现可见即可爬,完成JavaScript动态渲染页面。 1.3selenium执行原理图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 2.2、安装Selenium库 pip install selenium 2.3、简单使用 from selenium import webdriver driver=webdriver.Chrome('./chromedriver.exe')#初始化WebDriver对象 driver.get('https://www.baidu.com')#访问百度 Chrome的参数有很多,在这里我们初始化时传入的是executable_path,代表驱动的位置 驱动文件我放在了与代码同级目录下 ![]() ![]() ![]() ![]() 很多网站防止被恶意爬虫爬取,对selenium进行检测 3.7.2、相关代码 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})' }) 3.8、设置无头 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') 四、源码分析![]() webdriver.Chrome()实例化WebDrvier的原理如下: webdriver.py的部分源码 在这个文件中导入了WebDriver类并将WebDriver重命名,追溯WebDriver类可找到如下图的继承关系,WebDriver是继承了RemoteWebDriver类。 继承关系图下图是webdriverAPI 在 RemoteWebDriver类的调用关系, RemoteWebDriver类的作用是向远程服务器发送命令。 WebDrvierAPI在RemoteWebDrvier类的调用图该类初始化了服务器连接对象,并发送执行的标准命令,如源码所示标准命令 在selenium的原理执行图中我们可以知道,其实selenium底层是通过http协议来实现的,但是这些字符串是怎么转化成http请求的呢? 解答RemoteWebDriver类是调用了RemoteConnect类实现发送http请求的 如下图在RemoteConnect类中的调用关系,在_commands字典中定义了每个命令对应的http请求,而且还是restful风格的,关于restful风格可以参考这篇文章Restful风格及实践_杜小白也想的美的博客-CSDN博客 在上面的一段代码中,实现了对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 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |