Python and selenium_project articles_project actual combat, code optimization, project refactoring

In actual combat, I just want to say one thing: that is to write use cases that cover basic functions in combination with the project you are currently in. When you encounter a problem, solve a problem, persevere, you will be done.
Background: The code is the process of booking tickets on Ctrip.com.
(1) File directory, each directory code
(2) Code optimization and reconstruction, introduction to the code level framework,
(3) Exception handling, log handling, intelligent waiting

(1) Please see the code:
Insert picture description here
basic code layer function.py

# coding=utf-8
from datetime import datetime,date,timedelta
from selenium import webdriver
import logging,os,xlrd,xlwt
import urllib3

# 以下为driver设置和打开携程火车票网站
# driver = webdriver.Chrome()
'''
函数return_driver()的功能是返回driver对象
'''
def return_driver():
    return driver
'''
函数open_base_site(url)的功能是打开携程火车票首页面
'''
def open_base_site(url):
    driver.get(url)
'''
函数date_n(n)将返回n天后的日期
'''
def date_n(n):
    return str((date.today() + timedelta(days = +int(n))).strftime("%Y-%m-%d"))
'''
函数id将返回按照id属性来定位元素的语句
'''
def id(element):
    return driver.find_element_by_id(element)
'''
函数css将返回css selector方式来定位元素的语句
'''
def css(element):
    return driver.find_element_by_css_selector(element)
'''
函数xpath将返回xpath方式来定位元素的语句
'''
def xpath(element):
    return driver.find_element_by_xpath(element)
'''
函数js通过selenium来执行javascript语句
'''
def js(element):
    driver.execute_script(f"document.getElementById(f'{element}').removeAttribute('readonly')")
'''
函数log()定义了日志的输出格式
'''
def log(str):
    # 日志基础配置
    logging.basicConfig(
        level=logging.INFO, # 定义了日志的输出级别
        datefmt='%a,%d,%b,%Y,%H:%M:%S', # 定义了日志输出的时间格式
        filename='D:\\ui_date\\log-selenium.log', # 定义了日志输出路径文件
        filemode='a', #日志以追加的形式进入log-selenium.log
        format='%(asctime)s%(filename)s%(levelname)s%(message)s' # 定义了日志的输出形式
    )
    # 定义streamhandler格式的日志
    console = logging.StreamHandler()
    # 设置日志格式
    console.setFormatter(logging.INFO)
    console.setFormatter(logging.Formatter('%(name)-12s:%(levelname)-8s %(message)s'))
    # 给日志添加定义后的handler
    logging.getLogger('').addHandler(console)
    logging.info(str)
'''
函数read_excel是输出第几列的内容,如果不给cloumn的值,默认是以列表的形式输出所有内容
filename:文件路径一直到文件
index:索引值第几页
cloumn:第几列
'''
def read_excel(filename,index,cloumn):
    # 打开excel文件,filename是绝对路径或者相对路径下的文件
    xls = xlrd.open_workbook(filename)
    # 打开第几个sheet页
    sheet = xls.sheet_by_index(index)
    # print(sheet.nrows) 行
    # print(sheet.ncols) 列
    # 内容以字典的形式输出,不给cloum值,默认是输出所有表哥的所有内容
    dic={
    
    }
    for j in range(sheet.ncols):
        date=[]
        for i in range(sheet.nrows):
            date.append(sheet.row_values(i)[j])
        dic[j]=date
    return dic

if __name__ == "__main__":
    logging.log(logging.DEBUG,"我是dbug级别的")
    logging.log(logging.INFO,"我是info级别的")
    logging.log(logging.WARNING,"我是warning级别的")
    logging.log(logging.ERROR,"我是error级别的")
    logging.log(logging.CRITICAL,"我是critical级别的")

Business code layer search_tickets.py

'''
此页面的功能是测试火车票查询的页面元素
'''
from selenium.webdriver.common.action_chains import ActionChains
from functions import date_n,id,css,xpath,js,return_driver,open_base_site
from selenium import webdriver
import time

'''
函数名:search_tickets
参数:
    from_station:出发站
    to_station:到达站
    n:是一个数字,如1表示选择明天的车票,2表示选择后天的车票
'''
def search_tickets(from_station,to_station,n):
    driver = return_driver()
    open_base_site('https://trains.ctrip.com/')
    driver.maximize_window()
    driver.implicitly_wait(10)

    # from_station = '上海'
    from_station = from_station
    # to_station = '杭州'
    to_station = to_station

    # 以下为tommorrow变量
    tomorrow = date_n(n)
    # 以下为定位出发城市和到达城市的页面元素,设置其值为以上定义值
    css('[placeholder="出发城市"]').send_keys(from_station)
    id("arriveCityName").send_keys(to_station)

    # 移除出发时间的“readonly”属性
    js("date0bj")
    time.sleep(2)

    # 清除出发时间的默认值
    id('dateObj').clear()
    time.sleep(2)

    # 以下定位为搜索车次日期
    id('dateObj').send_keys(tomorrow)

    # 以下步骤是为了解决日期控件弹出框在输入日期后无法消失的问题,以防影响测试的进行,原理是鼠标点击空白处
    ActionChains(driver).move_by_offset(0,0).click().perform()

    # 单击“车次搜索”按钮
    id('searchbtn').click()

# 实例化类,run才有结果
if __name__ == '__main__':
    search_tickets("上海","杭州",1)

Test code layer test_booking_tickets.py

import time
from functions import date_n,id,css,xpath,js,return_driver,open_base_site
from search_tickets import search_tickets

# 搜索网站火车票列表
search_tickets("上海","杭州",1)
driver = return_driver()
time.sleep(2)
# 点击预订按钮
xpath("/html/body/div[7]/div/div[5]/div[3]/div/div[1]/div[6]/div[1]/a").click()
# 输入乘客姓名
css('[placeholder="姓名,请与所持证件上的一致"]').send_keys("小张")

(2) Code optimization and refactoring
Code optimization has 2 points:
1. Reduce the amount of code, increase reuse rate, improve robustness (in the case of big data), readability, and expandability.
2. Improve code readability and heavy code The structure can be implemented with a defined function. Such as:

# coding=utf-8
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys

# 定义函数部分,减少代码量的且提高复用率,如果定义函数的部分必须放在测试代码前面。
def id(element):
    return driver.find_element_by_id(element)
def css(element):
    return driver.find_element_by_css_selector(element)
def xpath(element):
    return driver.find_element_by_xpath(element)
def js(element):
    return driver.execute_script("document.getElementById(" + "'" + element + "'" + ").removeAttribute('readonly')")

driver = webdriver.Chrome()
driver.get("https://www.hao123.com/")
driver.maximize_window()
# 百度网站的id值
id("kw").click()
css([adsads="sdfs"]).click()

Code refactoring
As the code increases, functions and test codes are put in one file, which is difficult to expand and maintain. Therefore, add variables to the function appropriately and avoid hard coding. The ultimate goal is to make the test code more concise and clearer.
The project code is divided into a three-tier structure: the code structure and ideas need to be well planned in the initial stage of automation, and the code will become larger and larger in the later stage.
1. Test code layer
2. Business code layer
3. Basic code layer

Basic code layer: encapsulates the related configuration of selenium and webdriviver, such as the content of function.py

# coding=utf-8
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys

# 定义函数部分,减少代码量的且提高复用率
# coding=utf-8
from selenium import webdriver
import time

# 以下为driver设置和打开测试网站
driver = webdriver.Chrome()

# def return_driver():
#     return driver
# 打开网页
# def open_base_site(url):
#     driver.get(url)

# 定义函数部分,减少代码量的且提高复用率
def id(element):
    return driver.find_element_by_id(element)
def css(element):
    return driver.find_element_by_css_selector(element)
def xpath(element):
    return driver.find_element_by_xpath(element)
def js(element):
    return driver.execute_script("document.getElementById(" + "'" + element + "'" + ").removeAttribute('readonly')")

Business code layer:

"""
函数名:lang
参数:
    a是url
    b是用户名
    c是密码
"""
def land(a,b,c):
    driver = webdriver.Chrome()
    driver.get(f"{a}")
    driver.find_element_by_id("kw").send_keys(f"{b}")
    driver.find_element_by_id('mn').send_keys(f"{c}")
    driver.find_element_by_id('submit').click()
    time.sleep(1)
    driver.maximize_window()

Test code layer:

实现了测试用例。

The so-called refactoring and optimization means that as the project progresses, we need to change the basic code layer and business code layer so that our test code layer can be better carried out.

1. Exception handling
1. Selenium exception handling, refer to the exception handling of interface automation, that is very good, the common exceptions are as follows:

# coding=utf-8
import selenium
import logging

# 操作数据库的方法
class OperationDbInterface(object):
    # 初始化数据库连接
    def __int__(self, a):
        try:
            if 0 == 0:
                pass
            else:
                print("i")
            # 打开游标
            print("ok")
        except error as e:
            print('创建数据库失败|Mysql Error %d: %s' % (e.args[0], e.args[1]))
            # 配置日志格式
            logging.basicConfig(filename=config.src_path + 'E:/log/syserror.log', level=logging.DEBUG,
                                format='%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s %(message)s')
            # 获取日志
            logger = logging.getLogger(__name__)
            # 输出日志
            logger.exception(e)
            
# selenium常见的9种异常。
# (1)NoSuchElementException:选择器返回元素失败时,抛出异常
# (2)ElementNotVisibleException:定位的元素在DOM中存在,在页面不显示,不能交互时
# (3)ElementNotSelectableException:选择了不可选的元素
# (4)NoSuchFrameException:要切换的frmae不存在
# (5)NoSuchWindowException:要切换的新窗口不存在
# (6)TimeoutException:当代码执行时间超出时
# (7)NoSuchAttributeException:元素的属性找不到
# (8)UnexpectedTagNameException:当支持类没有获得预期的web元素时
# (9)NoAlertPresentException:一个意外的警告

Two, a brief introduction to the log module

# coding=utf-8
import logging
'''
函数log()定义了日志的基础配置
'''
def log(str):
    # 日志基础配置
    logging.basicConfig(
        level=logging.INFO, # 定义了日志的输出级别
        datefmt='%a,%d,%b,%Y,%H:%M:%S', # 定义了日志输出的时间格式
        filename='D:\\ui_date\\log-selenium.log', # 定义了日志输出路径文件
        filemode='a', #日志以追加的形式进入log-selenium.log
        format='%(asctime)s%(filename)s%(levelname)s%(message)s' # 定义了日志的输出形式
    )
    # 定义streamhandler格式的日志
    console = logging.StreamHandler()
    # 设置日志格式
    console.setFormatter(logging.INFO)
    console.setFormatter(logging.Formatter('%(name)-12s:%(levelname)-8s %(message)s'))
    # 给日志添加定义后的handler
    logging.getLogger('').addHandler(console)
    logging.info(str)

if __name__ == "__main__":
    logging.log(logging.DEBUG,"我是dbug级别的")
    logging.log(logging.INFO,"我是info级别的")
    logging.log(logging.WARNING,"我是warning级别的")
    logging.log(logging.ERROR,"我是error级别的")
    logging.log(logging.CRITICAL,"我是critical级别的")

3. Intelligent waiting
Because it is too troublesome to add the waiting time before each positioning element operation, so add the global intelligent waiting time: driver.implicitly_wait(10)
means: among all positioning operations, the browser waits the most 10 seconds, more than 10 seconds will report an error

# coding=utf-8
from selenium import webdriver
import time
from selenium.common import exceptions as ex

driver = webdriver.Chrome()
driver.get("https://www.hao123.com/")
driver.maximize_window()
driver.implicitly_wait(10)

Guess you like

Origin blog.csdn.net/weixin_45451320/article/details/112585768