Python日志采集(详细)
<p>通常在前期调试代码的时候,我们会使用print在IDE控制台打印一些信息,判断运行情况。但在运行整个自动化测试项目的过程中,通过print打印信息的方式获取运行情况显然行不通。<br>这时就需要收集日志,每次运行后通过查看日志来获取项目运行情况。那么我们该如何获取日志?</p>
<h2 id="一日志概述">一,日志概述</h2>
<h3 id="1日志作用">1,日志作用</h3>
<p>在项目开发或测试过程中,项目运行一旦出现问题,记录日志信息就显得尤为重要。主要通过日志来定位问题,就好比侦探人员要根据现场留下的线索来推断案情。</p>
<h3 id="2日志级别">2,日志级别</h3>
<ul>
<li>
<p>代码在运行的过程中会出现不同的情况,如调试信息、警告信息、报错等,那么采集日志时就需要对这些日志区分级别管理,这样才能更精确地定位问题。日志级别一般分类如下(以严重程度递增排序):</p>
<table>
<thead>
<tr>
<th style="text-align: left"><div style="width: 150px">级别</div></th>
<th><div style="width: 500px">何时使用</div></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">DEBUG</td>
<td>调试信息,也是最详细的日志信息</td>
</tr>
<tr>
<td style="text-align: left">INFO</td>
<td>证明事情按预期工作</td>
</tr>
<tr>
<td style="text-align: left">WARNING</td>
<td>表明发生了一些意外,或不久的将来会发生问题(如 磁盘满了),软件还是正常工作</td>
</tr>
<tr>
<td style="text-align: left">ERROR</td>
<td>由于更严重的问题,软件已经不能执行一些工作了</td>
</tr>
<tr>
<td style="text-align: left">CRITICAL</td>
<td>严重错误,表明软件已经不能继续运行了</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>日志级别排序为:CRITICAL > ERROR > WARNING > INFO > DEBUG</p>
<p>日志采集时设置低级别的日志,能采集到更高级别的日志,但不能采集到更低级别的日志。</p>
<p>例如:设置的日志级别为info级别,就只能采集到info、warning、error、critical级别的日志,不能采集到debug级别的日志。设置的日志级别为debug级别的话则能采集到所有级别的日志。<strong>默认设置级别为WARNING</strong>。</p>
</li>
<li>
<p>在自动化测试项目中,通常在一般情况时使用info日志,预计报错则使用error日志。</p>
</li>
</ul>
<h3 id="3日志格式">3,日志格式</h3>
<p>将日志格式化是为了提高日志的可阅读性,比如:<strong>时间+模块+行数+日志级别+日志具体信息</strong> 的日志格式。如果输出的日志信息杂乱无章,就不利于问题的定位。如下所示就是日志格式化输出,非常便于阅读查看。</p>
<pre><code>2020-09-30 10:45:05,119 logging_test.py DEBUG this is debug message.
2020-09-30 10:45:05,119 logging_test.py INFO this is info message.
2020-09-30 10:45:05,119 logging_test.py WARNING this is warning message.
2020-09-30 10:45:05,120 logging_test.py ERROR this is error message.
2020-09-30 10:45:05,120 logging_test.py CRITICAL this is critical message.
</code></pre>
<h3 id="4日志位置">4,日志位置</h3>
<p>通常,在一个项目中会有很多的日志采集点,日志采集点的设置必须结合业务来确定。</p>
<p>比如在执行修改登录密码用例前插入“开始执行修改登录密码用例...”的日志信息。再比如在登录代码执行前可以插入“准备登录...”日志信息。</p>
<p>如果在登录完成后,再设置登录的提示日志就会给人造成误解,无法判断到底是登录之前的问题还是登录之后的问题,因此日志采集点的位置很重要。</p>
<h2 id="二logging模块">二,logging模块</h2>
<h3 id="1简介">1,简介</h3>
<p>logging为python自带的日志模块,提供了通用的日志系统,包括不同的日志级别。logging可使用不同的方式记录日志,如使用文件,HTTP GET/POST,SMTP,Socket等方式记录。通常情况下,我们使用文件记录日志信息,文件格式一般为.txt或.log文件。</p>
<h3 id="2文档">2,文档</h3>
<p>详细内容可查看logging模块官方文档,使用时需要导入:</p>
<pre><code class="language-python">import logging
</code></pre>
<h2 id="三logging第一种使用方法简单配置使用">三,logging第一种使用方法:简单配置使用</h2>
<h3 id="1使用方法">1,使用方法</h3>
<p>logging.basicConfig(**kwargs)</p>
<h3 id="2basicconfig部分参数说明">2,basicConfig()部分参数说明</h3>
<p><strong>filename</strong> 指定日志名称或完整路径,如:E:/app-ui-autotest/log/log.txt</p>
<p><strong>filemode</strong> 指定打开文件的模式(如果文件打开模式未指定,则默认为'a')</p>
<p>常见的文件读写方式:</p>
<ul>
<li>w 以写的方式打开</li>
<li>W 清空后写入(文件已存在)</li>
<li>r 以读的方式打开</li>
<li>a 以追加模式打开(即在文件原有的数据后面添加)</li>
</ul>
<p><strong>format</strong> 指定日志输出格式</p>
<p><strong>level</strong> 将根记录器级别设置为指定级别</p>
<h3 id="3示例1日志打印至控制台">3,示例1:日志打印至控制台</h3>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
import logging
logging.basicConfig(filename='./log.txt', level=logging.DEBUG,
format='%(asctime)s %(filename)s
%(levelname)s %(message)s')
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
logging.error('This is error message')
logging.critical('This is critical message')
</code></pre>
<p>控制台输出结果:</p>
<pre><code>2020-09-30 10:45:05,119 logging_test.py DEBUG This is debug message.
2020-09-30 10:45:05,119 logging_test.py INFO This is info message.
2020-09-30 10:45:05,119 logging_test.py WARNING This is warning message.
2020-09-30 10:45:05,120 logging_test.py ERROR This is error message.
2020-09-30 10:45:05,120 logging_test.py CRITICAL This is critical message.
</code></pre>
<h3 id="4示例2日志保存至文件">4,示例2:日志保存至文件</h3>
<pre><code class="language-python">logging.basicConfig(filename='log.txt', level=logging.INFO,
format='%(asctime)s %(filename)s %(levelname)s %(message)s')
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
logging.error('This is error message')
logging.critical('This is critical message')
</code></pre>
<p>输出格式:</p>
<pre><code>2020-09-30 10:45:05,119 logging_test.py INFO This is info message.
2020-09-30 10:45:05,119 logging_test.py WARNING This is warning message.
2020-09-30 10:45:05,120 logging_test.py ERROR This is error message.
2020-09-30 10:45:05,120 logging_test.py CRITICAL This is critical message.
</code></pre>
<p><strong>注意:</strong></p>
<ul>
<li>
<p>相较于控制台打印日志,文件保存日志的区别在于basicConfig()方法中加入了filename参数(即文件的完整路径)。</p>
</li>
<li>
<p>保存日志至文件示例中,因为参数level=logging.INFO,所以DEBUG级别的日志未输出</p>
</li>
</ul>
<h2 id="四logging的第二种使用方式日志流处理流程">四,logging的第二种使用方式:日志流处理流程</h2>
<h3 id="1logging四大组件介绍">1,logging四大组件介绍</h3>
<p>logging模块包括<strong>Logger,Handler,Filter,Formatter</strong>四个部分。</p>
<ul>
<li>Logger 记录器,用于设置日志采集。</li>
<li>Handler 处理器,将日志记录发送至合适的路径。</li>
<li>Filter 过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录。</li>
<li>Formatter 格式化器,指明了最终输出中日志的格式。</li>
</ul>
<h3 id="2logger-记录器">2,Logger 记录器</h3>
<p>使用日志流采集日志时,须先创建Logger实例,即创建一个记录器(如果没有显式的进行创建,则默认创建一个root logger,并应用默认的日志级别WARNING,Handler和Formatter),然后做以下三件事:</p>
<ul>
<li>为程序提供记录日志的接口</li>
<li>根据过滤器设置的级别对日志进行过滤</li>
<li>将过滤后的日志根据级别分发给不同handler</li>
</ul>
<h3 id="3handler-处理器">3,Handler 处理器</h3>
<p>Handler处理器作用是,将日志记录发送至合适的路径。如发送至文件或控制台,此时需要使用两个处理器,用于输出控制台的处理器,另一个是用于输出文件的处理器。通过 addHandler() 方法添加处理器 。常用的处理器类型有以下两种:</p>
<h4 id="31streamhandler">3.1,StreamHandler</h4>
<ul>
<li>
<p>将日志信息发送至sys.stdout、sys.stderr或任何类似文件流对象,如在Pycharm IDE上显示的日志信息。</p>
</li>
<li>
<p>构造函数为:StreamHandler(strm)。参数strm是一个文件对象,默认是sys.stderr。</p>
</li>
</ul>
<h4 id="32filehandler">3.2,FileHandler</h4>
<ul>
<li>
<p>将日志记录输出发送至磁盘文件。 它继承了StreamHandler的输出功能,不过FileHandler会帮你打开这个文件,用于向一个文件输出日志信息。</p>
</li>
<li>
<p>构造函数为:FileHandler(filename, mode)。参数filename为文件名(文件完整路径),参数mode为文件打开方式,默认为'a'即在文末追加。</p>
</li>
</ul>
<p>自动化测试使用这两种类型就够了,其他还有RotatingFileHandler、TimedRotatingFileHandler、NullHandler等处理器,有兴趣可以查找资料了解。</p>
<h3 id="4filter-过滤器">4,Filter 过滤器</h3>
<p>顾名思义是用于过滤,Handlers 与 Loggers 使用 Filters 可以完成比级别更复杂的过滤。不多做介绍,有兴趣可以查找资料了解。</p>
<h3 id="5formatter-格式化器">5,Formatter 格式化器</h3>
<p>Formatter用于设置日志的格式与内容,默认的时间格式为%Y-%m-%d %H:%M:%S,更多格式如下:</p>
<table>
<thead>
<tr>
<th><div style="width: 150px">格式</div></th>
<th><div style="width: 400px">描述</div></th>
</tr>
</thead>
<tbody>
<tr>
<td>%(levelno)s</td>
<td>打印日志级别的数值</td>
</tr>
<tr>
<td>%(levelname)s</td>
<td>打印日志级别的名称</td>
</tr>
<tr>
<td>%(pathname)s</td>
<td>打印当前执行程序的路径</td>
</tr>
<tr>
<td>%(filename)s</td>
<td>打印当前执行程序的名称</td>
</tr>
<tr>
<td>%(funcName)s</td>
<td>打印日志的当前函数</td>
</tr>
<tr>
<td>%(lineno)d</td>
<td>打印日志的当前行号</td>
</tr>
<tr>
<td>%(asctime)s</td>
<td>打印日志的时间</td>
</tr>
<tr>
<td>%(thread)d</td>
<td>打印线程ID</td>
</tr>
<tr>
<td>%(threadName)s</td>
<td>打印线程名称</td>
</tr>
<tr>
<td>%(process)d</td>
<td>打印进程ID</td>
</tr>
<tr>
<td>%(message)s</td>
<td>打印日志信息</td>
</tr>
</tbody>
</table>
<h3 id="6使用示例将日志输出至控制台同时保存至文件">6,使用示例:将日志输出至控制台,同时保存至文件</h3>
<p>根据logging的模块化来编写代码,思路参考如下。</p>
<p><strong>目录结构</strong></p>
<p><img src="https://upload-images.jianshu.io/upload_images/11175909-78ae26fad5eca004.png!thumbnail?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<p><strong>logging_test.py</strong></p>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
import logging
# 第一步,创建日志记录器
# 1,创建一个日志记录器logger
logger = logging.getLogger()
# 2,设置日志记录器的日志级别,这里的日志级别是日志记录器能记录到的最低级别,区别于后面Handler里setLevel的日志级别
logger.setLevel(logging.DEBUG)
# 第二步,创建日志处理器Handler。这里创建一个Handler,用于将日志写入文件
# 3,创建一个Handler,用于写入日志文件,日志文件的路径自行定义
logFile = './log.txt'
fh = logging.FileHandler(logFile, mode='a', encoding='utf-8')
# 4,设置保存至文件的日志等级
fh.setLevel(logging.INFO)
# 第三步,定义Handler的输出格式
# 5,日志输出格式定义如下
format= logging.Formatter('%(asctime)s %(filename)s %(levelname)s %(message)s')
# 6,设置 写入日志文件的Handler 的日志格式
fh.setFormatter(format)
# 第四步,将Handler添加至日志记录器logger里
logger.addHandler(fh)
# 同样的,创建一个Handler用于控制台输出日志
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(format)
logger.addHandler(ch)
# 输出日志
logger.info("This is info message")
logger.warning("This is warning message")
logger.error("This is error message")
logger.critical("This is critical message")
</code></pre>
<p>Pycharm运行logging_test.py模块,log.txt以及Pycharm控制台得到如下结果:</p>
<pre><code>2020-10-07 15:54:04,752 test.py INFO This is info message
2020-10-07 15:54:04,752 test.py WARNING This is warning message
2020-10-07 15:54:04,752 test.py ERROR This is error message
2020-10-07 15:54:04,752 test.py CRITICAL This is critical message
</code></pre>
<h2 id="五logging-实战">五,logging 实战</h2>
<h3 id="1测试场景">1,测试场景</h3>
<p>给登录今日头条app的操作添加日志采集。</p>
<h3 id="2简单配置代码示例">2,简单配置代码示例</h3>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
import logging
from appium import webdriver
logging.basicConfig(filename='./testLog.log', level=logging.INFO,
format='%(asctime)s %(filename)s %(levelname)s %(message)s')
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logging.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logging.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("18768124236") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xiaoqq3915172") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logging.error("登录错误,原因为:{}".format(e))
else:
logging.info("登陆成功...")
driver = android_driver()
login_opera(driver)
</code></pre>
<p>登录成功则日志输出如下:</p>
<pre><code>2020-09-30 18:20:05,119 logging_test.py INFO 启动今日头条APP...
2020-09-30 18:20:10,119 logging_test.py INFO 开始登陆今日头条APP...
2020-09-30 18:21:07,120 logging_test.py INFO 登陆成功...
</code></pre>
<h3 id="3抛出问题">3,抛出问题</h3>
<p>上面示例代码成功地获取了日志信息,但这种写法只能作用于当前模块。而一个自动化测试项目往往有多个模块,如果在每个需要获取日志的模块都使用这样的方式,显然是不方便维护的。那么我们需要怎么解决呢?</p>
<h3 id="4解决思路">4,解决思路</h3>
<p><strong>使用日志流处理流程</strong>。提供以下两种思路:</p>
<p><strong>思路1</strong>:使用python代码实现日志配置。先创建日志记录器,并设置好Handler与日志格式,如上面的logging_test.py模块构造logger,其他模块采集日志时直接调用。</p>
<p><strong>思路2</strong>:将日志的格式、输出路径等参数抽离出来放置在专门的配置文件里,如logging.conf,使用专门的模块处理,使用时直接在模块调用即可。</p>
<h3 id="5思路1使用python代码实现日志配置示例">5,思路1:使用python代码实现日志配置示例</h3>
<p><strong>目录结构</strong></p>
<p><img src="https://upload-images.jianshu.io/upload_images/11175909-72c63e13527ae1a6.png!thumbnail?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<p>test.py中需要采集日志时,从logging_test.py导入logger即可。也可以将logging_test.py里的代码进行进一步的封装,再调用,这里仅仅只是示例。<br>
<strong>logging_test.py</strong></p>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
import logging
# 创建日志记录器
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 设置日志输出格式
format= logging.Formatter('%(asctime)s %(filename)s %(levelname)s %(message)s')
# 创建一个Handler用于将日志写入文件
logFile = './log.txt'
fh = logging.FileHandler(logFile, mode='a', encoding='utf-8')
fh.setLevel(logging.INFO)
fh.setFormatter(format)
logger.addHandler(fh)
# 同样的,创建一个Handler用于控制台输出日志
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(format)
logger.addHandler(ch)
</code></pre>
<p><strong>test.py</strong></p>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
from appium import webdriver
from log.logging_test import logger
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logger.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logger.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("18768124236") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xiaoqq3915172") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logger.error("登录错误,原因为:{}".format(e))
else:
logger.info("登陆成功...")
driver = android_driver()
login_opera(driver)
</code></pre>
<p>运行test.py,结果如下:</p>
<pre><code>2020-10-07 18:45:05,119 logging_test.py INFO 启动今日头条APP...
2020-10-07 18:45:11,119 logging_test.py INFO 开始登陆今日头条APP...
2020-10-07 18:45:20,120 logging_test.py INFO 登陆成功...
</code></pre>
<h3 id="6思路2日志格式配置示例">6,思路2:日志格式配置示例</h3>
<h4 id="61loggerconf文件">6.1,logger.conf文件</h4>
<pre><code class="language-conf"> # loggers日志器对象列表,必须包含
keys=root, exampleLogger # 一定要包含root这个值,当使用无参函数logging.getLogger()时,默认返回root这个logger,其他自定义logger可以通过logging.getLogger("exampleLogger")方式进行调用
# handlers处理器对象列表,必须包含
keys=consoleHandler, fileHandler # 定义声明handlers信息
# formatters格式对象列表,必须包含
keys=form01,form02
# 对loggers中声明的logger进行逐个配置,且要一一对应,在所有的logger中,必须制定lebel和handlers这两个选项。对于非roothandler,还需要添加一些额外的option,如qualname、propagate等。handlers可以指定多个,中间用逗号隔开,比如handlers=fileHandler,consoleHandler,同时制定使用控制台和文件输出日志
level=DEBUG
handlers=consoleHandler, fileHandler
# 配置日志处理器exampleLogger:设置日志级别、日志输出指定的处理器配置文件,如consoleHandler,fileHandler
level=DEBUG
handlers=consoleHandler, fileHandler
qualname=exampleLogger# qualname 表示它在logger层级中的名字,在应用代码中通过这个名字制定所使用的handler
propagate=0 # 可选项,其默认是为1,表示消息将会传递给高层次logger的handler
# 日志处理器consoleHandler的配置文件
class=StreamHandler # 定控制台输出。将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象
level=DEBUG # 日志级别
formatter=form01 # 输出格式
args=(sys.stdout,)
# 日志处理器fileHandler的配置文件
class=FileHandler # 将日志输出至磁盘文件
level=DEBUG # 日志级别
formatter=form02 # 输出格式
args=('./log.txt', 'a', 'UTF-8') # 参数如未设置绝对路径,则默认生成在执行文件log.py的工作目录。指定日志文件的打开模式,默认为’a’
# 格式配置1
format=%(asctime)s %(filename)s %(levelname)s %(message)s
# 格式配置2
format=%(asctime)s %(filename)s %(levelname)s %(message)s
</code></pre>
<p><strong>注意:</strong></p>
<ul>
<li>
<p>为了说明配置结构,这里的配置文件 logger.conf 里加了中文注释,实际使用时需要将注释去掉或改写成英文注释,否则会报编码错误。</p>
</li>
<li>
<p>配置文件中包含三大主要模块:loggers,handlers,formatters。这三个主要模块包含的内容都是通过keys进行指定,然后通过logger_key、handler_key、formatter_key对里面的key进行具体的设置。</p>
</li>
<li>
<p>配置handlers中的handler_consoleHandler的参数:指定日志输出到控制台、级别、输出格式、参数。</p>
</li>
<li>
<p>配置handlers中的handler_fileHandlers的参数:指定将日志输出至磁盘文件、设置日志级别、输出格式、参数等。</p>
</li>
<li>
<p>配置日志输出格式formatter_xxx,可配置多个,如:form01,form02。</p>
</li>
</ul>
<h4 id="62读取配置文件创建日志记录器logger">6.2,读取配置文件,创建日志记录器logger</h4>
<p><strong>baseLog.py</strong></p>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
import logging.config
CON_LOG='./logger.conf' # 配置文件路径
logging.config.fileConfig(CON_LOG)# '读取日志配置文件'
logger = logging.getLogger('exampleLogger') # 创建一个日志器logger
</code></pre>
<h4 id="63调用示例">6.3,调用示例</h4>
<p>目录结构如下</p>
<p><img src="https://upload-images.jianshu.io/upload_images/11175909-3c563eab0f75e771.png!thumbnail?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<p><strong>test.py</strong></p>
<pre><code class="language-python"># -*- coding:utf-8 -*-
# @author: 给你一页白纸
from appium import webdriver
from log.baseLog import logger
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logger.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logger.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("18768124236") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xiaoqq3915172") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logger.error("登录错误,原因为:{}".format(e))
else:
logger.info("登陆成功...")
driver = android_driver()
login_opera(driver)
</code></pre>
<p>控制台、log.txt输出结果如下:</p>
<pre><code>2020-10-07 19:30:35,119 logging_test.py INFO 启动今日头条APP...
2020-10-07 19:30:40,119 logging_test.py INFO 开始登陆今日头条APP...
2020-10-07 19:31:12,120 logging_test.py INFO 登陆成功...
</code></pre>
<h3 id="7总结">7,总结</h3>
<p>在实际使用python做自动化测试过程中两种解决思路都可以使用,且都挺方便。其中对于思路1,还可以将代码进行更进一步的封装。</p>
<p><img src="https://img2020.cnblogs.com/blog/1213182/202010/1213182-20201008135654654-949871860.jpg" alt="" loading="lazy"></p>
</div>
<div id="MySignature" role="contentinfo">
<div style="font-size: 13px; border: 1px dashed rgb(45, 161, 45); padding: 10px 15px; background-color: rgb(248, 248, 248)">
<!-- <div>
<label style="font-weight: bold">
<label style="font-weight: bold; color: red; font-size: 15px">左边二维码</label>
为博主
<label style="font-weight: bold; color: red; font-size: 15px">个人微信</label>
,
<label style="font-weight: bold; color: red; font-size: 15px">扫码添加微信后可加入测试学习交流群</label>
(添加时请务必备注:加入测试学习交流群)。
<label style="font-weight: bold; color: red; font-size: 15px">右边二维码</label>
为博主
<label style="font-weight: bold; color: red; font-size: 15px">微信公众号</label>
,专注于自动化测试、测试开发技术分享,欢迎关注。
书山有路勤为径,学海无涯苦做舟。希望通过分享学习交流,大家能够朝着
<label style="font-weight: bold; color: red; font-size: 15px">最朴实的愿望:成长、加薪、升职</label>
更进一步。
</label>
</div> -->
<!-- <div>
<label style="font-weight: bold">
<label style="font-weight: bold; color: red; font-size: 15px">下边二维码</label>
为博主
<label style="font-weight: bold; color: red; font-size: 15px">微信公众号</label>
,专注于自动化测试、测试开发技术分享,欢迎关注。
书山有路勤为径,学海无涯苦做舟。希望通过分享学习交流,大家能够朝着
<label style="font-weight: bold; color: red; font-size: 15px">最朴实的愿望:成长、加薪、升职</label>
更进一步。
</label>
</div> -->
<!-- <div align="center">
<img style="height: 160px; width: 160px;" alt="个人微信" src="https://images.cnblogs.com/cnblogs_com/lfr0123/2106623/t_220220120615_wechat_black.png">
</div> -->
<!-- <div style="text-align: center; margin-top: 10px">
<img style="width: 180px; padding-right: 20%" alt="个人微信" src="https://images.cnblogs.com/cnblogs_com/lfr0123/2106623/o_220303134143_WeChat_with_logo.png">
<img style="width: 180px" alt="个人微信公众号" src="https://images.cnblogs.com/cnblogs_com/lfr0123/2106623/o_220303134126_gzh_with_ps.png">
</div> -->
<div><b>本文作者</b>:给你一页白纸</div>
<div><b>版权申明</b>:本博客所有文章除特殊声明外,均采用BY-NC-SA
许可协议。转载请注明出处!</div>
<div><b>声援博主</b>:如果觉得这篇文章对您有帮助,请点一下右下角的
“推荐”
图标哦,您的
“推荐”
是我写作的最大动力。您也可以点击下方的
【关注我】
按钮,关注博主不迷路。
</div>
</div><br><br>
来源:https://www.cnblogs.com/lfr0123/p/13781152.html
頁:
[1]