zoukankan      html  css  js  c++  java
  • selenium

    一、什么是Selenium

    selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。Selenium的核心Selenium Core基于JsUnit,完全由JavaScript编写,因此可以用于任何支持JavaScript的浏览器上。

    selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。

    二、selenium基本使用

    用python写爬虫的时候,主要用的是selenium的Webdriver,我们可以通过下面的方式先看看Selenium.Webdriver支持哪些浏览器

    执行结果如下,从结果中我们也可以看出基本山支持了常见的所有浏览器:

    这里要说一下比较重要的PhantomJS,PhantomJS是一个而基于WebKit的服务端JavaScript API,支持Web而不需要浏览器支持,其快速、原生支持各种Web标准:Dom处理,CSS选择器,JSON等等。PhantomJS可以用用于页面自动化、网络监测、网页截屏,以及无界面测试

    声明浏览器对象

    上面我们知道了selenium支持很多的浏览器,但是如果想要声明并调用浏览器则需要:

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser = webdriver.Firefox()

    这里只写了两个例子,当然了其他的支持的浏览器都可以通过这种方式调用

    访问页面

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    
    browser.get("http://www.baidu.com") # 打开链接
    browser.save_screenshot('screenshot.png') #屏幕截图
    print(browser.page_source) #获取JS渲染后的源代码
    browser.close() #关闭

    查找元素

    单个元素查找

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    
    browser.get("http://www.taobao.com")
    input_first = browser.find_element_by_id("q") #通过id
    input_second = browser.find_element_by_css_selector("#q") #通过css选择器
    input_third = browser.find_element_by_xpath('//*[@id="q"]') #通过xpath
    print(input_first)
    print(input_second)
    print(input_third)
    browser.close()

    这里我们通过三种不同的方式去获取响应的元素,第一种是通过id的方式,第二个中是CSS选择器,第三种是xpath选择器,结果都是相同的。
    结果如下:

    这里列举一下常用的查找元素方法:

    find_element_by_name
    find_element_by_id
    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

    下面这种方式是比较通用的一种方式:这里需要记住By模块所以需要导入
    from selenium.webdriver.common.by import By

    from selenium import webdriver
    
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    
    browser.get("http://www.taobao.com")
    input_first = browser.find_element(By.ID,"q")
    print(input_first)
    browser.close()

    多个元素查找

    其实多个元素和单个元素的区别,举个例子:find_elements,单个元素是find_element,其他使用上没什么区别,通过其中的一个例子演示:

    from selenium import webdriver
    
    
    browser = webdriver.Chrome()
    browser.get("http://www.taobao.com")
    lis = browser.find_elements_by_css_selector('.service-bd li')
    print(lis)
    browser.close()

    这样获得就是一个列表

    当然上面的方式也是可以通过导入from selenium.webdriver.common.by import By 这种方式实现

    lis = browser.find_elements(By.CSS_SELECTOR,'.service-bd li')

    同样的在单个元素中查找的方法在多个元素查找中同样存在:
    find_elements_by_name
    find_elements_by_id
    find_elements_by_xpath
    find_elements_by_link_text
    find_elements_by_partial_link_text
    find_elements_by_tag_name
    find_elements_by_class_name
    find_elements_by_css_selector

    元素交互操作

    对于获取的元素调用交互方法

    from selenium import webdriver
    
    import time
    
    browser = webdriver.Chrome()
    browser.get("http://www.taobao.com")
    input_str = browser.find_element_by_id('q')
    input_str.send_keys("ipad")
    time.sleep(1)
    input_str.clear()
    input_str.send_keys("MakBook pro")
    button = browser.find_element_by_class_name('btn-search')
    button.click()

    运行的结果可以看出程序会自动打开Chrome浏览器并打开淘宝输入ipad,然后删除,重新输入MakBook pro,并点击搜索

    Selenium所有的api文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

    交互动作

    将动作附加到动作链中串行执行

    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提供的方法
    
    click(on_element=None)                    #单击鼠标左键
    
    click_and_hold(on_element=None)    #点击鼠标左键,按住不放
    
    context_click(on_element=None)           #点击鼠标右键
    
    double_click(on_element=None)            #双击鼠标左键
    
    drag_and_drop(source,target)              #拖拽到某个元素然后松开
    
    drag_and_drop_by_offset(source,xoffset, yoffset)#拖拽到某个坐标然后松开
    
    move_by_offset(xoffset,yoffset)             #鼠标移动到距离当前位置(x,y)
    
    move_to_element(to_element)               #鼠标移动到某个元素
    
    move_to_element_with_offset(to_element,xoffset, yoffset) #将鼠标移动到距某个元素多少距离的位置
    
    release(on_element=None)                     #在某个元素位置松开鼠标左键
    
    perform()                                            #执行链中的所有动作

    执行JavaScript

    这是一个非常有用的方法,这里就可以直接调用js方法来实现一些操作,
    下面的例子是通过登录知乎然后通过js翻到页面底部,并弹框提示

    from selenium import webdriver
    browser = webdriver.Chrome()
    browser.get("http://www.zhihu.com/explore")
    browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    browser.execute_script('alert("To Bottom")')

    获取元素属性
    get_attribute('class')

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    url = 'https://www.zhihu.com/explore'
    browser.get(url)
    logo = browser.find_element_by_id('zh-top-link-logo')
    print(logo)
    print(logo.get_attribute('class'))

    获取文本值
    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,位置,标签名
    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.id)
    print(input.location)
    print(input.tag_name)
    print(input.size)

    Frame

    frame相当于独立的网页,如果在父类网frame查找子类的,则必须切换到子类的frame,子类如果查找父类也需要先切换

    这里常用的是switch_to.from()和switch_to.parent_frame()

    实例:登录qq邮箱并发送邮件

    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.wait import WebDriverWait
    
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)
    try:
        driver.get('https://mail.qq.com/')
        driver.maximize_window() #最大化
        driver.switch_to_frame('login_frame') #切换到login_frame
        locator1 = (By.ID,'login_button')
        WebDriverWait(driver,20).until(EC.presence_of_element_located(locator1))
        driver.find_element_by_id('u').clear()
        driver.find_element_by_id('u').send_keys('xxxx')#输入qq账号
        time.sleep(1)
        driver.find_element_by_id('p').send_keys('xxxx')# 输入密码
        time.sleep(1)
        driver.find_element_by_id('login_button').click()#点击登录
        time.sleep(2)
        locator2 = (By.ID,'btlogin')
        WebDriverWait(driver,20).until(EC.presence_of_element_located(locator2))
        driver.find_element_by_id('pp').clear()
        driver.find_element_by_id('pp').send_keys('xxxx')#输入安全密码
        driver.find_element_by_id('btlogin').click()#点击确认
        time.sleep(3)
        locator3 = (By.ID,'composebtn')
        WebDriverWait(driver,20).until(EC.presence_of_element_located(locator3))
        driver.find_element_by_xpath('//*[@id="composebtn"]').click()
        time.sleep(2)
        driver.switch_to_frame('mainFrame')#切到mainFrame
        locator4 = (By.ID,'toAreaCtrl')
        WebDriverWait(driver,20).until(EC.presence_of_element_located(locator4))
        driver.find_element_by_xpath('//*[@id="toAreaCtrl"]/div[2]/input').send_keys('xxxxx')
        time.sleep(1)
        driver.find_element_by_id('subject').send_keys('test')
        time.sleep(1)
        driver.switch_to_frame(driver.find_element_by_tag_name('iframe'))
        driver.find_element_by_xpath('/html/body').send_keys('12345')
        driver.switch_to.parent_frame()#切回父类
        driver.find_element_by_xpath('//*[@id="AttachFrame"]/span/input').click()
        driver.find_element_by_link_text('发送').click()
        locator5 = (By.ID,'sendinfomsg')
        WebDriverWait(driver, 20).until(EC.presence_of_element_located(locator5))
        print(driver.find_element_by_id('sendinfomsg').text)
    except Exception as e:
        print(e)

    实例二:

    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')
    source = browser.find_element_by_css_selector('#draggable')
    print(source)
    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)

    等待

    当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 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)

    显示等待

    指定一个等待条件,并且指定一个最长等待时间,会在这个时间内进行判断是否满足等待条件,如果成立就会立即返回,如果不成立,就会一直等待,直到等待你指定的最长等待时间,如果还是不满足,就会抛出异常,如果满足了就会正常返回

    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')))#等待input标签出现
    button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
    print(input, button)

    上述的例子中的条件:EC.presence_of_element_located()是确认元素是否已经出现了
    EC.element_to_be_clickable()是确认元素是否是可点击的

    常用的判断条件:
    title_is 标题是某内容
    title_contains 标题包含某内容
    presence_of_element_located 元素加载出,传入定位元组,如(By.ID, 'p')
    visibility_of_element_located 元素可见,传入定位元组
    visibility_of 可见,传入元素对象
    presence_of_all_elements_located 所有元素加载出
    text_to_be_present_in_element 某个元素文本包含某文字
    text_to_be_present_in_element_value 某个元素值包含某文字
    frame_to_be_available_and_switch_to_it frame加载并切换
    invisibility_of_element_located 元素不可见
    element_to_be_clickable 元素可点击
    staleness_of 判断一个元素是否仍在DOM,可判断页面是否已经刷新
    element_to_be_selected 元素可选择,传元素对象
    element_located_to_be_selected 元素可选择,传入定位元组
    element_selection_state_to_be 传入元素对象以及状态,相等返回True,否则返回False
    element_located_selection_state_to_be 传入定位元组以及状态,相等返回True,否则返回False
    alert_is_present 是否出现Alert

    更多操作参考:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions

    浏览器的前进和后退

    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()

    cookie操作

    get_cookies()
    delete_all_cookes()
    add_cookie()

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get('https://www.zhihu.com/explore')
    print(browser.get_cookies())#获取cookies
    browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'}) #添加cookies
    print(browser.get_cookies())
    browser.delete_all_cookies() #移除所有cookies
    print(browser.get_cookies())

    小结

    导入webdriver
    from selenium import webdriver
    import time
    
    #要想调用键盘按键操作需要引入keys包
    from selenium.webdriver.common.keys import Keys
    
    driver.get("http://www.baidu.com/")
    
    # 获取css=#u1 > a:nth-child(1)文本内容
    data = driver.find_element_by_css_selector('#u1 > a:nth-child(1)').text
    
    # 打印数据内容
    print(data) # 新闻
    
    # 生成页面快照并保存
    driver.save_screenshot("baidu.png")
    
    # 搜索
    # # id="kw"是百度搜索输入框,输入字符串"长城"
    driver.find_element_by_id('kw').send_keys('长城')
    
    # id="su"是百度搜索按钮,click()是模拟点击
    driver.find_element_by_id('su').click()
    time.sleep(1)
    # 获取新的页面快照
    driver.save_screenshot("长城.png")
    
    # 打印网页渲染后的源代码
    print(driver.page_source)
    
    # 获取当前页面Cookie
    print('cookies: ',driver.get_cookies())
    #
    #ctrl+a全选输入框内容
    driver.find_element_by_id('kw').send_keys(Keys.CONTROL, 'a')
    #ctrl+x剪切输入框内容
    driver.find_element_by_id('kw').send_keys(Keys.CONTROL, 'x')
    #
    #输入框重新输入内容
    driver.find_element_by_id('kw').send_keys('python')
    #
    # 模拟Enter回车键
    driver.find_element_by_id('su').send_keys(Keys.RETURN)
    time.sleep(5)
    # 清空输入框内容
    driver.find_element_by_id('kw').clear()
    #生成新的页面快照
    driver.save_screenshot('python.png')
    #获取当前url
    print(driver.current_url)
    
    driver.quit()
    
    driver.close()

    选项卡管理

    通过执行js命令实现新开选项卡window.open()
    不同的选项卡是存在列表里browser.window_handles
    通过browser.window_handles[0]就可以操作第一个选项卡

    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.taobao.com')
    time.sleep(1)
    browser.switch_to_window(browser.window_handles[0])
    browser.get('https://python.org')

    异常处理

    这里的异常比较复杂,官网的参考地址:
    http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions
    这里只进行简单的演示,查找一个不存在的元素

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

    弹窗处理

    当你触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息方法如下

    alert = driver.switch_to_alert()
    alert.accept()
    print(alert)

    phantomjs介绍

    PhantomJS是一个无界面的,可脚本编程的WebKit浏览器引擎。它原生支持多种web标准:DOM 操作,CSS选择器,JSON,Canvas 以及SVG。

    phantomjs常用配置

    # 引入配置对象DesiredCapabilities
    
    fromselenium.webdriver.common.desired_capabilities import DesiredCapabilities
    
    dcap =dict(DesiredCapabilities.PHANTOMJS)
    
    #从USER_AGENTS列表中随机选一个浏览器头,伪装浏览器
    
    dcap["phantomjs.page.settings.userAgent"]= (random.choice(USER_AGENTS))
    
    # 不载入图片,爬页面速度会快很多
    
    dcap["phantomjs.page.settings.loadImages"]= False
    
    # 设置代理
    
    service_args =['--proxy=127.0.0.1:9999','--proxy-type=socks5']
    
    #打开带配置信息的phantomJS浏览器
    
    driver =webdriver.PhantomJS(phantomjs_driver_path,desired_capabilities=dcap,service_args=service_args)

    填充表单

    我们已经知道了怎样向文本框中输入文字,但是其它的表单元素呢?例如下拉选项卡的的处理可以如下

    首先获取了第一个 select 元素,也就是下拉选项卡。然后轮流设置了 select 选项卡中的每一个 option 选项。你可以看到,这并不是一个非常有效的方法。

    其实 WebDriver 中提供了一个叫 Select 的方法,可以帮助我们完成这些事情。

    如你所见,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。是十分方便的。

    全部取消选择怎么办呢?很简单

    这样便可以取消所有的选择。

    另外我们还可以通过下面的方法获取所有的已选选项。

    这样就相当于模拟点击了 submit 按钮,做到表单提交。

    当然你也可以单独提交某个元素

    方法,WebDriver 会在表单中寻找它所在的表单,如果发现这个元素并没有被表单所包围,那么程序会抛出 NoSuchElementException 的异常。

  • 相关阅读:
    CSS揭秘(六用户体验)
    CSS揭秘(五字体排印)
    CSS揭秘(四视觉效果)
    java split() 使用 . 来分割,转义(“” "|" "*" "+")
    springboot get请求405 Method Not Allowed
    websocket前端消息读取问题
    java解决中文乱码问题(jar包运行时中文返回前端数据或者控制台输出乱码问题)
    解决mysql 允许执行 XA RECOVER语句(atomikos 解决分布式事务报错)
    navicat修改mysql密码
    mybatisplus添加字段填充
  • 原文地址:https://www.cnblogs.com/woaixuexi9999/p/9419863.html
Copyright © 2011-2022 走看看