selenium01

selenium day01、02

python 3.6.6     
selenium 3.141.0

chrome 99.0.4844.51        
chromedriver 99.0.4844.51

Firefox 98.0.1        
geckodriver v0.30.0

自动化脚本编写原则:LOVE原则
L:Locate,定位
O:Operate,操作
V:Verify,断言
E:Except,异常处理
-------------------------------------
1. 环境准备

    1-1. 安装selenium
        pip install selenium

        pip install 包名 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

        安装成功后,..\Python36\Lib\site-packages里面可看到selenium相关文件,
            执行 pip show selenium 可查看版本,
            使用 from selenium import webdriver 导包时不会报错


    1-2. 安装浏览器及驱动

            不同的浏览器,其内核不同

        Chrome离线下载:https://www.google.cn/chrome/?standalone=1&platform=win64
        Chrome、Firefox驱动下载:https://npm.taobao.org/mirrors/
        (Firefox驱动是geckodriver)

        Firefox下载:https://www.firefox.com.cn/download/
        火狐版本及驱动映射:https://github.com/mozilla/geckodriver/releases/

        将下载好的压缩包解压后chromedriver.exe移动到..\Python36\Scripts文件夹下


2. 前端页面

    打开百度首页,打开F12,使用元素拾取器,标记输入框,可看到元素及CSS样式

        在html标签中,如li表示列表,input表示输入框或按钮,a表示超链接


3. 打开网页

        # 1.导入工具包
        from selenium import webdriver

        # 2.打开浏览器,注意第一个字母大写
        dr = webdriver.Chrome()        # 获取浏览器句柄
        # dr = webdriver.Firefox()

        # 以下是360浏览器
        # options = webdriver.ChromeOptions()
        # options.binary_location = r'D:\Program Files1\360se\360se6\Application\360se.exe'
        # dr = webdriver.Chrome(r'D:\chromedriver.exe', options=options) # 对应驱动的路径        

        # 3.打开被测页面
        url = "https://www.baidu.com"
        dr.get(url)


4.八大元素定位方法 (使用条件是元素及对应属性值要唯一)

    4-1.根据id属性定位:find_element_by_id(id的值),元素及对应属性值可以查看源码搜索

            inputBox = dr.find_element_by_id("kw")    # 定位输入框
            inputBox.send_keys("selenium自动化")        # 模拟键盘输入    
            sBtn = dr.find_element_by_id("su")        # 定位搜索按钮    
            sBtn.click()                            # 点击按钮

    4-2.根据name属性定位:find_element_by_name(name的值)

    4-3.根据class属性定位:find_element_by_class_name(class的值)
            当class有两个值时,(如class="placeholder lowie-bg"),
            输入其中一个唯一的值即可(placeholder 或 lowie-bg)

    4-4.根据超链接文本定位:find_element_by_link_text(超链接文本信息)

    4-5.根据超链接部分文本信息定位:find_element_by_partial_link_text(部分文本信息)

    4-6.根据标签定位:find_element_by_tag_name(标签名称) , 实际较少使用

            #如果有重复属性值,需要定位一组元素:find_elements_by_xxxx ,注意元素的s
                 #注:尽量不用同一种定位方法,容易报错,原因未知

            tags = dr.find_elements_by_tag_name("input")
            print(len(tags),type(tags))
            for ele in tags:
                if ele.get_attribute("id") == "kw":     # 通过获取元素属性值定位
                    ele.send_keys("百度咋回事儿")
            sBtn = dr.find_element_by_id('su') # 换了另一种定位方法,避免出错
            sBtn.click()

    4-7.根据xpath定位:

        4-7-1.根据绝对路径定位:find_element_by_xpath(绝对路径),以 / 开头,实际较少使用

                find_element_by_xpath('/html/body/div[5]/div/span[2]/input')
                    # [5]表示第5个位置的标签

        4-7-2.根据相对路径定位:find_element_by_xpath(相对路径),以 // 开头

            1).根据元素的单个属性定位:find_element_by_xpath('//input[@type="submit"]')

            2).根据元素的多个属性定位:find_element_by_xpath('//*[@name="wd" and @class="s_ipt"]')
                # 标签如果用*表示,代表所有的标签

            3).根据层级+元素属性定位:find_element_by_xpath('//span[1]/input[@id="kw"]')
                # 父子级标签均可加属性值[@...]或位置标记[2],也均可同时加属性值和位置标记,顺序不分先后

            4).根据层级+层级位置定位:find_element_by_xpath('//span[1]/input') 
                # 如果层级标签唯一,位置标记也可不加

            5).根据元素的文本信息定位:find_element_by_xpath('//span[text()="设置"]')
                # 文本信息要输入全部文本,且前面没有@符号

    4-8.根据css定位:find_element_by_css_selector('css的语法')

        1).根据id的属性定位 ('#id')
                # 如id="kw",写成('#kw')

        2).根据class的属性定位:('.class') 或 ('.class1.class2')
                # 如class="s_ipt",写成('.s_ipt')
                # 如class="bg s_btn",括号里面需要写('.bg.s_btn'),中间没有空格

        3).根据id和class之外的属性定位:('[属性]')或('标签[属性]')或('[属性1][属性2]')
                # ('[name="wd"]')            # 不带标签的属性
                # ('input[name="wd"]')        # 带标签的属性
                # ('[name="wd"][id="kw"]')    # 多个属性
                # ('[name="wd"]#kw')        # 多个属性(name和id)
                # ('#kw.s_ipt')             # 多个属性(id和class)

        4).根据层级+属性定位  ('父级 > 子级[属性=值]') 或 ('父级.class > 子级#id')
                # ('span > input')  
                # ('span > input#kw') 
                # ('span.bg.s_ipt_wr.quickdelete-wrap > input')    # span的class属性值有多个
                # ('span[name="goods_id"] > input')


5. 元素定位之By类

    from selenium.webdriver.common.by import By

    find_element_by_id   ------->   find_element(By.ID,'id的属性值')
    find_element_by_name   ----->   find_element(By.NAME,'name的属性值')
    find_element_by_xpath   ----->  find_element(By.XPATH,'xpath语法')
    find_element_by_css_selector--> find_element(By.CSS_SELECTOR,'cs语法')

    find_element(By.CLASS_NAME,"s_ipt")
    find_element(By.TAG_NAME,'标签名称')   # 较少使用
    find_element(By.LINK_TEXT,'文本信息')
    find_element(By.PARTIAL_LINK_TEXT,'部分文本信息')

6. 浏览器元素的操作

    6-1.浏览器的控制

        dr.maximize_window()       最大化浏览器窗口
        dr.set_window_size(a,b)    a、b代表的浏览器的长宽
        dr.current_url             获取当前url
        dr.back()                  后退操作
        dr.forward()               前进操作
        dr.refresh()               模拟F5刷新

    6-2.元素的操作方法

        .click()            点击事件
        .send_keys()        模拟用户输入内容
        .clear()            清空输入框的内容
        .text                获取指定元素的文本信息
        .is_displayed()        判断元素是否在页面显示(肉眼可见的元素才能操作)
                                返回True表示可见,False表示不可见

        .send_keys()        上传文件(该方法上传文件只针对input标签有效)                        
        .get_attribute('属性名称')    获取元素属性的值

        等待: 1) time模块的sleep            强制等待,或固定等待

              2) dr.implicitly_wait()   隐式等待,只对dr(webdriver)开头的操作生效
                # 注:隐式等待中只要页面加载完成就结束等待,隐式等待超时后没有加载完成,
                        就会直接报异常,隐式等待默认为0秒

              3)WebDriverWait()      显式等待,只对某一页面有效,超时报异常,且需要先导包

                from selenium.webdriver.support.wait import WebDriverWait
                # 等待10秒,每0.2秒检查一次数据
                inputBox = WebDriverWait(dr,10,0.2).until(lambda dr:dr.find_element_by_id("kw"))
                  
                  from selenium.webdriver.support import expected_conditions as EC
                # 显式等待结合expected_conditions使用,visibility_of_element_located()判断元素是否可见
                inputBox = WebDriverWait(dr,10,0.2).until(EC.visibility_of_element_located((By.ID,"kw")))
                inputBox.send_keys(888)    

                  # 注: 显式等待,WebDriverWait可与expected_conditions结合使用,
                      详见:https://blog.csdn.net/sinat_41774836/article/details/88965281


                  总结: 
                      1.强制等待,不建议用这种等待方法,严重影响代码的执行速度    
                      2.隐式等待,程序会一直等待整个页面加载完成,直到超时。
                          有时候我需要的那个元素早就加载完成了,只是页面上有个别其他元素加载特别慢,
                          仍要等待页面全部加载完成才能执行下一步
                      3.显式等待,程序每隔xx秒看一眼,如果条件成立了,则执行下一步,
                          否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException

    6-3. 其他操作方法

        1) submit()  提交表单,模拟回车键的操作

        2) 鼠标悬停、动作生效:
                from selenium.webdriver import ActionChains  # 导包
                move_to_element()  将鼠标移动到对应的元素   
                perform()   执行所有ActionChains中存储的行为,即让悬停的动作生效

              例:找到百度首页的“更多”,鼠标移过去展开“更多”
                from selenium.webdriver import ActionChains    # 导包
                moreBtn = dr.find_element_by_name('tj_briicon')  # 定位首页的“更多”元素
                ActionChains(dr).move_to_element(moreBtn).perform() # 移动鼠标到“更多”并展开

        3)多表单切换: 
            dr.switch_to.frame()    # 切换表单
            dr.switch_to.default_content()  # 切回默认表单(最外层表单)

            某些页面(如https://mail.163.com/)采用了iframe页面嵌套,即HTML里面嵌套了另一个HTML,
                元素定位方法默认定位外层的HTML,如果定位里面的HTML,需要进行表单切换。

          例:在网易邮箱的用户名输入内容
                email = 'https://mail.163.com/'
                dr.get(email)
                frame = dr.find_element_by_xpath('//div[@id="loginDiv"]/iframe') # 定位iframe
                dr.switch_to.frame(frame)   # 切换到表单2
                username = dr.find_element_by_name('email')
                username.send_keys('iframe定位')

            如果表单1里面有并列的表单2和表单3,多表单切换顺序为:
                默认表单1 → 表单2 → 默认表单1 → 表单3 

            切回默认表单: 
                dr.switch_to.default_content()  # 切回默认表单1
                dr.switch_to.frame(表单3)    # 切换到表单3

        4)窗口切换
            windows = dr.window_handles   # 获取所有打开的窗口
            # print(len(windows))  # 打印列表长度
            dr.switch_to.window(windows[1])  # 切换到第2个窗口(取列表第2个元素)

        5)关闭窗口
            dr.close()  #关闭当前窗口, 若关闭多个窗口,需要先切换窗口
            dr.quit()   #关闭所有窗口,退出驱动

day 02-----------------------------------------------------------------------------

        6)警告框处理
            页面上有些弹框无法定位,在WebDriver 中处理JavaScript 所生成的网页告警信息
            可以使用switch_to.alert方法

            # dr.switch_to.alert.text          #获取警告框文本信息
            # dr.switch_to.alert.accept()    #点击警告框的确认按钮
            # dr.switch_to.alert.dismiss()   #点击警告框的取消按钮

          例如:百度首页的右上角设置-搜索设置-保存设置后出现的弹框
            element = dr.find_element_by_css_selector('#s-usersetting-top') #定位“设置”
            ActionChains(dr).move_to_element(element).perform() #鼠标悬停(需要先导包)
            time.sleep(0.5)
            setting = dr.find_element_by_css_selector('.setpref')  #定位“搜索设置”
            setting.click()
            saveSetting = dr.find_element_by_link_text('保存设置') #定位“保存设置”
            saveSetting.click()
            text = dr.switch_to.alert.text    #获取警告框文本信息
            print(text)
            time.sleep(0.5)
            dr.switch_to.alert.accept()    #点击警告框的确认按钮

        7)下拉框元素定位
            某些页面(如http://sahitest.com/demo/selectTest.htm)需要选择下拉框指定值

                from selenium.webdriver.support.select import Select    # 先导包
                Select(element).select_by_index(下标)         根据索引定位,从0开始
                Select(element).select_by_value("value的值")    根据value属性的值定位
                Select(element).select_by_visible_text("文本信息")    根据文本信息定位

          例如:定位页面最后一个下拉框,分别选择Cell Phone、Fax、Mail
            from selenium.webdriver.support.select import Select    # 先导包
            url = "http://sahitest.com/demo/selectTest.htm"
            dr.get(url)
            lastList = dr.find_element_by_css_selector("#s1")  # 定位最后一个下拉框
            time.sleep(2)
            Select(lastList).select_by_index(2) # 根据索引定位
            time.sleep(2)
            Select(lastList).select_by_value("49")  # 根据value属性的值定位
            time.sleep(2)
            Select(lastList).select_by_visible_text("Mail") # 根据文本信息定位
            
        8)键盘事件Keys类

            from selenium.webdriver.common.keys import Keys     # 先导包
            inputBox = dr.find_element_by_css_selector("#kw")
            inputBox.send_keys("自动化测试")
            time.sleep(2)
            inputBox.send_keys(Keys.BACKSPACE)        # 模拟键盘 删除键 backspace
            # inputBox.send_keys(Keys.BACK_SPACE)    # 模拟删除键的另一种写法
            time.sleep(2)
            inputBox.send_keys(Keys.CONTROL,"a")    # 模拟键盘 复制键 Ctrl + A
            time.sleep(2)
            inputBox.send_keys(Keys.CONTROL,"x")    # 模拟键盘 剪切键 Ctrl + X
            time.sleep(2)
            inputBox.send_keys(Keys.CONTROL,"v")    # 模拟键盘 粘贴键 Ctrl + V
            time.sleep(2)
            inputBox.send_keys(Keys.ENTER)            # 模拟键盘 回车键 Enter    


    6-4. 浏览器元素操作之进阶篇

            在某些特殊情况下,浏览器的元素是无法被定位,或无法被操作的,比如浏览器的滚动条,
            或元素具有readonly属性,我们需要使用稍微有难度一点的定位方法---调用js脚本进行定位。
            js语句末尾最好加上分号(不加也可)

        1)滚动条处理

            taobao = 'https://www.taobao.com/'
            dr.get(taobao)
            time.sleep(2)
            location1 = 'window.scrollTo(0,700);'   # 定位到(0,700)
            dr.execute_script(location1)           # 执行定位
            time.sleep(2)
            location2 = "window.scrollTo(0,300);"   # 定位到(0,300)
            dr.execute_script(location2)


        2)js定位(较少使用,不要求掌握)
            除了id是定位到的单个element元素对象,其它的都是elements返回的是list对象。
                (注意后面的s)

          例如:打开百度首页后,进行元素定位

            # 1.根据id定位:定位到输入框,并输入内容
            inputBox1 = 'document.getElementById("kw").value="juzi01";'
            dr.execute_script(inputBox1)
            time.sleep(1)

            # 2.根据class定位:定位到输入框,并输入内容 (注意返回的是list,选取第1个)
            inputBox2 = 'document.getElementsByClassName("s_ipt")[0].value="juzi02"'
            dr.execute_script(inputBox2)
            time.sleep(1)

            # 3.根据name定位:定位到输入框,并输入内容 (注意返回的是list,选取第1个)
            inputBox3 = 'document.getElementsByName("wd")[0].value="juzi03";'
            dr.execute_script(inputBox3)
            time.sleep(1)

            # 4.根据标签名称定位(很少使用):定位到输入框,并输入内容 (注意选取list第8个标签)
            inputBox4 = 'document.getElementsByTagName("input")[7].value="juzi04";'
            dr.execute_script(inputBox4)
            time.sleep(1)

            # 5.根据css定位:定位到搜索按钮,并点击
            sBtn = 'document.querySelectorAll("#su")[0].click();'
            dr.execute_script(sBtn)

        3) jQuery定位,跟css_selector定位很像,实际工作中应用较少。

            注:整个$(...)都可以放到console里面运行,查看length的值不为0,表示定位到了

            # 1.根据id定位
            inputBox = '$("#kw").val("自动化测试");'
            dr.execute_script(inputBox)
            
            # 2.根据class定位
            inputBox2 = '$(".s_ipt").val("自动化测试2");'
            dr.execute_script(inputBox2)
            
            # 3.根据其他属性定位:使用的是css语法
            inputBox3 = '$("input[name=wd]").val("自动化测试3");'
            dr.execute_script(inputBox3)
            
            # 4.根据层次+属性定位
            inputBox4 = '$("span > input[id=kw]").val("自动化测试4");'
            # inputBox4 = '$("span > #kw").val("自动化测试44");'
            dr.execute_script(inputBox4)
            # 注:如果input标签有个属性是type="text",可以写成$("span > input:text")
            
            # 5.根据标签索引定位: 标签名:eq(index)  ,index指的是索引位
            inputBox5 = '$("span > input:eq(0)").val("自动化测试5");' # 找到第1个input标签
            dr.execute_script(inputBox5)
            
            # 6.根据标签顺序定位: 标签名:nth-child(n) ,n指的是同一层级下的第n个元素
            # inputBox6 = '$("span > input:nth-child(2)").val("自动化测试6");' # 找到第2个元素
            # inputBox6 = '$(".bg > input:nth-child(2)").val("自动化测试66");' # 找到第2个元素
            inputBox6 = '$("span.bg > input:nth-child(2)").val("自动化测试666");' # 找到第2个元素
            dr.execute_script(inputBox6)
            
            # 7.根据标签名和顺序定位: 标签名p:nth-of-type(n),n指的是同一层级下的标签名为p的第n个元素
            # inputBox7 = '$("span.bg>input#kw:nth-of-type(1)").val("自动化测试7");'  # 找到第1个input
            inputBox7 = '$("span.bg.s_ipt_wr>input:nth-of-type(1)").val("自动化测试7");'  # 找到第1个input
            dr.execute_script(inputBox7)
            
            # 8.根据指定层级的最后一个标签定位: 标签名p:last,在指定层级定位最后一个标签p
            inputBox8 = '$(".bg.s_ipt_wr > input:last").val("自动化测试8")'
            dr.execute_script(inputBox8)
            
        4) 对元素属性增删改操作

            如百度首页的图片上传图标,标签为 <span class="soutu-btn"></span>,修改静态页面的图标不显示,
            只需要对标签加个style属性即可,即<span class="soutu-btn" style="display:none;"></span>,
            其中,style="display:none;"表示隐藏该元素,style="display:block;"表示显示该元素。


            # 例如操作百度首页的图片上传图标,根据js定位的css语法定位到图标,
                先增加元素属性,然后修改,最后再移除属性

            # 1.在静态页面中,添加元素属性并设为隐藏(style="display:none;)
            time.sleep(2)
            soutu = 'document.querySelectorAll(".soutu-btn")[0].setAttribute("style","display:none");'
            dr.execute_script(soutu)

            # 2.在静态页面中,修改元素属性为显示(style="display:block;)
            time.sleep(2)
            soutu2 = 'document.querySelectorAll(".soutu-btn")[0].style="display:block";'
            dr.execute_script(soutu2)

            # 3.在静态页面中,修改元素属性为隐藏(style="display:none;)
            time.sleep(2)
            soutu3 = 'document.querySelectorAll(".soutu-btn")[0].style="display:none";'
            dr.execute_script(soutu3)

            # 4.在静态页面中,移除元素属性style
            time.sleep(2)
            soutu4 = 'document.querySelectorAll(".soutu-btn")[0].removeAttribute("style");'
            dr.execute_script(soutu4)


        5) 删除readonly属性

            若元素包含readonly属性,无法直接操作,需要调用JS脚本把readonly属性删掉。

            例如某电商平台新增活动时,活动开始、结束时间需要把readonly属性删除

            import time
            from datetime import date, timedelta  #导包一般放在前面

            ecshop = 'http://192.168.0.134/ecshop/admin'
            dr.get(ecshop)
            username = dr.find_element_by_xpath('//input[@name="username"]')
            username.send_keys('admin')
            password = dr.find_element_by_xpath('//input[@name="password"]')
            password.send_keys('admin123')
            btn = dr.find_element_by_xpath('//input[@type="submit"]')
            btn.click()

            activity = dr.find_element_by_css_selector('#menu-frame')  #定位到iframe表单A
            dr.switch_to.frame(activity)  #切换到表单A
            time.sleep(1)
            duoBao = dr.find_element_by_link_text('夺宝奇兵')
            time.sleep(1)
            duoBao.click()
            dr.switch_to.default_content()  #切回默认表单
            activity = dr.find_element_by_css_selector('#main-frame')  #定位到iframe表单B
            dr.switch_to.frame(activity)  #切换到表单B
            duoBaoAdd = dr.find_element_by_xpath('//span[@class="action-span"]/a')
            time.sleep(1)
            duoBaoAdd.click()
            activityName = dr.find_element_by_xpath('//input[@name="snatch_name"]')
            activityName.send_keys('这是夺宝活动名称啊')   #填写活动名称
            goodsKeys = dr.find_element_by_css_selector('input[value=" 搜索 "]')
            goodsKeys.click()
            activityDesc = dr.find_element_by_css_selector('textarea[name="desc"]')
            activityDesc.send_keys('这是活动描述啊')  #填写活动描述

            # 移除活动开始时间的readonly属性
            js = '''document.querySelectorAll('[name="start_time"]')[0].removeAttribute("readonly")'''
            # js = "document.querySelectorAll('#start_time_id')[0].removeAttribute('readonly')"  #也可使用id定位
            dr.execute_script(js)
            startTime = dr.find_element_by_css_selector('[name="start_time"]')
            startTime.clear()
            now = time.strftime('%Y-%m-%d %H:%M')  #当前日期、时间,如果加上秒就是 :%S
            startTime.send_keys(now)

            # 移除活动结束时间的readonly属性
            js = "document.getElementById('end_time_id').removeAttribute('readonly')"
            dr.execute_script(js)
            endTime = dr.find_element_by_id('end_time_id')
            endTime.clear()

            end = date.today() + timedelta(10)   #日期是当前日期加10天
            end2 = str(end) + ' 23:59'   #日期转换成字符串格式,再拼接上具体时间
            endTime.send_keys(end2)
            save = dr.find_element_by_xpath('//input[@value=" 确定 "]') #定位保存按钮
            save.click()

            #等待一秒钟后获取页面代码,并保存在ecShop.html文件中
            time.sleep(1)
            # res = dr.page_source
            # print(res)
            # with open('ecshop.html','w+',encoding='utf-8') as f:
            #     f.write(res)

            #断言
            actualResult = '添加成功'
            resultPage = dr.find_element_by_xpath('//tbody/tr/td[2]').text
            # if resultPage == actualResult:
            if actualResult in resultPage :
                print('pass')
            else:
                print('fail')


pip install sshtunnel报错,尝试升级pip


元素定位失败的原因:
1.页面元素未加载完成
2.元素属性值不是唯一的
3.元素属性值是动态变化的
4.元素不在同一个表单中


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值