zoukankan      html  css  js  c++  java
  • 自动化遍历-appcrawler

    下载appclawler

    下载地址:https://pan.baidu.com/s/1dE0JDCH#list/path=%2F

    查看帮助文档:

    java -jar appcrawler-2.4.0-jar-with-dependencies.jar

    Usage: appcrawler [options]
    
      -a, --app <value>        Android或者iOS的文件地址, 可以是网络地址, 赋值给appium的app选项
      -e, --encoding <value>   set encoding, such as UTF-8 GBK
      -c, --conf <value>       配置文件地址
      -p, --platform <value>   平台类型android或者ios, 默认会根据app后缀名自动判断
      -t, --maxTime <value>    最大运行时间. 单位为秒. 超过此值会退出. 默认最长运行3个小时
      -u, --appium <value>     appium的url地址
      -o, --output <value>     遍历结果的保存目录. 里面会存放遍历生成的截图, 思维导图和日志
      --capability k1=v1,k2=v2...
                               appium capability选项, 这个参数会覆盖-c指定的配置模板参数, 用于在模板配置之上的参数微调
      -r, --report <value>     输出html和xml报告
      --template <value>       输出代码模板
      --master <value>         master的diff.yml文件地址
      --candidate <value>      candidate环境的diff.yml文件
      --diff                   执行diff对比
      -vv, --verbose           是否展示更多debug信息
      --demo                   生成demo配置文件学习使用方法
      --help
    示例
    appcrawler -a xueqiu.apk
    appcrawler -a xueqiu.apk --capability noReset=true
    appcrawler -c conf/xueqiu.json -p android -o result/
    appcrawler -c xueqiu.json --capability udid=[你的udid] -a Snowball.app
    appcrawler -c xueqiu.json -a Snowball.app -u 4730
    appcrawler -c xueqiu.json -a Snowball.app -u http://127.0.0.1:4730/wd/hub
    

    生成demo.yaml例子

    java -jar appcrawler-2.4.0-jar-with-dependencies.jar --demo

    ---
    pluginList: []
    saveScreen: true
    reportTitle: "雪球自动化遍历"
    resultDir: "./test"
    waitLoading: 500
    waitLaunch: 6000
    showCancel: true
    maxTime: 10800
    maxDepth: 10
    capability:
      noReset: "true"
      fullReset: "false"
      appium: "http://127.0.0.1:4723/wd/hub"
      appPackage: com.xueqiu.android
      appActivity: .view.WelcomeActivityAlias 
    testcase:
      name: "TesterHome AppCrawler"
      steps:
      - xpath: 行情
        action: click
      - xpath: 龙虎榜
        action: click
        then: 
        - //*[contains(@text,'沪深上榜个股')]
    selectedList:
    - xpath: "//*[contains(name(), 'Text') and @clickable='true' and string-length(@text)<10]"
    - xpath: "//*[@clickable='true']/*[contains(name(), 'Text') and string-length(@text)<10]"
    
    firstList: []
    lastList:
    - xpath: "//*[@selected='true']/..//*" 
    - xpath: "//*[@selected='true']/../..//*"
     
    backButton:
    - given: []
      when: null
      then: []
      xpath: "Navigate up"
      action: null
      actions: []
      times: 0
    triggerActions:
    - xpath: 净买入
      times: 10
    - xpath: 总成交
      times: 10
    - given: []
      when: null
      then: []
      xpath: "share_comment_guide_btn"
      action: null
      actions: []
      times: 0
    xpathAttributes:
    - "name"
    - "label"
    - "value"
    - "resource-id"
    - "content-desc"
    - "instance"
    - "text"
    sortByAttribute:
    - "depth"
    - "list"
    - "selected"
    findBy: "default"
    defineUrl: []
    baseUrl: []
    appWhiteList: []
    urlBlackList: []
    urlWhiteList: []
    blackList:
    - given: []
      when: null
      then: []
      xpath: ".*[0-9]{2}.*"
      action: null
      actions: []
      times: 0
    beforeRestart: []
    beforeElement:
    - given: []
      when: null
      then: []
      xpath: "/*"
      action: "Thread.sleep(500)"
      actions: []
      times: 0
    afterElement: []
    afterPage: []
    afterPageMax: 2
    tagLimitMax: 2
    tagLimit:
    - given: []
      when: null
      then: []
      xpath: "确定"
      action: null
      actions: []
      times: 1000
    - given: []
      when: null
      then: []
      xpath: "取消"
      action: null
      actions: []
      times: 1000
    - given: []
      when: null
      then: []
      xpath: "share_comment_guide_btn_name"
      action: null
      actions: []
      times: 1000
    assertGlobal: []
    
    

    启动已经安装过的app

    java -jar appcrawler-2.4.0-jar-with-dependencies.jar --capability "appPackage=com.xueqiu.android,appActivity=.view.WelcomeActivityAlias"

    定位模式xpath

    xpath:
        //*[@resource-id=‘xxxx’]
        //*[contains(@text, ‘密码’)]
    正则:
        ^确定$
        ^.*输入密码
    包含:
        请
        输入
        密码
    
    

    自动化遍历支持

        selectedList:需要被遍历的元素范围 
        firstList:优先被点击
        lastList:最后被点击
        tagLimitMax:同祖先(同类型)的元素最多点击多少
        backButton:当所有元素都被点击后默认后退控件定位 
        blackList:黑名单
        maxDepth: 6 遍历的最大深度
    
    

    触发器

    triggerActions:
        需要特定次数的触发动作
        通常用于处理弹框
        xpath: 指定具体按钮 
        action:动作 
        times:规则的使用次数
    
    

    动作支持action

        “” 只是截图记录
        back 后退
        backApp 回退到当前的app 默认等价于back行为 可定制 monkey 随机事件
        xxx() 执行代码
            Thread.sleep(3000)
            driver.swipe(0.9, 0.5, 0.1, 0.5) click
        longTap
        非以上所有行为是输入 xx ddd
    

    与传统WebDriver的不同点

    WebDriver:
        根据id class xpath进行定位
        直接截图 
    AppCrawler:ReactWebDriver模式:
        先getPageSource获取所有的元素列表 
        根据配置好的宽泛的xpath直接选择元素 
        然后再生成匹配到的每个元素的唯一定位xpath表达式或者id定位表达式 
        然后调用appium定位并执行action
        截图时增加对选择控件的高亮区分
     
    

    配置文件参考

    https://github.com/seveniruby/AppCrawler/blob/2.3.1/src/main/scala/com/testerhome/appcrawler/CrawlerConf.scala

    package com.testerhome.appcrawler
    
    import java.io.File
    
    import com.fasterxml.jackson.databind.ObjectMapper
    import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
    import com.fasterxml.jackson.module.scala.DefaultScalaModule
    import org.openqa.selenium.interactions.Actions
    
    import scala.collection.mutable
    import scala.collection.mutable.ListBuffer
    import scala.io.Source
    
    /**
      * Created by seveniruby on 16/1/6.
      */
    class CrawlerConf {
      /** 插件列表,暂时禁用,太高级了,很多人不会用 */
      var pluginList = List[String]()
      /** 是否截图 */
      var saveScreen = true
      var reportTitle = ""
      /** 结果目录 */
      var resultDir = ""
      /**在执行action后等待多少毫秒进行刷新*/
      var waitLoading=500
      var waitLaunch=6000
      //var tagLimit=scala.collection.mutable.Map[String, Int]()
      var showCancel = true
      /** 最大运行时间 */
      var maxTime = 3600 * 3
      /** 默认的最大深度10, 结合baseUrl可很好的控制遍历的范围 */
      var maxDepth = 10
      /** sikuli的数据 */
      //var sikuliImages=""
      //todo: 通过数据驱动,支持多设备
      /** appium的capability通用配置 */
      var capability = Map[String, Any](
        //默认不清空数据,防止有人用于微信和qq
        "noReset" -> "true",
        "fullReset" -> "false",
      )
    
      //测试用例
      var testcase = ReactTestCase(
        name = "TesterHome AppCrawler",
        steps = List[Step](
          Step(xpath = "/*", action = "Thread.sleep(5000)")
        )
      )
    
      /** 默认遍历列表,xpath有用,action暂时没启用*/
      var selectedList = ListBuffer[Step](
        Step(xpath="//*[contains(name(), 'Button')]"),
        //android专属
        Step(xpath="//*[contains(name(), 'Text') and @clickable='true' and string-length(@text)<10]"),
        Step(xpath="//*[@clickable='true']/*[contains(name(), 'Text') and string-length(@text)<10]"),
        Step(xpath="//*[contains(name(), 'Image') and @clickable='true']"),
        Step(xpath="//*[@clickable='true']/*[contains(name(), 'Image')]"),
        //ios专属
        Step(xpath="//*[contains(name(), 'Image') and @name!='']"),
        Step(xpath="//*[contains(name(), 'Text') and @name!='' and string-length(@label)<10]"),
      )
      /** 优先遍历元素 */
      var firstList = ListBuffer[Step](
      )
      /** 最后遍历列表 */
      var lastList = ListBuffer[Step](
        Step(xpath="//*[@selected='true']/..//*"),
        Step(xpath="//*[@selected='true']/../..//*")
      )
      /** 后退按钮标记, 主要用于iOS, xpath */
      var backButton = ListBuffer[Step](
        Step(xpath="Navigate up")
      )
    
      //todo: 去掉triggerAction
      /** 引导规则. name, value, times三个元素组成 */
      var triggerActions = ListBuffer[Step](
        Step(xpath="share_comment_guide_btn")
      )
    
      //自动生成的xpath表达式里可以包含的匹配属
      var xpathAttributes = List("name", "label", "value", "resource-id", "content-desc", "instance", "text")
      /** 先按照深度depth排序,再按照list排序,最后按照selected排序。后排序是优先级别最高的 */
      var sortByAttribute = List("depth", "list", "selected")
      //可选 default|android|id|xpath,默认状态会自动判断是否使用android定位或者ios定位
      var findBy="default"
      /** 用来确定url的元素定位xpath 他的text会被取出当作url因素 */
      var defineUrl = List[String]()
      /** 设置一个起始url和maxDepth, 用来在遍历时候指定初始状态和遍历深度 */
      var baseUrl = List[String]()
      var appWhiteList = ListBuffer[String]()
      /** url黑名单.用于排除某些页面 */
      var urlBlackList = ListBuffer[String]()
      var urlWhiteList = ListBuffer[String]()
      /** 黑名单列表 matches风格, 默认排除内容是2个数字以上的控件. */
      var blackList = ListBuffer[Step](
        Step(xpath=".*[0-9]{2}.*")
      )
    
      //在重启session之前做的事情
      var beforeRestart=ListBuffer[String]()
      //在执行action之前和之后默认执行的动作,比如等待
      var beforeElement = ListBuffer[Step](
        Step(xpath="/*", action="Thread.sleep(500)")
      )
      var afterElement = ListBuffer[Step]()
      /**是否需要刷新或者滑动*/
      var afterPage = ListBuffer[Step]()
      //afterPage执行多少次后才不执行,比如连续滑动2次都没新元素即取消
      var afterPageMax=2
      //相似控件最多点击几次
      var tagLimitMax = 2
      //个别控件可例外
      var tagLimit = ListBuffer[Step](
        //特殊的按钮,可以一直被遍历
        Step(xpath = "确定", times = 1000),
        Step(xpath = "取消", times = 1000),
        Step(xpath = "share_comment_guide_btn_name", times=1000)
      )
      //只需要写given与then即可
      var assertGlobal = List[Step]()
    
    
      def loadByJson4s(file: String): Option[this.type] = {
        if (new java.io.File(file).exists()) {
          println(s"load config from ${file}")
          println(Source.fromFile(file).mkString)
          Some(TData.fromYaml[this.type](Source.fromFile(file).mkString))
        } else {
          println(s"conf file ${file} no exist ")
          None
        }
      }
    
      def save(path: String): Unit = {
    
        /*
            //这个方法不能正确的存储utf8编码的文字
            implicit val formats = DefaultFormats+ FieldSerializer[this.type]()
            val file = new java.io.File(path)
            val bw = new BufferedWriter(new FileWriter(file))
            log.trace(writePretty(this))
            log.trace(write(this))
            bw.write(writePretty(this))
            bw.close()
            */
    
        val file = new java.io.File(path)
        val mapper = new ObjectMapper()
        mapper.registerModule(DefaultScalaModule)
        mapper.writerWithDefaultPrettyPrinter().writeValue(file, this)
        println(mapper.writeValueAsString(this))
      }
    
      def toJson(): String = {
        val mapper = new ObjectMapper()
        mapper.registerModule(DefaultScalaModule)
        mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this)
    
      }
    
      def toYaml(): String = {
        val mapper = new ObjectMapper(new YAMLFactory())
        mapper.registerModule(DefaultScalaModule)
        mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this)
      }
    
      def loadYaml(fileName: File): CrawlerConf = {
        val mapper = new ObjectMapper(new YAMLFactory())
        mapper.registerModule(DefaultScalaModule)
        mapper.readValue(fileName, classOf[CrawlerConf])
      }
    
      def loadYaml(content: String): Unit = {
        val mapper = new ObjectMapper(new YAMLFactory())
        mapper.registerModule(DefaultScalaModule)
        mapper.readValue(content, classOf[CrawlerConf])
      }
    
    
      def load(file: String): CrawlerConf = {
        load(new File(file)).get
      }
    
      //如果没有显式配置参数,那么就会用默认值代替
      def load(file: File): Option[CrawlerConf] = {
        val content = Source.fromFile(file, "UTF-8").getLines().mkString("
    ")
        file.getName match {
          case json if json.endsWith(".json") => {
            Some(TData.fromJson[CrawlerConf](content))
          }
          case yaml if yaml.endsWith(".yml") || yaml.endsWith(".yaml") => {
            Some(TData.fromYaml[CrawlerConf](content))
          }
          case path => {
            println(s"${path} not support")
            None
          }
        }
      }
    
    
    
    
  • 相关阅读:
    再谈反射
    XmlElement和XmlNode的区别
    几个常用的集合类的使用
    node.js 练习3 调用函数
    ioc 的好文章 转自 GavinJun
    sqlserver 使用小技巧总结
    node.js 练习2 (调用函数)
    c# 面向对象基础
    linq 和 lmabda 表达式 的用法 和优劣 转自 农码一生
    memcache 基本操作
  • 原文地址:https://www.cnblogs.com/an5456/p/11488736.html
Copyright © 2011-2022 走看看