• Class 17


    利用Selenium 可以驱动浏览器执行特定的动作,如点击、下拉等操作, 同时还可以获取浏览器当前呈现的页面的源代码 ,做到可见即可爬。

    1. 基本使用
      • 示例:
        from selenium import webdriver
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys
        from selenium.webdriver.support import expected_conditions as EC
        from selenium.webdriver.support.wait import WebDriverWait
        browser = webdriver.Chrome()
        try:
            browser.get('https://www.baidu.com')
            input = browser.find_element_by_id('kw')
            input.send_keys('Python')
            input.send_keys(Keys.ENTER)
            wait = WebDriverWait(browser,10)
            wait.until(EC.presence_of_element_located((By.ID,'content_left')))
            print(browser.current_url)
            print(browser.get_cookies())
            print(browser.page_source)
        finally:
            browser.close()

        运行代码后,会自动弹出一个 Chrome 浏览器。首先会跳转到百度,然后在搜索框中输入 Python,接着跳转到搜索页。  搜索结果加载出来后,控制台分别会输出当前的 URL 、当前的 Cookies 和网页源代码.

      • 如果用 Selenium 来驱动浏览器加载网页的话,就可以直接拿到 JavaScript 渲染的结果,不用担心使用的是什么加密系统。声明浏览器对象  

    2. 声明浏览器对象
      • Selenium 支持非常多浏览器,如 Chrome/ Firefox/ Edge等,还有 Android 等手机端的浏览器,也支持无界面浏览器 PhantomJS。
        • 初始化方式:
          from selenium import webdriver
          browser = webdriver.Chrome()
          browser = webdriver.Firefox()
          browser = webdriver.Edge()
          browser = webdriver.PhantomJS()
          browser = webdriver.Safari()

          浏览器对象的初始化并将其赋值为 browser对象。接下来,就是调用 browser 对象,让其执行各个动作以模拟浏览器操作

    3. 访问页面
      • 用 get()方法来请求网页,参数传入链接 URL 即可。如用 get()方法访问淘宝, 然后输出源代码,代码:
        from selenium import webdriver
        browser = webdriver.Chrome()
        browser.get('https://www.taobao.com/')
        print(browser.page_source)

        弹出了 Chrome 浏览器并且自动访问了淘宝,然后控制台输出了淘宝页面的源代码, 随后浏览器关闭。可以实现浏览器的驱动并获取网页源码

    4. 查找节点
      • Selenium 可以驱动浏览器完成各种操作,如填充表单、模拟点击等。Selenium 提供了系列查找节点的方法,我们可以用这些方法来获取想要的节点,以便执行一些动作或者提取信息。
      1. 单个节点
        • 如,要从淘宝页面中提取搜索框这个节点,观察源代码(它的 id 是 q, name 也是q。此时就可以用多种方式获取它。如,find_element_by_name()是根据 name 值获取,find element_by_id()是根据 id 获取。 还有根据 XPath、css 选择器等获取的方式):
          from selenium import webdriver
          browser = webdriver.Chrome()
          browser.get('https://www.taobao.com')
          input_first = browser.find_element_by_id('q')
          input_second = browser.find_element_by_xpath('//*[@id ="q"]')
          input_third = browser.find_element_by_css_selector('#q')
          print(input_first, input_second, input_third)
          browser.close()

          这里使用 3 种方式获取输入框,分别根据 ID, CSS 选择器和 XPath 获取,它们返回的结果完全一致。

        • 列出所有获取单个节点的方法:
          • find_element_by_id
          • find_element_by_name
          • 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
        • Selenium 提供了通用方法 find_element (),需要传入两个参数:查找方式 By 和值。就是 find_element_by_id()这种方法的通用函数版本,如 find_element_by_id(id )等价 find_element(By.ID, id),得到的结果完全一致。代码:
          from selenium import webdriver
          from selenium.webdriver.common.by import By
          
          browser = webdriver.Chrome()
          browser.get('https://www.taobao.com')
          input_first = browser.find_element(By.ID, 'q')
          print(input_first)
          browser.close()

          查找方式的功能与上面列举函数一致,参数更加灵活。

      2. 多个节点
        • 如果有多个节点,用 find_element()方法查找,就只能得到第一个节点。如果要查找所有满足条件的节点, 需要用 find_elements()方法。注意,这个方法名称中,element 多了一个s 
          • 查找淘宝侧边导航条的所有条目:
            from selenium import webdriver
            browser = webdriver.Chrome()
            browser.get('https://www.taobao.com')
            lis = browser.find_elements_by_css_selector('.service-bd li')
            print(lis)
            browser.close()

            得到的内容变成了列表类型,列表中的每个节点都是 WebElement 类型。

            如果用 find_element()方法,只能获取匹配的第一个节点,结果是 WebElement类型。如果用 find_elements()方法,结果是列表类型,列表中的每个节点是 WebElement 类型。
            • 列出所有获取多个节点的方法:
            • find_elements_by_id
            • find_elements_by_name
            • find_elements_by_xpath
            • find_elements_by_link_text
            • find_elements_by_tag_name
            • find_elements_by_class_name
            • find_elements_by_css_selector
          • 也可以直接用 find_elements()方法来选择,可以这样写,结果是完全一致的:
            •  lis = browser.find_elements(By.CSS_SELECTOR, ’.service-bd li')  
    5. 节点互交
      • Selenium 可以让浏览器模拟执行一些动作。常见的用法有:输入文字时用 send_keys()方法,清空文字时用 clear()方法,点击按钮时用 click()方法。示例:
        from selenium import webdriver
        import time
        browser = webdriver.Chrome()
        browser.get('https://www.taobao.com')
        input = browser.find_element_by_id('q')
        input.send_keys('iPhone')
        time.sleep(1)
        input.clear()
        input.send_keys('iPad')
        button = browser.find_element_by_class_name('btn-search')
        button.click()

        首先驱动浏览器打开淘宝,用 find_element_by_id()方法获取输入框,再用 send_keys() 方法输入 iPhone 文字,等待秒后用 clear()方法清空输入框,再次调用 send_keys()方法输入 iPad 文字,之后再 find_element_by_class_name()方法获取搜索按钮,最后调用 click ()方法完成搜索动作。

      • 更多的操作参见官方文档交互动作介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement。

    6. 动作链
      • 动作链 没有特定的执行对象,如:鼠标拖曳、键盘按键等。
      • 如:现在实现一个节点的拖曳操作,将某个节点从一处拖曳到另外一处,实现代码:
        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

        打开网页中一个拖曳实例,依次选中要拖曳的节点和拖曳到的目标节点,接着声明 ActionChains 对象并将其赋值为 actions 变量,然后调用 actions 变量的 drag_and_drop()方法,再调 perform()方法执行动作。

      • 更多动作链操作 官方文档:http://selenium-python.readthedocs.io/api.html#moduleselenium.webdriver.common.action_chains
    7. 执行JavaScript
      • 某些操作,Selenium API 并没有提供。如,下拉进度条,它可以直接模拟运行 JavaScript,此时使用 execute_script()方法即可实现,(注意:execute_script)
        from selenium import webdriver
        
        browser = webdriver.Chrome()
        browser.get('https://www.zhihu.com/explore')
        browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
        browser.execute_script('alert("To Bottom")')
    8. 获取节点信息
      • 通过 page_source 属性可以获取网页的源代码,接着使用解析库(如正则表式、Beautiful Soup、pyquery 等)提取信息。 
      • 获取属性
        • 可以使用 get_attribute ()方法来获取节点的属性,但是其前提是先选中这个节点,示例:
          from selenium import webdriver
          browser = webdriver.Chrome()
          url = 'https://zhihu.com/explore'
          browser.get(url)
          logo = browser.find_element_by_id('zh-top-link-logo')
          print(logo)
          print(logo.get_attribute('class'))

          结果获取知乎的 logo 节点,最后打印出它的 class。

          通过 get_attribute()方法,然后传人想要获取的属性名,就可以得到它的值了
      • 获取文本值
        • 每个 WebElement 节点都有 text 属性,直接调用这个属性就可以得到节点内部的文本信息,相当于 Beautiful Soup 的 get_text()方法、 pyquery 的 text()方法。示例:
          from selenium import webdriver
          browser = webdriver.Chrome()
          url = 'https://www.zhihu.com/explore'
          browser.get(url)
          input = browser.find_element_by_class_name('zu-top-add-question')
          print(input.text)
      • 获取id、位置、标签名和大小
        • Web Element 节点还有 些其他属性,如 id 属性可以获取节点 id,location 属性可以获取该节点在页面中的相对位置,tag_name 属性可以获取标签名称,size 属性可以获取节点的大小(宽高),示例:
          from selenium import webdriver
          browser =webdriver.Chrome()
          url = 'https://www.zhihu.com/explore'
          browser.get(url)
          input = browser.find_element_by_class_name('zu-top-add-question')
          print(input.text)
          print(input.id)
          print(input.location)
          print(input.size)
          print(input.tag_name)

          首先获得“提问”按钮节点,再调用其 id、location、tag_name、size 属性来获取对应的属性值

    9. 切换Frame

      • 网页中有种节点叫作 iframe也就是子 Frame,相当于页面的子页面,它的结构和外部网页的结构完全一致。Selenium 打开页面后,默认在父级 Frame 里面操作,而此时如果页面中还有子Frame,是不能获取到子 Frame 里面的节点的。这时就需要使用 switch_to.frame()方法来切换Frame。示例:

        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')
        try:
            logo = browser.find_element_by_class_name('logo')
        except NoSuchElementException:
            print('NO LOGO')
        browser.switch_to.parent_frame()
        logo = browser.find_element_by_class_name('logo')
        print(logo)
        print(logo.text)

        以前面动作链操作的网页例,首先通过 switch_to.frame()方法切换到子 Frame 里,再尝试获取父级 Frame 里的 logo 节点(这是不能找到的),如果找不到的话,就会抛出 NoSuchEle entException 异常,异常被捕捉之后,就会输出 NO LOGO。接下来,重新切换父级 Frame, 然后再次重新获取节点,发现此时可以成功获取了。 

        当页面中包含子 Frame 时,如果想获取子 Frame 中的节点,需要先调用 switch_to.frame() 方法切换到对应的 Frame,再进行操作。  
    10. 延时等待
      • Selenium 中, get()方法会在网页框架加载结束后结束执行,此时如果获取 page_source ,可能并不是浏览器完全加载完成的页面,某些页面有额外的 Ajax 请求,在网页惊代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。
        • 延时等待方式有两种:隐式等待和显式等待
      • 隐式等待
        • 使用隐式等待执行测试的时候,如果 Selenium 没有在 DOM 中找到节点,将继续等待,超出设定时间后(默认时间为 0 ),则抛出找不到节点的异常。示例:
          from selenium import webdriver
          browser = webdriver.Chrome()
          browser.implicitly_wait(10)
          browser.get('https://www.zhihu.com/explore')
          input = browser.find_element_by_class_name('zu-top-add-question')
          print(input)

          用 implicitly_wait()方法实现隐式等待。

      • 显式等待
        • 指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点, 则抛出超时异常。示例:
          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,10)
          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)

          首先引人 WebDriverWait 对象,指定最长等待时间,调用 until()方法,传人要等待条件 expected_conditions。如:传入 presence_of_element_located 条件,代表节点出出现意思,参数是节点的定位元组,也就是 ID 为 q 的节点搜索框

          效果:在 10 秒内如果 ID 为 q的节点(搜索框)成功加载出来,就返回该节点;如果超过 10 秒还没有加载出来,就抛出异常。
          • 对于按钮,更改一下等待条件,如改为 element_to_be_clickable,也就是可点击,所以找按钮时查找 CSS 选择器为 .btn_search 的按钮,如果 10 秒内它是可点击的,也就是成功加载,返回这个按钮节点;如果超过 10 秒还不可点击,就抛出异常.
            • 等待条件,如判断标题内容,判断某个节点内是否出现了某文字。等待条件:
            • title_is:标题是某内容
            • title_contains: 标题包含某内容
            • presence_of_element_located:节点加载出来,传入定位元组,如(By.ID,‘q’)
            • visibility_of_element_located:节点课件,传入定位元组
            • visibility_of:可见,传入节点对象
            • presence_of_all_elements_ilocated:所有节点加载出来
            • text_to_be_present_in_element:某个节点文本包含某文字
            • text_to_be_present_in_element_value:某个节点值包含某文字
            • frame_to_be_available_and_switch_to_it:加载并切换
            • invisibility_of_element_located:节点不可见
            • element_to_be_clickable:节点可点击
            • staleness_of:判断一个节点是否仍在DOM,可判断页面是否已经刷新
            • element_to_be_selected:节点可选择,传节点对象
            • element_located_to_be_selected:节点可选择,传入定位元组
            • element_election_state_to_be:传入节点对象以及状态,相等返回True,否则返回False
            • element_located_selection_state_to_be:传入定位元组。以及状态,相等返回True,否则返回False
            • alert_is_present:是否出现警告
          • 更多等待条件的参数及用法,参考官方文档: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions。
    11. 前进和后退
      • Selenium 可以完成前进和后退操作,它使用 back()方法后退,使用 forward()方法前进。示例:
        import time
        from selenium import webdriver
        
        browser = webdriver.Chrome()
        browser.get('https://www.baidu.com/')
        browser.get('https://www.taobao.com/')
        browser.get('https://www.python.org/')
        browser.back()
        time.sleep(1)
        browser.forward()
        browser.close()

        连续访问3个页面,调用 back()方法回到第二个页面,再调用 forward()方法前进到第 3个页面。

    12. Cookies
      • Selenium 可以方便地对 Cookies 进行 获取、添加、删除等。示例:
        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': 'germey'})
        print(browser.get_cookies())
        browser.delete_all_cookies()
        print(browser.get_cookies())

        访问知乎,加载完成后,浏览器已经生成 Cookies。调用 get_cookies() 方法获取所有的 Cookies。然后,添加一个 Cookie,传入一个字典,有name、domain、value内容。再次获取所有 Cookies。结果就多了新加的 Cookie。调用 delete_all_cookies()方法删除所有 Cookies。再重新获取,结果就为空了。

    13. 选项卡管理
      • 访问网页时候,会开启一个个选项卡。Selenium 中,也可以对选项卡进行操作。示例:
        import time
        from selenium import webdriver
        
        browser = webdriver.Chrome()
        browser.get('https://www.baidu.com')
        browser.execute_script('window.open()')
        print(browser.window_handles)
        browser.switch_to_window(browser.window_handles[1])
        browser.get('https://www.taobap.com')
        time.sleep(1)
        browser.switch_to_window(browser.window_handles[0])
        browser.get('https://python.org')

        首先访问百度,然后调用 execute_script()方法,传入 window.open()这个 JavaScript 语句新开启一个选项卡。接下来,想切换到该选项卡,调用 window_handles 属性获取当前开启的所有选项卡,返回的是选项卡的代号列表。要想切换选项卡,只需要调用 switch_to_window()方法即可,其中参数是选项卡的代号。将第二个选项卡代号传人,即跳转到第二个选项卡,接下来在第二个选项卡下打开一个新页面,然后切换回第一个选项卡重新调用 switch_to_window()方法,再执行其他操作。

    14. 异常处理
      • 在使用 Selenium 过程中,可以使用 try except 语句来捕获各种异常。(模拟节点未找到异常)示例:
        from selenium import webdriver
        browser = webdriver.Chrome()
        browser.get('https://www.baidu.com')
        browser.find_element_by_id('hello')

        首先打开百度页面,尝试选择一个并不存在的节点 ,此时就会遇到异常。捕获异常示例:

        from selenium import webdriver
        from selenium.common.exceptions import TimeoutException, NoSuchElementException
        
        browser = webdriver.Chrome()
        try:
            browser.get('https://www.baidu.com')
        except TimeoutException:
            print('Timeout')
        try:
            browser.find_element_by_id('hello')
        except NoSuchElementException:
            print('No Element')
        finally:
            browser.close()

        这里使用 try except 来捕获各类异常。如,对 find_element_by_id()查找节点方法捕获 NoSuchElementException 异常,一旦出现这样的错误,就进行异常处理,程序也不会中断。

      • 更多异常类,参考官方文档 http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions。
  • 相关阅读:
    models F Q查询
    Django models 多对多 操作
    Cookies与session的区别
    Form表单验证
    图片上传
    Django进阶
    sql 单个字段去重查询 distinc 和 group by的效率问题
    Django知识点整理
    Web应用请求和响应 HTTP相关
    Django中的几种重定向方式
  • 原文地址:https://www.cnblogs.com/Mack-Yang/p/10184662.html
Copyright © 2020-2023  润新知