selenium语法

学习目标

  • 完成web自动化环境搭建
  • 掌握八大元素定位方法
  • 掌握浏览器操作的方法
  • 掌握鼠标键盘操作的方法
  • 掌握获取元素信息操作的方法
  • 掌握下拉框、滚动条、原生弹窗操作的方法
  • 掌握iframe框架、浏览器句柄切换的方法
  • 掌握截图操作的方式
  • 掌握元素等待操作的方式
  • 掌握cookie操作的方式
  • 完成自定义练习

1. 了解自动化测试

自动化测试:由代码程序代替手工操作,完成测试目的

① 优点:

  • 较少的时间内运行更多的测试用例
  • 自动化脚本可以重复运行
  • 减少人为错误
  • 克服手工测试的局限性

② 误区:

  • 自动化测试能完全代替手工测试【×】
  • 自动化测试比手工测试厉害【×】
  • 自动化测试能发现更多的bug【×】
  • 自动化适合所有的项目【×】
需求变更频繁、需求变动太大、时间紧迫的项目不适合进行自动化测试

③ 自动化测试分类

  • web自动化(python+selenium+pytest+POM)
  • app自动化(python+appium+pytest+POM)
  • 接口自动化(python+request+pytest)
  • 单元自动化(白盒测试)

注意:

  • UI自动化是用代码代替手工测试,模拟用户操作界面(访问网页、点击、浏览、输入、数据交互...)
  • 手工功能测试完成后,再写自动化脚本,确保系统已无明显bug,否则代码维护成本会很大
  • 2. web自动化环境准备

    • 下载安装谷歌浏览器(版本不能太低)
    • 下载浏览器驱动
      • 确认当前浏览器的版本
      • 下载驱动:谷歌驱动地址:http://chromedriver.storage.googleapis.com/index.html
      • 解压出exe执行文件,复制粘贴到python根目录下
    • 安装selenium包(建议使用3.14.1版本)

    3. 自动化启动浏览器

                
    from selenium import webdriver
    import time
    
    # 获取浏览器驱动
    driver = webdriver.Chrome()
    
    # 打开指定网页
    driver.get('file:///E:/pagetest/注册A.html')
    
    time.sleep(2)   # 休眠2秒
    driver.quit()   # 退出浏览器驱动
                
            

    4. 八大元素定位方法

    • id:元素的id属性定位
    • name:元素的name属性定位
    • class_name:元素的class属性定位
    • tag_name:元素的标签名称定位
    • link_text:超链接文本定位
    • partial_link_text:部分超链接文本定位
    • css:元素的css选择器路径定位
    • xpath:元素的标签路径定位(xpath路径)

    ①. id定位

                
    '''
    id定位:
    注意事项:
        ①对于html页面来说,原则上id是不允许重复的,应当能够用id定位到唯一元素,但是不排除编码不规范的情况
        ②要使用id定位,要求元素必须要有id属性,id属性不是必填项
    '''
    # 定位元素
    username = driver.find_element_by_id('userA')
    # 操控元素
    username.send_keys('admin')
                
            

    ②. name定位

                
    '''
    name定位:
    注意事项:
        ①对于html页面来说,name允许重复,使用find_element_by_name会定位到第一个满足条件的元素
        ②要使用name定位,要求元素必须要有name属性,name属性不是必填项
    '''
    password = driver.find_element_by_name('passwordA')
    password.send_keys("123456")
                
            

    ③. class_name定位

                
    '''
    class_name定位:
    注意事项:
        ①对于html页面来说,class是允许重复,使用find_element_by_class_name会定位到第一个满足条件的元素
        ②要使用class_name定位,要求元素必须要有class_name属性,class_name属性不是必填项
        ③若一个元素拥有多个class属性,只要任意选择一个class即可
    '''
    tel = driver.find_element_by_class_name('telA')
    tel.send_keys("13282135001")
    
    email = driver.find_element_by_class_name('emailA')
    email.send_keys("888888@qq.com")
                
            

    ④. tag_name定位

                
    '''
    tag_name定位:
    注意事项:
        ①对于html页面来说,标签名会存在大量重复,使用find_element_by_tag_name会定位到第一个满足条件的元素
        ②元素一定会有标签名
    '''
    button = driver.find_element_by_tag_name('button')
    button.click()
                
            

    ⑤. link_text定位

                
    '''
    link_text定位:
    注意事项:
        ①对于html页面来说,超链接文本是允许重复的,使用find_element_by_link_text会定位到第一个满足条件的元素
        ②link_text的文字,是<a>标签内的文本,需要进行完全匹配
    '''
    sina = driver.find_element_by_link_text('新浪')
    sina.click()
    driver.back()   # 回退页面
                
            

    ⑥. partial_link_text定位

                
    '''
    partial_link_text定位:
    注意事项:
        ①对于html页面来说,超链接文本是允许重复的,使用find_element_by_partial_link_text会定位到第一个满足条件的元素
        ②partial_link_text的文字,是<a>标签内的部分文本,需要进行模糊匹配
    '''
    sina_2 = driver.find_element_by_partial_link_text('问 新')
    sina_2.click()
    driver.close()      # 关闭当前页面
                
            

    ⑦. css选择器定位

                
    '''
    css选择器路径:
    注意事项:
        ①css定位是根据css样式的选择器进行定位
        ②可以通过F12复制出selector路径,不需要自己写,但不能完全依赖复制功能
    '''
    username = driver.find_element_by_css_selector('#userA')
    username.send_keys("admin")
    
    email = driver.find_element_by_css_selector('body > div > fieldset > form > p:nth-child(4) > input')
    email.send_keys("8888@qq.com")
                
            

    ⑧. xpath路径定位

                
    '''
    xpath路径定位:
    注意事项:
        ①在XML文档中找元素信息,html也可以看做为xml文件
        ②xpath路径有2种:相对路径 和 绝对路径
        ③可以通过F12复制出xpath路径,不需要自己写,但不能完全依赖
    '''
    pwd = driver.find_element_by_xpath('//*[@id="passwordA"]')
    pwd.send_keys("123")
    
    tel = driver.find_element_by_xpath('/html/body/div/fieldset/form/p[3]/input')
    tel.send_keys("18877772222")
                
            

    5. By语法定位

    原语法:find_element_by_id('userA')

    By语法:find_element(By.ID, 'userA')

    八大定位方法的By语法:

    • id定位:find_element(By.ID, 'userA')
    • name定位:find_element(By.NAME, 'passwordA')
    • class_name定位:find_element(By.CLASS_NAME, 'telA')
    • tag_name定位:find_element(By.TAG_NAME, 'button')
    • link_text定位:find_element(By.LINK_TEXT, '新浪')
    • partial_link_text定位:find_element(By.PARTIAL_LINK_TEXT, '问 新')
    • css定位:find_element(By.CSS_SELECTOR, '#userA')
    • xpath定位:find_element(By.XPATH, '//*[@id="passwordA"]')

    ①. By.ID

                
    from selenium import webdriver
    # 需要额外导入By包
    from selenium.webdriver.common.by import By
    
    # 定位元素
    username = driver.find_element(By.ID, 'userA')
    # 操控元素
    username.send_keys('admin')
                
            

    ②. By.NAME

                
    password = driver.find_element(By.NAME, 'passwordA')
    password.send_keys("123456")
                
            

    ③. By.CLASS_NAME

                
    tel = driver.find_element(By.CLASS_NAME, 'telA')
    tel.send_keys("13282135001")
    
    email = driver.find_element(By.CLASS_NAME, 'emailA')
    email.send_keys("888888@qq.com")
                
            

    ④. By.TAG_NAME

                
    button = driver.find_element(By.TAG_NAME, 'button')
    button.click()
                
            

    ⑤. By.LINK_TEXT

                
    sina = driver.find_element(By.LINK_TEXT, '新浪')
    sina.click()
    driver.back()   # 回退页面
                
            

    ⑥. By.PARTIAL_LINK_TEXT

                
    sina_2 = driver.find_element(By.PARTIAL_LINK_TEXT, '问 新')
    sina_2.click()
    driver.close()      # 关闭当前页面
                
            

    ⑦. By.CSS_SELECTOR

                
    username = driver.find_element(By.CSS_SELECTOR, '#userA')
    username.send_keys("admin")
    
    email = driver.find_element(By.CSS_SELECTOR, 'body > div > fieldset > form > p:nth-child(4) > input')
    email.send_keys("8888@qq.com")
                
            

    ⑧. By.XPATH

                
    pwd = driver.find_element(By.XPATH, '//*[@id="passwordA"]')
    pwd.send_keys("123")
    
    tel = driver.find_element(By.XPATH, '/html/body/div/fieldset/form/p[3]/input')
    tel.send_keys("18877772222")
                
            

    6. 元素生命周期

                
    from selenium import webdriver
    # 需要额外导入By包
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    username = driver.find_element(By.ID, 'userA')          # 第一次定位username
    button = driver.find_element(By.TAG_NAME,'button')      # 定位按钮
    button.click()                                          # 点击按钮,会刷新页面
    username2 = driver.find_element(By.ID, 'userA')         # 第二次定位username
    
    print(username)         # 打印第一次定位的username
    print(username2)        # 打印第二次定位的username,会发现两次打印的编号不一致
    username.send_keys('admin')     # 往第一次定位的username里输入值,会失败
    username2.send_keys('admin')    # 往第二次定位的username里输入值,会成功
    
    driver.close()
                
            

    7. 定位一组元素

    若使用原方法,则将find_element_by_id('userA') 改成 find_elements_by_id('userA')

    若使用By方法,则将find_element(By.ID, 'userA') 改成 find_elements(By.ID, 'userA')

    此时,返回的会是list类型的元素列表,需要使用下标定位具体的某一个元素对象

                
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get("file:///E:/pagetest/注册A.html")
    inputs_1 = driver.find_elements_by_tag_name("input")    # 定位标签名是“input”的所有元素
    inputs_2 = driver.find_elements(By.TAG_NAME, "input")   # 定位标签名是“input”的所有元素
    print(len(inputs_2), inputs_2)          # 打印元素列表的长度,即有多个满足条件的元素
    inputs_2[0].send_keys("123456")         # 使用下标定位某一个元素,才能进行正常元素操作
    inputs_2[1].send_keys("1234567")
    inputs_2[2].send_keys("123456789")
    
    driver.close()
                
            

    8. 浏览器操作

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # -------------------------对浏览器的操作-------------------------
    driver.maximize_window()                # 浏览器窗口最大化
    time.sleep(1)
    driver.set_window_size(500, 300)        # 设置浏览器宽高,单位:像素 px
    time.sleep(1)
    driver.set_window_position(200, 300)    # 设置浏览器坐标位置,单位:像素px
    time.sleep(1)
    driver.back()       # 后退一页
    time.sleep(1)
    driver.forward()    # 前进一页
    time.sleep(1)
    driver.refresh()    # 刷新页面
    time.sleep(1)
    print(driver.title)         # 获取当前页面标题
    print(driver.current_url)   # 获取当前页面url
    driver.close()              # 关闭当前浏览器窗口
    driver.quit()               # 退出浏览器驱动
                
            

    9. 鼠标操作

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # ------------------------------鼠标操作------------------------
    from selenium.webdriver.common.action_chains import ActionChains
    
    action = ActionChains(driver)   # 实例化鼠标操作类
    
    button = driver.find_element_by_tag_name('button')
    button.click()      # 普通的单击操作,不属于【鼠标类】的方法,不实例化鼠标类,也可执行单击操作
    
    username = driver.find_element_by_id('userA')
    username.send_keys("admin")
    action.double_click(username).perform()    # 双击指定的元素,并提交事件
    
    username = driver.find_element_by_id('userA')
    username.send_keys("admin")
    action.context_click(username).perform()     # 在指定元素上右击鼠标,并提交事件
    
    button = driver.find_element_by_tag_name('button')
    action.move_to_element(button).perform()  # 将鼠标移动到指定元素上
    action.move_by_offset(280,465).perform()  # 将鼠标移动到指定坐标xy上
    
    driver.get("file:///E:/pagetest/drag.html")
    red = driver.find_element_by_xpath('//*[@id="div1"]')
    blue = driver.find_element_by_xpath('//*[@id="div2"]')
    action.drag_and_drop(red,blue).perform()    # 将[源元素]移动到[目标元素]上
    time.sleep(1)
    action.drag_and_drop_by_offset(blue, 100, 200).perform()
    # 以当前元素位置为0点,x:正数向右移动 负数向左移   y:正数向下移 负数向上移
    # 注意元素层级关系
                
            

    注意:在同一条用例、同一个执行脚本中,尽量不要重复perform提交

    10. 键盘操作

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # ----------------------键盘操作-------------------------
    from selenium.webdriver.common.keys import Keys
    username = driver.find_element_by_id('userA')
    tel = driver.find_element_by_id('telA')
    
    username.send_keys('admin')
    username.send_keys(Keys.BACK_SPACE)
    time.sleep(1)
    username.send_keys(Keys.SPACE)
    time.sleep(1)
    username.send_keys(Keys.TAB)
    
    username.send_keys(Keys.CONTROL, 'a')
    time.sleep(1)
    username.send_keys(Keys.CONTROL, 'c')
    time.sleep(1)
    tel.send_keys(Keys.CONTROL, 'v')
    time.sleep(1)
    
    tel.clear()
    time.sleep(1)
    driver.close()
                
            

    11. 获取元素信息操作

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # --------------------获取元素信息---------------------
    username = driver.find_element_by_id('userA')
    print(username.size)    # 获取元素尺寸
    
    sina = driver.find_element_by_link_text('新浪')
    print(sina.text)    # 元素内的文本信息
    
    print(username.get_attribute('placeholder'))    # 获取元素的指定属性值
    
    username.send_keys("admin")
    print(username.get_attribute('value'))      # input输入框有默认属性value,即用户的输入/选择的内容
    
    span_1 = driver.find_element_by_xpath('/html/body/div/fieldset/form/p[5]/span')
    print(span_1.is_displayed())    # 判断元素是否可见,可见返回True,不可见返回False
    print(username.is_displayed())
    
    button_1 = driver.find_element_by_css_selector('body > div > fieldset > form > p:nth-child(5) > button')
    button_2 = driver.find_element_by_css_selector('#cancelA')
    print(button_1.is_enabled())    # 判断元素是否可用,可用返回True,不可用返回False
    print(button_2.is_enabled())
    
    pga = driver.find_element_by_id('pga')
    lia = driver.find_element_by_id('lia')
    print(pga.is_selected())    # 判断元素是否被选中,选中返回True,未选中返回False
    print(lia.is_selected())
    
    driver.quit()
                
            

    12. 下拉框操作

    注意:此方法仅适用于原生下拉框操作,目前很多页面上的下拉框是由其他标签+css样式组成的,外表看上去像下拉框,但并非原生下拉框

                
    from selenium import webdriver
    import time
    from selenium.webdriver.support.select import Select
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # 原生下拉框操作
    city = driver.find_element_by_id('selectA')
    select = Select(city)
    select.select_by_index(2)   # 选择下标=2的选项,此处下标从0开始
    time.sleep(1)
    select.select_by_value('sz')    # 选择value值=sz的选项
    time.sleep(1)
    select.select_by_visible_text('北京')     # 选择文本=‘北京’的选项
    time.sleep(1)
    driver.close()
                
            

    13. 滚动条操作

    注意:并非所有页面都支持此操作方式

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # 滚动条操作:
    '''
    selenium没有提供滚动条操作事件,但是提供了js代码运行方法,因此控制滚动条需要先编写js代码,再让selenium运行js
    '''
    # 将滚动条移动到最底部
    js_1 = "window.scrollTo(0,10000)"   # 左边距0,上边距10000
    driver.execute_script(js_1)
    time.sleep(1)
    
    # 将滚动条移动到最上方
    js_2 = "window.scrollTo(0,0)"
    driver.execute_script(js_2)
    time.sleep(1)
    
    # 将滚动条移动到其他位置
    js_3 = "window.scrollTo(0,100)"
    driver.execute_script(js_3)
    time.sleep(1)
    
    driver.close()
                
            

    14. 原生弹窗操作

    注意:此操作方式仅使用于原生弹窗,有部分弹窗是由其他标签+css组成的,并非原生弹窗

                
    from selenium import webdriver
    import time
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    # 原生弹窗处理
    '''
    网页中常见的三种原生弹窗:
        ①alert弹窗:标题、提示文本、【确定】按钮
        ②confirm弹窗:标题、提示文本、【确定】按钮、【取消】按钮
        ③prompt弹窗:标题、提示文本、输入框、【确定】按钮、【取消】按钮
    因为弹窗会影响页面其他元素的操作,所以当弹窗被触发后,应当先处理掉弹窗
    '''
    driver.find_element_by_id('alerta').click()
    time.sleep(1)
    alert = driver.switch_to.alert      # 获取弹窗对象
    print(alert.text)                   # 获取弹窗“提示文本”
    alert.accept()                      # 点击【确定】按钮
    time.sleep(1)
    
    driver.find_element_by_id('confirma').click()
    time.sleep(1)
    confirm = driver.switch_to.alert      # 获取弹窗对象
    print(confirm.text)
    confirm.accept()                      # 点击【确定】按钮
    # confirm.dismiss()                   # 点击【取消】按钮
    
    driver.find_element_by_id('prompta').click()
    time.sleep(1)
    prompt = driver.switch_to.alert      # 获取弹窗对象
    print(prompt.text)
    prompt.send_keys('123456')           # 输入(谷歌浏览器看不到输入的内容)
    prompt.accept()                      # 点击【确定】按钮
    # prompt.dismiss()                   # 点击【取消】按钮
    
    driver.close()
                
            

    15. iframe框架切换

    注意:HTML代码中如果存在iframe框架,相当于是嵌套了另一个页面进来,需要切换框架焦点,才能操作嵌套进来的页面

                
    from selenium import webdriver
    import time
    
    # --------------------页面中的iframe框架切换--------------------
    driver = webdriver.Chrome()
    driver.get("file:///E:/pagetest/注册实例.html")
    
    driver.find_element_by_id('userA').send_keys('admin')   # 定位主页面元素,并输入值
    time.sleep(1)
    frame_A = driver.find_element_by_id('idframe1')         # 定位到A页面的iframe框架
    driver.switch_to.frame(frame_A)                         # 焦点切换至A页面
    driver.find_element_by_id('AuserA').send_keys("adminAAAA")
    time.sleep(1)
    
    driver.switch_to.default_content()                      # 回退到默认主界面,很重要!!!
    
    frame_B = driver.find_element_by_id('idframe2')         # 定位到B页面的iframe框架
    driver.switch_to.frame(frame_B)                         # 焦点切换至B页面
    driver.find_element_by_id('BuserA').send_keys('adminBBBBB')
    time.sleep(1)
    
    driver.close()
                
            

    16. 浏览器句柄切换

    注意:如果操作过程中,弹出了另一个浏览器窗口,则需要切换窗口句柄,才能操作新的浏览器窗口的页面

                
    from selenium import webdriver
    import time
    # ---------------------浏览器窗口切换------------------------
    '''
    句柄:每个浏览器窗口的唯一标识
    '''
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    
    handles = driver.window_handles     # 获取全部句柄
    print(handles)
    
    driver.find_element_by_id('fw').click()
    
    handles = driver.window_handles     # 获取全部句柄
    print(handles)
    
    driver.switch_to.window(handles[-1])    # 切换到最新的句柄
    handles_1 = driver.current_window_handle    # 获取当前句柄
    print(handles_1)
    
    driver.find_element_by_xpath('/html/body/div[7]/div[1]/div[1]/ul[1]/li[2]/a').click()
    time.sleep(1)
    driver.quit()
                
            

    17. 截图

                
    '''
    窗口截图:把被测系统的当前窗口界面截图,保存到指定目录下,保存成功 返回True,保存失败 返回False
    文件保存路径:
        1.截图的文件名不能包含以下字符:\ / : * ? # " <  > |
        2.可以使用相对路径 或 绝对路径
    '''
    from selenium import webdriver
    import time
    import datetime
    
    driver = webdriver.Chrome()
    driver.get('https://www.baidu.com')
    cur_time = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f')
    print(cur_time)
    driver.get_screenshot_as_file(f'./img/bug{cur_time}.png')      # 相对路径
    # driver.get_screenshot_as_file(r'E:\bug01.png')          # 绝对路径
    time.sleep(1)
    driver.close()
                
            

    18. 隐式等待

                
    # 隐式等待:全局等待,在规定时间内等待页面中所需要的元素,如果超时未加载出元素,则报错
    '''
    如果设置隐式等待时间10s:
        ①10s内元素全部加载完成,会继续执行后续代码
        ②10s后,元素未全部加载完,则报错
        ③如果仅花费6s完成全部元素加载,剩下的4s不再等待
    '''
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    driver.implicitly_wait(10)
    element_1 = driver.find_element_by_xpath('/html/body/div/div[2]/div[1]/input[1]')
    element_2 = driver.find_element_by_xpath('/html/body/div/div[2]/div[1]/input[2]')
    
    driver.quit()
                
            

    19. 显式等待

                
    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    
    driver = webdriver.Chrome()
    driver.get('file:///E:/pagetest/注册A.html')
    # 显式等待:针对单一元素进行等待,如果超时未加载出指定元素,则报错
    '''
    如果设置显式等待时间10s,每0.1s监测一次:
        ①10s内指定元素加载完成,会继续执行后续代码
        ②10s内的每次监测均未找到指定元素,则报错
        ③如果仅花费6s指定元素加载完成,剩下的4s不再等待
    '''
    element_1 = WebDriverWait(driver, 5, 0.1).until(lambda x: x.find_element_by_xpath('/html/body/div/div[2]/div[1]/input[1]'))
    element_2 = WebDriverWait(driver, 10, 0.1).until(lambda x: x.find_element_by_xpath('/html/body/div/div[2]/div[1]/input[2]'))
    
    driver.quit()
                
            

    20. 强制等待

                
    import time
    time.sleep(2)   # 强制等待2s
                
            

    21. cookie操作

    1. cookie操作

    Cookie:一种客户端机制,浏览器第一次访问服务器时,由服务器返回,然后保存在浏览器中。

    项目中常常会使用cookie记录一些不太机密的缓存信息,也常常用来记录登录状态。

                
    '''
    cookie操作目的:以添加cookie的方式,绕过复杂的登录流程
    思路:
        手动登录-->拿到自己有效的用户身份信息cookie-->运行python代码时,将用户身份信息追加到cookie缓存中-->刷新页面
    '''
    import time
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get('https://www.baidu.com')
    driver.maximize_window()
    time.sleep(5)
    baidu = {'name': 'BDUSS', 'value': 's0R1ROWTVQczhLcDZycGlaOGZyWUlkaX5VbXlFOERTYmh1SW5LQn5XRXkxMzFqSUFBQUFBJCQAAAAAAAAAAAEAAACdST5IssWyu8rH0KG6otfTxNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADJKVmMySlZjN2'}
    driver.add_cookie(baidu)
    driver.refresh()
    time.sleep(2)
    driver.quit()
                
            

    自定义练习

    任意选择以下的网站之一,完成自动化练习,编码100行,操作动作不限:

    • 时光钥匙:https://www.shiguangkey.com/
    • CSDN:https://www.csdn.net/
    • 百度:https://www.baidu.com/
    • 哔哩哔哩:https://www.bilibili.com/
    • 京东:https://www.jd.com/