Frossky 发布的文章

知乎上的这个回答很好,可以参考:如何让各大搜索引擎搜索收录到刚建的wordpress网站?
里面提到了两个提交单个页面的工具
Google 网站站长工具
Baidu url提交_站长工具
对于google提交站点地图,在google console页面可以先添加站点资源,然后在站点地图里面增加站点地图.
对百度提交,在这个页面下面选择自动提交-sitemap的方式来提交.

不过typecho默认是没有站点地图的, 可以通过插件添加.

添加xml格式的站点地图

这篇文章里面介绍了typecho的google站点地图插件,下载解压缩后,将其中的Sitemap目录上传到usr/plugins中.登录typecho后台的插件页面,然后访问http://your.site/index.php/sitemap/就能得到google想要的xml格式的站点地图.
由于百度也支持谷歌的xml格式的站点地图,尝试提高上述地址时,却发现百度不能正确识别,似乎站点地图后缀必须是.xml.
于是,将上述插件Sitemap/Plugin.php中做一下修改, 第29~32行改为:

    public static function activate()
    {
        Helper::addRoute('sitemap', '/sitemap.xml', 'Sitemap_Action', 'action');
    } // old: 'sitemap', '/sitemap/', 'Sitemap_Action', 'action'

重新上传并启用,新的地址变为http://your.site/index.php/sitemap.xml
再次加入百度的站点地图后成功了.

添加html格式的站点地图

在这篇文章:Typecho 无插件轻松实现html站点地图中,提供了无插件下载站点地图的方式. 将文章中的php上传到usr/themes/default/中, 再在typecho后台创建页面,将连接地址设置为sitemap.html, 选择自定义模板为Template Page Of Sitemap,公开度设置为隐藏, 访问http://your.site/index.php/sitemap.html即可.

node-serialport确实是一个非常麻烦的模块,相比来说,python的pyserial就要好用很多啊.
node升级后,到对应的项目目录中, 在node_modules\serialport下,运行node-gyp rebuild,可以重新编译serialport模块.

晴日携妻游方时,广场阔阔人如织。玻璃长廊场中现,凌空三米好景观。欲寻入口在场心,一无楼梯二无门。旁置梯子搭来使,梯短口高勉强支。妻子担忧手扶好,场工建议如此般。爬至梯顶手举直,撑开数块压口板。下宽上窄人难爬,思忖我上将妻拉。妻与场工多主意,我仍决定尊自意。方换一边爬上梯,一梦忽断续无期。

是在受不了grav的体积...已被撑爆...删除全站转typecho了.
grav号称宇宙最强flat cms,看来不适合我

互联网服务的本质是信息的服务.
信息服务的本质是解决两个问题: 信息的产生和信息的获得.
哪一个价值更大?如果从市值最高的这些互联网公司推断, 解决信息获得问题的价值更大, 可以排为互联网服务的第一本质. 换一个互联网的名词: 解决了入口问题,做的是平台的生意.
举例来说,百度,谷歌,不产生信息,而是为通过搜索引擎梳理和连接信息, 找出搜索关键词和目标信息的关联, 也就是解决用户信息获得的问题.淘宝网解决了商品信息的获得问题, 同时也为信息的产生提供了平台,并且它阻止百度从他那儿获取信息.为什么阿里不让百度替他解决信息获得的问题?这在淘宝之前的大多数电商网站都是巴不得的,因为带来的更多的流量!那就是因为,信息获得更有价值,产生的信息不让其流出,逼迫用户只能从他这儿获得信息,从而为他产生价值.
从信息产生和获得的人群来说,获得信息的人很多情况是比要产生信息的人要多.一个人花费在获得信息上的时间,也通常比产生信息的时间要多.一个人同样的时间内去获得信息和产生信息, 获得的信息也比产生的信息多得多.
网络游戏是信息产生和获得的一种升华,他提供了另一种娱乐体验,不由用户产生直接信息(可能只是终端发给服务器的二进制数据),和获得(消费)直接信息,如果计算利润, 互联网游戏也占比很高.但本质上其游戏体验的价值还是远超过信息的价值的,互联网在其中不可或缺,但不是主要价值提供者,游戏趣味本身才是.当然你也可以说游戏的整个安装包也是一个信息, 但这个信息不一定是通过网络获取(光盘U盘也可以), 其中的信息也是不可检索的.
从这个角度,进一步看互联网服务的本质,是可检索信息的服务.第一本质是可检索信息的获得.
如今日头条,在一开始也只是从各个网站抽取新闻才快速发展起来的.做起来的视频网站,一开始也只是搜集其他的个人上传视频,然后让用户可以观看,搜索,解决用户信息获得的问题.豆瓣,知乎主要解决了信息产生,但由于其向百度开放了搜索(大多数网站都是这样的),而百度上信息获取更容易,所以豆瓣知乎仍需要借助百度解决信息获得问题,本身价值就会下降.
当然,将信息截流在自己的服务器上,不许其他服务器爬取,听上去就违反互联网精神,但实际上很多互联网公司就是这么做的.阿里电商,京东电商,微信公众号文章,都是产生了信息之后截流在自己的服务器上.于是就有了爬虫和反爬虫的斗争.
对信息的截流可能有这些方式:

  • 版权的名义进行截流.如文学网站宣称对于在自己网站上发布的销售拥有版权,视频网站同样的方式或者通过购买正版版权,独占版权等进行信息截流. 建立了信息发布平台,购买了版权,就可以以此名义截流.
  • 流量的名义要求信息生产者发布独占信息或定制化信息. 如平台独占游戏, 渠道APP包, 平台独占文章(挖知乎达人要求只为自己生产内容), 双11要求商家二选一等. 形成平台效应,在某一领域有足够大的流量甚至是垄断流量,就可以这么做.
  • 技术上防止爬虫, 阻止信息外流.如将价格使用图片显示, 增加防爬虫的标识等.

在国内,大公司截流信息的情况应该是非常普遍的.

需要linux系统, kali最好,自带很多网络监听工具.
在windows上安装虚拟机, 试过Virtualbox和VMWare, 只有VMware是正常的(VMWare Workstation 11)
需要一个可以监听的硬件,试过这款可以Ralink RT5370 150M USB迷你无线网卡 机顶盒WIFI信号发射接收器,价格也只有17元.

这个也可以, 只是太贵,要100多.包邮TP-LINK WN722N V1 AR9271A无线渗透usb无线网卡LINUX 免驱动. 可以搜索AR9271,找到更便宜一些的.

参考文章 capturing-wifi-in-monitor-mode-with-iw

今天登陆后台发现, grav现在已经占了100多M的空间,我还没有上传1张图片...这看起来比使用数据库的wordpress耗费的存储要多得多.

参考文章 Convert-an-Android-Device-to-Linux

  1. busybox可以模拟部分linux指令和操作, 但毕竟不是linux
  2. Termux更像是linux, 有自己的包管理,能装node, python, 而且不需要root,但工作起来毕竟还是受限
  3. 要装任意linux发行版,怎么办, 可以安装Linux Depoly或者Complete Linux Installer
  4. 还可以装模拟器Limbo PC Emulator

根据网上的中文版《FreeRTOS实时内核实用指南》,主要有这几部分内容

  • 任务调度。可以创建多个任务(xTaskCreate),然后启动调度器(vTaskStartScheduler)根据优先级进行调度
  • 消息队列。任务间通讯通过消息队列完成。
  • 中断管理。
  • 资源管理。主要是独占资源如何在多任务中进行管理。
  • 内存管理。

其实核心是多任务。

根据ESP8266 FreeRTOS的指南,可以完成如下事项:

  • 常规的WIFI操作,如AP、Station、混杂模式Sniffer等
  • spiffs,spi flash文件系统
  • SSC, 简单串口命令注册和使用,可通过串口发送命令和解析
  • 系统的启动与升级

在windows上比较简单:

import  msvcrt
ch = msvcrt.getch()

其他平台,可以安装getch模块

pip install getch

然后

import getch
# ...
char = getch.getch() # User input, but not displayed on the screen
# or
char = getch.getche() # also displayed on the screen

本网站[idarc.cn]使用了dns解析服务器上设置显性URL的方式来将二级域名grav.idarc.cn进行重定向到 idarc.cn/grav, 但对于主域名idarc.cn也想重定向到idarc.cn/grav上, 这儿有一篇很好很详细的文章:How to Redirect a Web Page
由于我是托管在php主机上, 所以无法随意改主机服务器的设置, 只能修改网页. 我使用了JavaScript的window.location转向的方式, 但似乎搜索引擎只有google能搜索出来, 而百度和bing都不行. 下来试试meta的效果看如何:

<meta http-equiv="refresh" content="0; URL='http://new-website.com'" />

2020-2-21更新

很多次想搞一搞android的自动化界面测试, 这下开始啦!

主要参考的Appium官方文档:

失效文档

Android文档

wd.js文档

Webdriver文档

1. Appium分为server和client, server需要先运行. client用于跑脚本.

在windows上用appium server, 可以用node安装或者安装Desktop版本. 推荐安装Desktop版本,下载地址在github上
node安装方式:

npm install -g appium
appium

可惜的是, 他需要从googleapis下载一个chromedriver的包, 你知道的,这是不可能的, 所以会一直卡在这儿:

npm install -g appium                                                                                                      
C:\Users\Jac\AppData\Roaming\npm\appium -> C:\Users\Jac\AppData\Roaming\npm\node_modules\appium\build\lib\main.js            

> appium-chromedriver@3.0.1 install C:\Users\Jac\AppData\Roaming\npm\node_modules\appium\node_modules\appium-chromedriver    
> node install-npm.js                                                                                                        

info Chromedriver Install Installing Chromedriver version '2.30' for platform 'win' and architecture '32'                    
info Chromedriver Install Opening temp file to write chromedriver_win32 to...                                                
info Chromedriver Install Downloading https://chromedriver.storage.googleapis.com/2.30/chromedriver_win32.zip...             

这儿你可以使用cmder, 设置代理, 然后再下载.

另外还可以老老实实下载desktop版本试试. 下载地址在github上

2. 调试安卓的准备.

可以看appium的官方文档,步骤还是不少的, 下面简要说一下:

  • 下载和安装/解压JDK, 设置JAVA_HOME, 将其中bin目录放到PATH里面
  • 安装Android SDK, 设置ANDROID_HOME, 将其中tools和platform-tools目录放到PATH里面
  • 安装Apache Ant,或者用android SDK目录下的eclipse\plugins里面那个. 确保能访问ant的目录放入PATH里面
  • 安装Apache Maven, 设置M2_HOME为解压目录, M2为bin目录,把bin目录加到PATH里面(PATH里面得多少东西啊, win10的PATH还有2048个字符的限制, 我的已经分分钟要超出了...)
  • 连接android设备或者启动个模拟器,API level需要大于等于17.
  • 测试脚本需要确认platformVersion与测试设备一致, app项设置地址是到.apk文件的绝对路径

3. 运行测试

  • 连接手机
    用线连接手机很简单, 要记得点击手机中设置->版本号5次打开开发者模式->打开USB调试.

  • 连接安卓夜神模拟器
    连接安卓夜神模拟器的方式, 先在模拟器设置中把平板模式调成手机模式, 然后再点击手机中设置->版本号5次打开开发者模式->打开USB调试.
    然后再命令行输入:

    adb connect 127.0.0.1:62001
  • adb devices确定连接的设备有且只有一个. 如果有问题, 你可以重启adb:

    adb kill-server && adb devices

    测试安卓得知道包名和activity名字, 可测试的人儿哪儿知道...好啦有个办法(linux上用grep替代findstr):

    adb shell dumpsys window windows | findstr mFocusedApp

    我关注的我们isen的输出是这样的:

    adb shell dumpsys window windows | findstr isen                                                                                
    Window #5 Window{f9a1670 u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity}:                                   
      mOwnerUid=10242 mShowToOwnerOnly=true package=com.isen.trace.police addTime=2017-11-24 19:49:12 appop=NONE                   
      mToken=AppWindowToken{c40a9b1 token=Token{ca91458 ActivityRecord{471753b u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity, isShadow:false t129}}}                                                                                            
      mRootToken=AppWindowToken{c40a9b1 token=Token{ca91458 ActivityRecord{471753b u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity, isShadow:false t129}}}                                                                                        
      mAppToken=AppWindowToken{c40a9b1 token=Token{ca91458 ActivityRecord{471753b u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity, isShadow:false t129}}}                                                                                         
      WindowStateAnimator{2b01034 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity}:                                 
        mSurface=Surface(name=com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity)                                      
    mInteractingStatusBarWindow=Window{f9a1670 u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity}                  
    mCurrentFocus=Window{f9a1670 u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity}                                
    mFocusedApp=AppWindowToken{c40a9b1 token=Token{ca91458 ActivityRecord{471753b u0 com.isen.trace.police/com.isen.tz.wifitz.activity.MainActivity, isShadow:false t129}}}                                                                                         
      PkgName=com.isen.trace.police                                                                                                

4. 检查一下android环境

前面安装好了appium desktop版的话, 默认也会装一个appium-doctor,可以用来检查环境.我的目录如下:

"C:\Program Files (x86)\Appium\node_modules\.bin\appium-doctor.cmd" --android

Running Android Checks
✔ ANDROID_HOME is set to "C:\Users\Jac\AppData\Local\Android\Sdk"
✔ JAVA_HOME is set to "C:\Program Files\Java\jdk1.8.0_111."
✔ ADB exists at C:\Users\Jac\AppData\Local\Android\Sdk\platform-tools\adb.exe
✔ Android exists at C:\Users\Jac\AppData\Local\Android\Sdk\tools\android.bat
✔ Emulator exists at C:\Users\Jac\AppData\Local\Android\Sdk\tools\emulator.exe
✔ Android Checks were successful.

✔ All Checks were successful

当然你可以用npm装一个,这样就不需要找appium-doctor到底在那个目录了

npm install -g appium-doctor
appium-doctor.cmd --android

info AppiumDoctor Appium Doctor v.1.4.3
info AppiumDoctor ### Diagnostic starting ###
info AppiumDoctor  ✔ The Node.js binary was found at: C:\Program Files\nodejs\node.exe
info AppiumDoctor  ✔ Node version is 6.10.0
info AppiumDoctor  ✔ ANDROID_HOME is set to: C:\Users\Jac\AppData\Local\Android\Sdk
info AppiumDoctor  ✔ JAVA_HOME is set to: C:\Program Files\Java\jdk1.8.0_111
info AppiumDoctor  ✔ adb exists at: C:\Users\Jac\AppData\Local\Android\Sdk\platform-tools\adb.exe
info AppiumDoctor  ✔ android exists at: C:\Users\Jac\AppData\Local\Android\Sdk\tools\android.bat
info AppiumDoctor  ✔ emulator exists at: C:\Users\Jac\AppData\Local\Android\Sdk\tools\emulator.exe
info AppiumDoctor  ✔ Bin directory of %JAVA_HOME% is set
info AppiumDoctor ### Diagnostic completed, no fix needed. ###
info AppiumDoctor
info AppiumDoctor Everything looks good, bye!
info AppiumDoctor

主要是是 ANDROID_HOME 这个变量, 我的系统里面只设置了一个叫 ANDROID_SDK_ROOT 的变量...不知道是安装那个程序需要的. 内容是一样的.

5. 设置项目

当然是先新建个项目目录,然后npm init了,老规矩,然后安装appium官方推荐的wd.js作为客户端driver, 使用promise的方式.

npm init
npm install -S wd chai chai-as-promised colors

6. 运行服务器

把appium跑起来. 这儿选择桌面版的运行. 运行了以后,看到提示服务器地址 http://127.0.0.1:4723

7. 准备和服务器建立连接前的基础知识

不得不先讲点儿理论了. 就是这个Webdriver和JSONWireProtocol建立了客户端与服务器的会话(Session).
那么Webdriver是什么呢, 说起源头还是Selenium的一部分, 是一个自动化的测试方式, 也就是通过客户端向服务器发命令进行测试的方式, 测试服务器再控制浏览器运行测试命令. 2012年, Webdriver被W3C标准化, 然后也就出现了很多不同的Webdriver的语言实现.
webdriver标准里面定义了服务器客户端使用RestFul API进行交互, 交互的协议称为wire protocol. 数据内容是JSON形式的, 这就是JSONWireProtocol了(也称作Webdriver Wire Protocol). 定义在github这儿.
按照这个定义页面上讲的, JSON Wire Protocol也已经过期, 因此, 目前来看Webdriver标准和JSONWireProtocol, Webdriver Wire Protocol其实就是一个东西在不同时期的叫法不同. 现在来看, 最新叫法就是W3C Webdriver 标准了.

建立连接的步骤分两步:

  • 先建立与服务器连接, 这儿需要知道服务器的地址,端口号, 有时候还需要用户名密码. 因为是HTTP RESTful的, 因此可以表示为url形式, 如默认一般是http://localhost:4723
  • 再建立session连接. 建立session连接时, 客户端应提供一些基础数据, 称之为能力Capabilities, 简称caps. webdriver最初是用作web测试的, 所以需要填写的内容和Appium用作app测试的有些不同. 测试androidapp, 数据如下(JSON形式):
    2020-2-20注: 最新版Appium已经改了很多,详细看: Appium Desired Capabilities
    {
    platformName: "Android",
    deviceName: "HUAWEI MLA-AL10",
    appPackage: "com.ss.android.ugc.aweme",  //这个是抖音包名,包名可以在设置->应用->运行中的APP查看
    appActivity: ".main.MainActivity",  //主Activity,也可以在上面的路径查看
    automationName: "UiAutomator1",
    platformVersion: "4.4.2",
    browserName: "",
    noReset: "true",  //非常重要! 如果不希望清空原APP数据直接启动,这个一定要为true
    newCommandTimeout: 6000,
    unicodeKeyboard: "true", //unicodeKeyboard和resetKeyboard非常重要! 设置后才能通过sendKeys发送中文
    resetKeyboard: "true"
    }

    newCommandTimeout默认值为60, 意思是60秒无任何命令输入就断掉session. 如果是使用wd shell交互式命令, 或者使用Appium inspector(后面讲), 或者刚刚开始学习的话, 最好设置久一点,以免正看文档着呢, session就没了就无法操作了, 还得花几分钟重启session呢.
    后面在常见问题里讲了如果session中断后如何重连的方式.

下面就可以发命令控制了. 控制浏览器的命令就写在Webdriver标准里面, 控制app的命令写在appium文档里面

8. 获得界面元素的工具

界面上很多元素需要获得之后再去操作, H5可以在页面审查,看源码,知道ID和Class什么的用来定位,可是安卓原生应用该怎么办?
两个工具Appium inspector和UIAutomator Viewer

UIAutomator Viewer

先说UIAutomator Viewer(简称UIAV),这个是跟android SDK一起安装的. 我的Windows下位置是:

C:\Users\Jac\AppData\Local\Android\Sdk\tools\uiautomatorviewer.bat

双击后打开, 点击第三个图标"Device Screeshot with compressed Hierarchy".
UIAV的运行与Appium session的运行冲突, 如果报错, 请将Appium 服务停掉, 相关的client session断掉.
然后左侧窗口将显示屏幕截图, 点击图上某一元素右侧会显示属性.

Appium inspector

再说说Appium inspector(以下简称AI), 这是和Appium Desktop版一起安装的. 从界面上我估计这些货都是Electron开发的:)
Appium Desktop的服务器运行后,右上角第一个放大镜按钮点击,打开一个Appium的图形化界面客户端, 在这儿启动session后就会进入AI.
你可以在左侧一行一行的添加caps, 也可以在右侧直接将JSON复制进去并保存. json 格式正确将会成功保存, 格式错误将无法保存, 不过工具目前没有给提示.
输入后点击start session, 等待服务器将必要的app和测试app都装入手机, 将进入Appium inspector.
左侧是截图, 也可以选择元素, 不过位置总不太对. 上面还可以选择录制(眼睛图标), 录制下来的脚本可以选择不同的语言. 不过目前还有很大的问题, wd.js里面有的语法还是写错的...另外, 选择一步操作后,反应还是有些慢.似乎主要都耗时在截图传输上了.

9. 使用AI录制命令

进入AI界面后, 点击录制(start recording)按钮开始录制.
右侧可以选择客户端语言, 以wd.js为例(JS - WD(Promise)). 旁边三个按钮依次是:显示完整代码, 复制代码, 清空代码. 选择滑动, 做一个上滑操作, 显示完整代码, 如下:

// Requires the admc/wd client library
// (npm install wd)
// Then paste this into a .js file and run with Node 7.6+

const wd = require('wd');
const driver = wd.promiseChainRemote("localhost", 4723);
const caps = {"platformName":"android","deviceName":"myphone","app":"C:\\my.apk","browserName":""};

async function main () {
  await driver.init(caps);
  await (new TouchAction(driver))
    .press({x: 326, y: 491})
    .moveTo({x: 21: y: -166})
    .release()
    .perform()
  await driver.quit();
}

main().catch(console.log);

注意代码中有两个问题

  • moveTo里面的对象格式写错了, 应该是{x: 21, y: -166}
  • new TouchAction(driver)写错, 应该是new wd.TouchAction(driver)
    改好以后, 放到项目下的一个js文件里(如test.js), 用node运行node test.js, node 版本需要大于7.6, 主要是新版node实现了ES7里面的async和await.

10. 使用wd.js的repl界面

wd.js支持repl是个惊喜. 运行方式是在项目目录下面:

 .\node_modules\.bin\wd shell

在这儿可以输入wd.js的命令, 进行交互.
因为交互敲命令需要时间,为避免session断开, 可以在caps里面增加一项"newCommandTimeout": 6000, 延长超时时长(默认60秒)到6000秒.
依次(三条命令分三次)输入如下命令, 达到与代码类似的效果

const wd = require('wd'),
    driver = wd.promiseChainRemote("localhost", 4723),
    caps = {"platformName":"android","deviceName":"c195b35c","app":"C:\\r\\Appium\\wrtestcases\\apk\\TzRadar_373_v3.7.3_373_jiagu_sign.apk","browserName":"",
        "newCommandTimeout": 6000},
    TouchAction = wd.TouchAction;

driver.init(caps);

(new TouchAction(driver))
    .press({x: 338, y: 716})
    .moveTo({x: -5, y: -357})
    .release()
    .perform();

11. wd.js在appium测试android的时候可以用哪些命令: driver部分

因为不同的测试平台可用的命令不同, 如果敲入了未实现的命令, 就会返回错误.
哪些命令可用? 参考的知识太多, 涉及webdriver, wd.js, appium, android...同时开这几个文档来回切换看好累...实操可用的如下:

//driver可用的命令, cb表示callback函数. 是否可以await尚未测试.
driver.lock(3) //锁定, 3貌似是延时
driver.backgroundApp(5) //后台运行, 5貌似是延时
driver.hideKeyboard()
driver.startActivity({appPackage: 'com.example.android.apis', appActivity: '.Foo'}, cb)
driver.openNotifications(cb);
driver.isAppInstalled("com.example.android.apis")
  .then(function (isAppInstalled) { /*...*/ })
driver.installApp("path/to/my.apk")
driver.removeApp("com.example.android.apis")
driver.closeApp()
driver.launchApp()
driver.resetApp()
driver.shake()
driver.contexts().then(function (contexts) { /*...*/ }) //List all available contexts
driver.currentContext().then(function (context) { /*...*/ })
driver.context() //SWITCH TO DEFAULT CONTEXT
driver.getAppStrings().then(function (appStrings) { /*...*/ })
driver.deviceKeyEvent(wd.SPECIAL_KEYS.Home) //send key event
driver.getCurrentActivity().then(function (activity) { /*...*/ })

//swipe
function swipe(opts) {
  var action = new wd.TouchAction(this);
  action
    .press({x: opts.startX, y: opts.startY})
    .wait(opts.duration)
    .moveTo({x: opts.endX, y: opts.endY})
    .release();
  return action.perform();
}
wd.addPromiseChainMethod('swipe', swipe);

// pinch
function pinch(el) {
  return Q.all([
    el.getSize(),
    el.getLocation(),
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2,
      y: loc.y + size.height / 2
    };
    var a1 = new wd.TouchAction(this);
    a1.press({el: el, x: center.x, y:center.y - 100}).moveTo({el: el}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el, x: center.x, y: center.y + 100}).moveTo({el: el}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
  }.bind(this));
};
wd.addPromiseChainMethod('pinch', pinch);
wd.addElementPromiseChainMethod('pinch', function() {
  return this.browser.pinch(this);
});
// ...
return driver.pinch(el);
// ...
return el.pinch();

// zoom
function zoom(el) {
  return Q.all([
    this.getWindowSize(),
    this.getLocation(el),
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2,
      y: loc.y + size.height / 2
    };
    var a1 = new wd.TouchAction(this);
    a1.press({el: el}).moveTo({el: el, x: center.x, y: center.y - 100}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el}).moveTo({el: el, x: center.x, y: center.y + 100}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
  }.bind(this));
};
wd.addPromiseChainMethod('zoom', zoom);
wd.addElementPromiseChainMethod('zoom', function() {
  return this.browser.zoom(this);
});
// ...
return driver.zoom(el);
// ...
return el.zoom();

// Scroll to an element.
return driver.elementByName().then(function (el) {
  driver.execute("mobile: scroll", [{direction: "down", element: el.value}]);
});

//Pulls a file from the device.
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb")
  .then(function (base64File) { /*...*/ })

// Pushes a file to the device.
driver.pushFile(path, data)

//SETTINGS
var settings = driver.settings();
browser.updateSettings({'someSetting': true});

12. wd.js在appium测试android的时候可以用哪些命令: 获取element

获取element有很多方式.

  • 使用id查找, driver.elementById("com.isen.trace.police:id/agree_use"),这也是AI录制下来的代码的默认方式.
  • 支持xpath查找, 不过xpath实在是长:
    let xpath = ' /hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.ScrollView/android.widget.LinearLayout/android.widget.Button[1]';
  let el = await driver.elementByXPath(xpath);
  • 支持按class查找el = await driver.elementByClassName('android.widget.Button', cb)

可是,上面的方式都需要我使用工具AI或者UIAV查看才知道怎么选中element. 能不能只看app界面就知道怎么选中element呢? 那就是下面这个方式了.

  • 支持使用android UIautomator api的UiSelectors. UiScrollable来查找元素.

怎么查找? 文档里里没说... google到appium论坛里面才知道方法,例如:

el = driver.elementByAndroidUIAutomator('new UiSelector().className(\"android.widget.Button\")',cb)

事实上就是把android命令直接作为字符串传入, android命令参考安卓的开发文档
那么看看能不能只知道element的文字(.text)就可以找到呢(假如文字可以唯一确定的话)? UiSelector文档是这样说的:

UiSelector().text(String text)
UiSelector().textContains(String text)
UiSelector().textMatches(String regex)
UiSelector().textStartsWith(String text)

假如一个控件,文字中包括"不同意"几个字, 可以这么写:

el = driver.elementByAndroidUIAutomator('new UiSelector().textContains("不同意")',cb)

13. wd.js在appium测试android的时候可以用哪些命令: 获取element的属性以用于测试期望值

//element可用的命令: element.xxxx()
element.getTagName(cb) -> cb(err, name)
element.clear(cb) -> cb(err) //清除input等输入区域的内容
element.isSelected(cb) -> cb(err, selected)
element.isEnabled(cb) -> cb(err, enabled)
element.isDisplayed(cb) -> cb(err, displayed)
element.getLocation(cb) -> cb(err, location)
element.getLocationInView(cb) -> cb(err, location)
element.getSize(cb) -> cb(err, size)
element.getOrientation(cb) -> cb(err, orientation)
element.tap(cb) -> cb(err)
element.click(cb) -> cb(err)

发送文本(不支持中文!)

element.setText("string", cb)
element.sendKeys("string", cb)
element.type("string", cb)

14. wd.js在appium测试android的时候可以用哪些命令: 虚拟按键

墙外: 安卓上所有按键的keycode在这儿
当然最好npm install -S keycode-for-android, 这样就好用多了.
主要的几个按键:
back 4
menu 82
home 37
volume_up 24
volume_down 25
volume_mute 164
power 26
示例:

driver.pressKeycode(4,cb) //返回键

常见问题

1. Session断了怎么重连?

如果连接已经断开, 首先要知道sessionID:

var sid
var sessions = await driver.sessions()
sid = sessions[0].id

如果连接还没有断开,可以显摆sessionId存下来:

sid = await driver.sessionId()

然后通过attach连接ID

await driver.attach(sid)

也有detach()断开连接.

2. 软键盘上的Search按钮无法用KEYCODE_SEARCH或者KEYCODE_ENTER触发?

appium git 论坛上有人提出了这个问题, 解决方式是运行:

await driver.execute( "mobile: performEditorAction", { "action": "search" } )

3. 如何选择automationName?

Android5.0以上支持 UiAutomator2, 以下支持UiAutomator1

4. 使用UIAV 截图,遇到XML解析错误怎么办?UIautomator viewer org.xml.sax.SAXParseException;

  1. 关掉Appium Inspector和Server.
  2. 重启模拟器.

5. 如何使用图片搜索?

很遗憾截止目前wd.js不支持, 只有Python和ruby支持. python下安装Appium-Python-Client

pip install Appium-Python-Client

Appium官方说明

npm install有些包的时候, 这些包总会在安装完之后运行一个post install的脚本, 这个脚本常常莫名其妙的导致一些问题, 其中一个就是要从不可访问的位置下载文件. 这些脚本总是自以为在哪儿都能下载任何地方的东西啊!
windows上幸好有cmder, 不过在设置菜单里面是没有proxy的设置的, 需要在命令行里面设置:

In cmder session:

Set http_proxy=http://[proxy]:[port]
Set https_proxy=http://[proxy]:[port]

In bash session:

export http_proxy=http://[proxy]:[port]
export https_proxy=http://[proxy]:[port]

In PowerShell session:

$env:http_proxy=http://[proxy]:[port]
$env:https_proxy=http://[proxy]:[port]

**

  1. python要print中文,文件最前面需要加入对utf8的支持,否则就会报错 Non-ASCII character 什么的
#-*- coding:utf-8 -*-
print('中文')

这样可以打印了,可是windows cmd打出来的是乱码?怎么办?

  1. python在windows cmd界面打印乱码,需要改windows cmd的编码。命令是:
chcp 65001

改回gbk编码命令是:

chcp 936

如果想在python打印前自动更改,可以在python中调用这条命令

import subprocess

def toUTF8():
    process = subprocess.Popen(['chcp', '65001'], shell=True)
    process.communicate()
    return

toUTF8()
  1. 乱码问题得到解决!如果想打印颜色呢?

python有个库叫做termcolor,先安装pip install termcolor
然后在代码中

from termcolor import colored
print(colored('some red text', 'red'))

还可以参考这儿**

python中没有像c一样的bool_value ? value_if_true : value_if_false的三元运算,替代方案是:

value_if_true if bool_value else value_if_false