首页 文章 精选 留言 我的

精选列表

搜索[ATH事业群],共10000篇文章
优秀的个人博客,低调大师

勒索软件eCh0raix衍生出新变种:可感染QNAP和群晖NAS设备

根据安全公司 Palo Alto Networks 的最新报告,知名勒索软件 eCh0raix(也称 QNAPCrypt)近日衍生出一个新变种,现在可以感染 QNAP 以及 Synology 网络附加存储(NAS)设备。 去年 9 月,Palo Alto Networks 就发现了这种新型 eCh0raix 变种,该勒索软件活动的项目名称为“rct_cryptor_universal”,表明该恶意软件可以影响任何供应商。早些时候,该项目名称为"qnap_crypt_worker",因为它将使用不同的变体经常在不同的实例上感染 QNAP 和 Synology 设备。 eCh0raix 是在 2016 年肆虐的一款勒索软件,当时它只是攻击 QNAP NAS 系统,因此也被称之为 QNAPCrypt。随后该勒索软件不断进化,在 2019 年和 2020 年再次对 QNAP 设备进行了攻击。 新型 eCh0raix 变种目前编号为 CVE-2021-28799。早在4月,QNAP 已经确认该漏洞是 HBS 3(混合备份同步3)中的"不当授权漏洞"。该公司进一步补充说,它已经在以下HBS 3版本中修复了这个黑客。 QTS 4.5.2: HBS 3 v16.0.0415及以后的版本 QTS 4.3.6: HBS 3 v3.0.210412及以后版本 QTS 4.3.3和4.3.4: HBS 3 v3.0.210411及以后版本 QuTS hero h4.5.1: HBS 3 v16.0.0419及以后版本 QuTScloud c4.5.1 ~ c4.5.4: HBS 3 v16.0.0419及以后版本 与受影响的Synology系统的安全固件版本相关的信息还不存在。根据Cortex Xpanse的数据,QNAP和Synology总共有大约25万台受影响的设备。

优秀的个人博客,低调大师

一个奇怪的MySQL慢查询,打懵了一群不懂业务的DBA!

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 前言 最近,开发人员需要定期的删除表里一定时间以前的数据,SQL如下: mysql > delete from testtable WHERE biz_date <= '2017-08-21 00:00:00' AND status = 2 limit 500\G 前段时间在优化的时候,我们已经在相应的查询条件上加上了索引,如下: KEY `idx_bizdate_st` (`biz_date`,`status`) 但是实际执行的SQL依然非常慢,为什么呢,我们来一步步分析验证下。 分析 表上的字段既然都有索引,那么按照之前的文章分析,是两个字段都可以走上索引的。 既然能够利用索引,表的总大小也就是200M左右,那么为什么形成了慢查呢? 我们查看执行计划,去掉limit 后,发现他选择了走全表扫描。 mysql > desc select * from testtable WHERE biz_date <= '2017-08-21 00:00:00'; +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | testtable | ALL | idx_bizdate_st | NULL | NULL | NULL | 980626 | Using where | +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ 1 row in set (0.00 sec) -- 只查询biz_date -- 关键点:rows:980626;type:ALL mysql > desc select * from testtable WHERE biz_date <= '2017-08-21 00:00:00' and status = 2; +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | testtable | ALL | idx_bizdate_st | NULL | NULL | NULL | 980632 | Using where | +----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+ 1 row in set (0.00 sec) -- 查询biz_date + status -- 关键点:rows:980632;type:ALL mysql > desc select * from testtable WHERE biz_date <= '2017-08-21 00:00:00' and status = 2 limit 100; +----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+ | 1 | SIMPLE | testtable | range | idx_bizdate_st | idx_bizdate_st | 6 | NULL | 490319 | Using index condition | +----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+ 1 row in set (0.00 sec) -- 查询biz_date + status+ limit -- 关键点:rows:490319; mysql > select count(*) from testtable WHERE biz_date <= '2017-08-21 00:00:00' and status = 2; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.34 sec) mysql > select count(*) from testtable WHERE biz_date <= '2017-08-21 00:00:00'; +----------+ | count(*) | +----------+ | 970183 | +----------+ 1 row in set (0.33 sec) mysql > select count(*) from testtable; +----------+ | count(*) | +----------+ | 991421 | +----------+ 1 row in set (0.19 sec) mysql > select distinct biz_status from testtable; +------------+ | biz_status | +------------+ | 1 | | 2 | | 4 | +------------+ 通过以上查询,我们可以发现如下几点问题: 通过 biz_date 预估出来的行数 和 biz_date + status=2 预估出来的行数几乎一样,为98w。 实际查询表 biz_date + status=2 一条记录都没有。 整表数据量达到了99万,MySQL发现通过索引扫描需要98w行(预估) 因此,MySQL通过统计信息预估的时候,发现需要扫描的索引行数几乎占到了整个表,放弃了使用索引,选择了走全表扫描。 那是不是他的统计信息有问题呢?我们重新收集了下表统计信息,发现执行计划的预估行数还是一样,猜测只能根据组合索引的第一个字段进行预估(待确定)。 那我们试下直接强制让他走索引呢? mysql > select * from testtable WHERE biz_date <= '2017-08-21 00:00:00' and status = 2; Empty set (0.79 sec) mysql > select * from testtable force index(idx_bizdate_st) WHERE biz_date <= '2017-08-21 00:00:00' and status = 2; Empty set (0.16 sec) 我们发现,强制指定索引后,查询耗时和没有强制索引比较,的确执行速度快了很多,因为没有强制索引是全表扫描嘛!但是!依然非常慢! 那么还有什么办法去优化这个本来应该很快的查询呢? 大家应该都听说过要选择性好的字段放在组合索引的最前面? 选择性好的索引在前面并不是对所有的场景都通用的,这个场景可以将status放前面,sql速度会更快。 那,能不能让他不要扫描索引的那么多范围呢?之前的索引模型中也说过,MySQL是通过索引去确定一个扫描范围,如果能够定位到尽可能小的范围,那是不是速度上会快很多呢? 并且业务逻辑上是定期删除一定日期之前的数据。所以逻辑上来说,每次删除都是只删除一天的数据,直接让SQL扫描一天的范围。那么我们就可以改写SQL啦! mysql > select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' and status = 2; Empty set (0.00 sec) mysql > desc select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' and status = 2; +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ | 1 | SIMPLE | testtable | range | idx_bizdate_st | idx_bizdate_st | 6 | NULL | 789 | Using index condition | +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ 1 row in set (0.00 sec) -- rows降低了很多,乖乖的走了索引 mysql > desc select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' ; +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ | 1 | SIMPLE | testtable | range | idx_bizdate_st | idx_bizdate_st | 5 | NULL | 1318 | Using index condition | +----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+ 1 row in set (0.00 sec) -- 即使没有status,也是肯定走索引啦 小结 这个问题,我原本打算用hint,强制让他走索引,但是实际上强制走索引的执行时间并不能带来满意的效果。结合业务逻辑,来优化SQL,是最好的方式,也是终极法宝,一定要好好利用。不了解业务的DBA,不是一个好DBA... 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/zhibo 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-04-24本文作者:互联网架构师 本文来自:“互联网架构师 微信公众号”,了解相关信息可以关注“互联网架构师”

优秀的个人博客,低调大师

这群少年让HR眼红创投青睐软件民工哭泣,80后不怕被干掉,因为…

在IT业,英雄往往出自少年郎。没错,我们都知道: ● 比尔盖茨创办微软的时候,20岁; ● 小扎创办Facebook的时候,不到20岁; ● Evan Spiegel创办Snapchat的时候,21岁; ● 乔布斯创办苹果的时候,21岁; 但,真正刺激人的不是这些遥不可及的名人,而是那些长江后浪推前浪的后辈们。看着那些比你聪明的人比你更努力,比你小一轮的人已经拥有了超强的技术能力,甚至拿到核心技术专利.....你还敢说余生且长,成功尚早吗?比如看这位邻家姑娘的故事。 后生不畏逐风浪 IT大赛弄新潮 8月,在广州酷热的天气里,当同学在LOL不亦乐乎,当打工一族乘着老板不在,偷开淘宝去扫货的时候。徐铭琪正在实验室敲着代码做实验项目,这个暑假,她没有回家也没有去旅行,而是选择留校在老师的实验室学习。也因此,她结实了郑沛霖、杨展富两位搭档,也有了后来联合参赛广东省“品高高校杯”软件作品设计大赛的故事。 作为中山大学数学学院应用统计专业大四学生,徐铭琪喜欢夜跑,喜欢科幻相关的书籍电影电视剧。典型的工科女生行头——黑框眼镜、马尾辫、双肩包,条纹T恤,完全掩盖了她作为学霸!学霸!!学霸!!!的事实。 10月29日,2016第25届广东省“品高高校杯”软件作品设计大赛在广东外语外贸大学(大学城校区)举行,至此大赛完美落幕。 来自中山大学的郑沛霖、徐铭琪、杨展富的“基于高性能计算集群机器学习的交通大数据分析系统”项目,获得在场评委的高度赞扬,同时摘得大赛一等奖及“品高奖”,成为本次大赛的大赢家。 比赛结束后,广东省公安厅领导对该项目表现出浓厚兴趣,还与品高云相关人员一同到中山大学与项目成员们交流,共同探讨项目的落地可行性与后续合作可能性。 记得赛后小表妹与郑沛霖团队进行了这样一段对话: 小表妹:恭喜各位夺得大奖成为本次大赛的最大赢家,你们是处于什么考虑会来参赛? 郑沛霖:当时我自己在这个郑老师这个试验室学习,后来就说到有这么一个比赛,让谁参加,然后发现我们现有的数据集很符合这个项目里面高性能计算,包括软件创新这些的要求。所以就决定去参加这个比赛。 小表妹:你们的项目成员是怎么召集在一起参赛的呢? 徐铭琪:因为我们都是郑老师试验室的学生,所以我们干脆就一起做。 郑沛霖:一开始是我们两个做,后来我们感觉力不从心。就加了一个大三的师弟杨展富进来,他在写数据与处理数据方面提供了莫大的帮助。很可惜,决赛当天和今天他都因为人在外地没有来。 小表妹:大概的分工是怎么样的? 郑沛霖:铭琪负责搞模型,还有一些数据的处理,包括天气什么的。这些数据的补充就是由展富做的,然后我就负责去把这些部署到品高云上,还有做一些整体的前端,把处理出来的数据进行的可视化。 小表妹:我听说这个项目只准备了两个多月,是吗? 郑沛霖:对。 徐铭琪:断断续续的在做这个东西吧,一暑假。 小表妹:过程中有没有觉得特别困难的地方? 郑沛霖:快到deadline的时候很辛苦了,最大压力是在九月底的时候,就是快到deadline就拼命改,拼命改,那段时间还是比较辛苦的,别的时间还好。 小表妹:那有没有一些有趣的事情?或者是一些特别的故事? 郑沛霖:要说的话,要说说我大三的时候参加过另一个比赛,当时觉得我们团队是最强实力的,结果最后被刷了,心有不甘,很不服。后来听到这个是广东省的软件设计竞赛,是品高云赞助的。之前就有听说过品高云是一家挺有本土风范的云计算厂商,起码在国内是有机会和AWS、阿里云他们拼一枪的。而且品高云在这个比赛里提供了一些高性能的集群,可以给我们用,我们团队本身对这个高性能集群挺有兴趣的,所以决定再尝试一下。 小表妹:在决赛完成答辩的时候,觉得自己表现怎么样?对最后的结果有信心吗? 郑沛霖:本来还挺有信心的。但是因为当时演讲开头一点小插曲,演示的电脑断电了。弄了挺久,还好后来发挥还是比较正常。 小表妹:那这次品高杯决赛算是如愿以偿了哦。你们得到了一等奖和品高奖双冠王,有没有什么话想跟导师说呢? 徐铭琪:感谢他给我们提供了这个机会。 郑沛霖:谢谢他从大三下学期以来就在数据挖掘方面给一些指导,包括为我们这次比赛提供了很多(帮助)比如说数据的支援,还有一些功能和需求分析上的指导。 徐铭琪:还有给我们提供了良好的实验室的环境,实验室的资源还是蛮丰富的。 小表妹:你们比赛完后,还有没有其他的计划,你们呢? 郑沛霖:补作业。 小表妹:。。。 赛后,表妹获悉,徐铭琪已保研到上海交通大学应用统计专业。 徐铭琪,只是无数职场精英后备军的一员。他们正被创投机构青睐,视为下一个金矿产业的开拓者;被各大IT公司的HR视为眼中宝,唯恐抢之不急。 必须承认,他们就是未来。 本文转自d1net(转载)

优秀的个人博客,低调大师

EasyClick苹果群控发短视频脚本怎么写?一份能直接跑的完整代码

## 六个账号,每天四小时 老陈做本地生活,手上六个短视频账号,每天各发一条探店视频。这个规模的短视频矩阵,卡人的地方从来不是剪片子,是发片子。 流程是这样的:素材提前剪好放电脑里,第二天早上挨个账号操作——传到手机相册、打开 App、找到发布入口、选视频、写标题、挂话题、点发布、等它传完、再确认有没有成功。一条视频六分钟,六个账号下来四十分钟上下。加上中途被打断、某个号卡在"上传中"要重来,实际每天耗掉的时间接近四小时。 他想把这段变成"早上点一下就好"。 这篇文章就是把这条链路写成脚本的完整过程。**每一步都给代码,并且注明官方文档里的函数签名和返回值约定**——因为写这种脚本最耗时间的不是逻辑,是搞清楚每个函数到底返回什么。 先说一个前提:文中所有函数名都来自 EasyClick iOS 版官方文档,逐条核对过。写 iPhone自动化 脚本最耗时间的其实不是逻辑,是搞清楚每个函数到底返回什么。**但目标 App 的包名、界面结构、坐标需要你换成自己的**,这部分我没法替你定。 下面这套EasyClick iOS自动化脚本 的写法,抖音、快手、视频号、TikTok 这类短视频 App 都适用,差别只在包名和界面元素上——你把这两处对着自己的目标 App 改掉就行。 --- ## 先看清一条视频是怎么发出去的 写代码之前先把流程拆开,标清楚每一步该用哪个能力: | 步骤 | 做什么 | 用什么 | | --- | --- | --- | | 1 | 视频进相册 | 工具栏「上传视频」或 `utils` 相册接口 | | 2 | 打开目标 App | 中控里右键运行,或 HTTP 接口 `openApp` | | 3 | 等界面真的就绪 | 节点抓取 + 按文案查询 | | 4 | 进发布页 | 节点点击,或坐标点击 | | 5 | 选相册里的视频 | 节点点击 | | 6 | 填标题和话题 | 输入法接口 `imeApi` | | 7 | 点发布并校验 | 节点点击 + 二次查询 / 截图 | 七步里,**第 1、3、7 步是最容易出问题的**,后面会逐个说。这套流程用苹果自动化脚本 跑通之后,多账号运营 真正省时间的不是单条变快,而是「六个号都发到了」这件事不再需要你去确认。 ![中控主界面-暗黑主题-概览.jpg](https://developer.qcloudimg.com/http-save/yehe-1989031/fc2057f1938bb384b6ded53d5e1beb87.jpg) --- ## 环境准备:先确定你用哪条链路 同样的业务逻辑,在不同链路上要调用不同的事件模块: | 链路 | 事件模块 | 系统要求 | 需要什么 | | --- | --- | --- | --- | | 代理模式 | `agentEvent` | iOS 13+ | 签名 IPA | | USB HID | `usbHidEvent` | **iOS 17+** | 一根数据线 | | 蓝牙 BLE | `bleEvent` | iOS 17+ | ESP32 开发板 | | OTG HID | `otgEvent` | iOS 17+ | 开发板 + 转接头 | iOS 17 这个门槛要特别注意:官方文档写得很直接——**USB HID 和蓝牙 BLE 都要求 iOS 17 及以上,低于 iOS 17 请使用代理模式**。手上是老机器的话,别在这上面浪费时间。 好消息是**四个模块的方法名完全一致**:都叫 `clickPoint`、`swipeToPoint`、`doubleClickPoint` 这些。所以业务逻辑写一遍,换链路只改模块名。设计脚本时这一点值得利用——把点击操作包一层,链路切换只改一处。 ### 脚本骨架 不管走哪条链路,开头都是这套: ```javascript function main() { logd("检查自动化环境..."); if (!autoServiceStart(3)) { logw("自动化服务启动失败,无法执行脚本"); exit(); return; } // 节点抓取参数,脚本开头设一次就够 setFetchNodeParam({ "labelFilter": "2", // 只取有 label 的节点 "visibleFilter": "2", // 只取 visible=true 的 "maxDepth": "20", // 层级,越少越快,建议 1-500 "excludedAttributes": "visible,selected,enable,accessible" }); // ... 业务代码 logd("脚本执行结束"); } // 环境检查:官方示例里的写法,直接用 function autoServiceStart(time) { for (let i = 0; i < time; i++) { if (isServiceOk()) { return true; } let started = startEnv(); logd("第" + (i + 1) + "次启动服务结果: " + started); if (isServiceOk()) { return true; } } return isServiceOk(); } main(); ``` 两个细节值得说明: `autoServiceStart` 不是系统函数,是**官方示例里给出的辅助写法**——循环调用 `startEnv()` 并检查 `isServiceOk()`,最多试 `time` 次。这个模式比自己写一个 `sleep(5000)` 再赌它能起来可靠得多。 注意这段骨架是代理模式的写法。 走 USB HID 链路的话,开头要换成 HID 自己的会话启动: ```javascript let r = usbHidEvent.sessionStart(true); // 参数是"是否尝试增强兼容模式",默认 true if (!(r == null || r === "")) { logw("开启 HID 会话失败: " + r); return; } r = usbHidEvent.setScreenSize(1170, 2532); // 坐标换算依赖这个 ``` `setScreenSize` 这一步在 HID 链路上是**必须的**,它的参数要和你投屏、截图的分辨率一致;换了设备或者横竖屏切过,都要重新设一次,否则所有坐标都会偏。蓝牙和 OTG 链路同理,用的是各自模块的会话接口。 `setFetchNodeParam` 的 `excludedAttributes` 是提速的关键。文档原话是「可以增加抓取速度」——设备多的时候,少抓几个用不上的属性,累积下来差异很明显。 --- ## 第一步:把视频放进相册 这是第一个坑,因为**两条链路的做法完全不同**。 ### 代理模式 / 脱机主程序(iOS 15+) 用投屏右侧工具栏的**上传视频**按钮,或者在小屏幕上右键 → 图片视频。**可以用「选择文件夹」批量上传**,一次把当天要发的片子都推进去。 ### HID 链路(没装代理 IPA) 官方文档给了完整步骤,必须在手机上先建一条快捷指令: 1. 在「快捷指令」App 里新建一条指令,名字叫 **iOS USB插入视频或图片到相册** 2. 到手机「设置 → 辅助功能 → 键盘与键入 → 全键盘打开 → 命令」,下拉找到「快捷指令 → iOS USB插入视频或图片到相册」 3. 之后用 HID 快捷键发送上传 少做这一步,HID 链路上视频根本进不了相册——很多人卡在这里以为是脚本问题。 ### 相册相关的脚本接口 ```javascript // 首次使用先请求相册权限(会弹窗,需要人工点一次允许) utils.requestPhotoAuthorization(); // 需要清空时(注意:有确认弹窗,需要模拟点击删除按钮) utils.deleteAllVideos(); utils.deleteAllPhotos(); ``` 两个必须知道的行为: 这些调用是异步的,不要依赖返回值。 文档明确写了「防止卡住不能模拟点击,请忽略返回值」。 清空操作不可恢复。 而且**调用时会出现确认弹窗,需要你模拟点击删除按钮**——这也是为什么它不能直接无条件用。试跑前一定确认设备和路径。 --- ## 第二步:打开 App,并等到界面真的就绪 "打开 App"和"界面可用"是两件事。App 图标点开了,启动页还在转,这时候去找发布按钮必然找不到。 打开这个动作本身有两种做法: 做法一:在中控里选中设备,右键执行脚本。适合手工触发。 做法二:走 HTTP 接口,适合和外部系统对接。文档给的接口是: ``` POST http://127.0.0.1:8019/openapi/openApp {"deviceId": "设备ID", "bundleId": "目标App包名"} ``` ![06-相册接口-用来操作相册-上传视频图片等.jpg](https://developer.qcloudimg.com/http-save/yehe-1989031/fd29e673c5c1a45e0a88e30f3ee546ca.jpg) 端口 8019 是中控地址,官方同时给了 Python、Node.js、cURL、C# 四种调用示例。 打开之后**不要写固定等待**,而是按节点文案去查: ```javascript const BUNDLE_ID = "com.example.shortvideo"; // ← 换成你的目标 App 包名 // 打开 App(中控里右键执行时可以省略这段,用界面操作代替) // 查询发布入口是否出现,这一步同时起到"等加载"的作用 releaseNode(); // 先释放上一轮节点数据 lockNode(); // 锁定当前界面节点 let entry = labelMatch(".*发布.*").getOneNodeInfo(15000); // 最多等 15 秒 if (!entry) { logw("15 秒内没找到发布入口,可能还在加载,也可能界面变了"); image.captureFullScreen(); // 截图留证 exit(); return; } ``` 这里有几个官方文档里的关键点: 节点查询是链式写法。 `labelMatch("正则").getOneNodeInfo(超时毫秒)`,不是传一个配置对象进去。可用的筛选器有 `id`、`idMatch`、`label`、`labelMatch`、`name`、`nameMatch`、`type`、`typeMatch`、`value`、`valueMatch`、`xpath`,以及 `visible`、`enable` 这类属性匹配。 `getOneNodeInfo(超时)` 里的超时就是你天然的元素等待。 传 15000 就是"最多等 15 秒",比 `sleep(15000)` 好得多——元素提前出现它会立刻返回。 每次查询前先 `releaseNode()` 再 `lockNode()`。 官方示例固定这么写:先释放老数据,再锁定新数据。不释放的话可能拿到上一屏的节点。 --- ## 第三步:找「发布」按钮,三种定位方式怎么选 这是全文最实用的一节。 | 方式 | 用什么 | 什么时候用 | 什么时候用不了 | | --- | --- | --- | --- | | **节点定位** | `labelMatch(...)`、`id(...)` | 界面元素有文字或可读属性 | HID / 蓝牙 / OTG 链路不支持节点选择器 | | **图色找图** | `image.findImage`、模板匹配 | 入口是图标、没有文字 | 界面样式一改就要重做模板 | | **视觉定位** | 工作流里的 VLM 定位步骤 | 界面树抓不到,需要"看得懂" | 需要配大模型 | 节点定位优先 ,因为它按文字找,界面挪位置不影响: ```javascript let btn = labelMatch("发布").getOneNodeInfo(5000); if (btn) { btn.clickCenter(); // 直接点节点中心 } else { logw("没找到发布按钮"); } ``` 节点对象上可用的东西(官方文档里列出的):`id`、`xpath`、`label`、`name`、`type`、`value`、`bounds`、`index`、`depth`、`visible`、`enable`,以及方法 `clickCenter`、`clickRandom`、`parent`、`child`、`allChildren`、`siblings`、`previousSiblings`、`nextSiblings`。 节点找得到但点不动的时候,用坐标兜底: ```javascript let nd = labelMatch("发布").getOneNodeInfo(5000); if (nd) { // 用节点自己的坐标点,比自己量坐标稳 clickPoint(nd.bounds.centerX(), nd.bounds.centerY()); } ``` `bounds.centerX()` / `centerY()` 是从节点直接算出来的坐标,**比手工量坐标可靠**——换机型、换分辨率都不用改。 如果确实要用硬坐标,注意坐标和投屏画面、截图的像素坐标是同一套。**分辨率变了或者横竖屏切过,必须先重新设置屏幕尺寸**,否则全偏。 --- ## 第四步:填标题和话题 这一步的动作本身很简单,但有一个**新手必踩的坑**。 ```javascript // 输入标题 if (imeApi.isOk()) { let r = imeApi.input("今天的探店:巷子口那家面馆"); logd("输入结果: " + r); } // 话题建议走剪贴板,长文本更稳 imeApi.setClipboard("#探店 #本地生活 #今日推荐"); imeApi.paste(); // ⚠️ 这一步不能省:收起键盘 imeApi.dismiss(); ``` 为什么 `imeApi.dismiss()` 必须写? 因为输入完标题,键盘会一直占着下半屏,而发布按钮往往就在键盘下面。不收起键盘,你点下去落在键盘上,按钮根本没被点到。这个失败不报错,只表现为"一直没发出去",很难查。 `imeApi.input(content)` 的返回值要注意:**空字符串代表输入不成功,非空代表实际输入的内容**。所以不能只判断 `!= null`。 如果是 HID 链路,输入是另一套: ```javascript usbHidEvent.inputText("今天的探店"); // 走剪贴板粘贴 usbHidEvent.typeText("Today's store"); // 需要键盘打字时用,遇非英文会自动粘贴 ``` 文档有个提示:往手机打英文如果总是多出空格,去手机「设置 → 通用 → 键盘」关掉**智能标点**。 --- ## 第五步:点发布,然后确认真的发出去了 点发布只是一行代码,难的是**确认**。 ```javascript let pub = labelMatch("发布").getOneNodeInfo(3000); if (pub) { pub.clickCenter(); } else { logw("发布按钮不见了,可能已经被点过,或者界面变了"); exit(); return; } // 等发布结果,不要用固定 sleep releaseNode(); lockNode(); let ok = labelMatch(".*发布成功.*").getOneNodeInfo(20000); if (!ok) { logw("20 秒内没看到成功提示,需要人工确认"); image.captureFullScreen(); // 截图存证,事后好排查 } else { logd("发布成功"); } ``` 为什么校验这一步不能省? 因为短视频发布失败经常是**静默的**:不弹错误,只是停在草稿箱,或者一直显示"上传中"然后悄悄停了。不写校验,你可能两天后才发现某个号少发了好几条。 需要 OCR 时,工作流里可以用 `ocr_screen_auto` / `ocr_screen_no_auto`,引擎可选 `paddleOcrNcnnV5`(默认)、`v5`、`v4`、`ocrLite`。脚本里对应的是 `image.captureFullScreen()` 截图后再走 OCR 接口。 ![04-中控右键菜单-可以暂停脚本或者继续执行脚本.jpg](https://developer.qcloudimg.com/http-save/yehe-1989031/6a330c2ea31f20be321b47e636783b9e.jpg) --- ## 串起来:一份完整脚本 把前面几段合成一份,可以直接复制到 IDEA 里改包名跑: ```javascript const BUNDLE_ID = "com.example.shortvideo"; // ← 改成你的目标 App const TITLE = "今天的探店:巷子口那家面馆"; const TOPICS = "#探店 #本地生活"; function main() { logd("=== 短视频发布开始 ==="); if (!autoServiceStart(3)) { logw("自动化服务启动失败"); exit(); return; } setFetchNodeParam({ "labelFilter": "2", "visibleFilter": "2", "maxDepth": "30", "excludedAttributes": "visible,selected,enable,accessible" }); // 1. 等发布入口出现(同时充当加载等待) if (!waitAndClick(".*发布.*", 15000)) { logw("找不到发布入口,退出"); shotForDebug(); exit(); return; } // 2. 选中相册里最新的那条视频 if (!waitAndClick("相册", 8000)) { logw("进不了相册"); exit(); return; } clickPoint(195, 640); // ← 第一条视频的位置,按自己屏幕量 sleep(800); if (!waitAndClick("下一步|确定", 8000)) { logw("视频没选上"); exit(); return; } // 3. 填标题 if (imeApi.isOk()) { imeApi.input(TITLE); } imeApi.setClipboard(TOPICS); imeApi.paste(); imeApi.dismiss(); // ⚠️ 必须收起键盘 // 4. 发布 if (!waitAndClick("发布", 8000)) { logw("发布按钮点不到"); exit(); return; } // 5. 校验 releaseNode(); lockNode(); if (labelMatch(".*发布成功.*").getOneNodeInfo(20000)) { logd("=== 发布成功 ==="); } else { logw("没看到成功提示,需人工确认"); image.captureFullScreen(); } releaseNode(); } // 等节点出现并点击,返回是否成功 function waitAndClick(labelRegex, timeout) { releaseNode(); lockNode(); let nd = labelMatch(labelRegex).getOneNodeInfo(timeout); if (!nd) { return false; } clickPoint(nd.bounds.centerX(), nd.bounds.centerY()); return true; } function autoServiceStart(time) { for (let i = 0; i < time; i++) { if (isServiceOk()) return true; startEnv(); if (isServiceOk()) return true; } return isServiceOk(); } function shotForDebug() { image.captureFullScreen(); } main(); ``` 代码里几个值得留意的地方: `waitAndClick` 这个封包。 整套流程里"等元素 → 点它"出现了五次,包成一个函数之后主流程只剩五行,改超时、改点击方式都只改一处。 点击优先用节点坐标 (`nd.bounds.centerX()`),只有选中视频列表那一步用了硬坐标——因为列表项通常没有可读文案。那一步的坐标记得按自己屏幕量。 每一步失败都 `exit()` 加日志。 短视频发布是长链路,中间任何一步静默失败,后面都会以奇怪的方式报错。宁可早退。 --- ## 多台设备怎么跑 脚本在一台上跑通了,下一步是六个号一起发。矩阵号运营 最费力的一直是这件事——一条一条点,点到第四五个就开始糊弄。三种方式按投入排序: 方式一:中控分组批量执行(最省事) 把编译好的 iec 文件放进中控左下角「脚本目录」,右键 → 刷新 → 右键脚本 → 执行脚本,就会对当前选中的设备批量执行。设备多的话,先在左侧**分组栏**把手机分好组,再对分组执行。 这里有个容易搞混的地方:**执行脚本需要的是 USB 设备授权,投屏需要的是 USB 投屏授权,两者不是同一个授权**。买错授权是这个环节最常见的坑。 方式二:HTTP 接口下发 前面提过的 `POST /openapi/openApp`,配合其他动作接口,可以让外部系统驱动多台设备。适合把发布流程接到自己的后台或项目管理工具里。 方式三:工作流 + 定时 把脚本逻辑做成工作流,配合定时规则按点触发。要注意一条硬约束:**同一台设备同一时间只能跑一个任务**,多台才能并行。所以批量提速靠的是设备数量,不是单台并发。 另外并发上限可以在设置里调(单任务最大设备数),改完需要重启。 排期上有个建议:六个号不要排在同一分钟。手机端发内容,时间分布太整齐本身就不是正常特征。错开几分钟,或者按分组错峰。 --- ## 排错清单 按"现象 → 先查什么"整理,都是文档里给过的: | 现象 | 先查什么 | | --- | --- | | 鼠标点手机没反应 | 设备小屏或设备列表上右键 → USB HID → **重建 USBHID 会话** | | 改过投屏方式后画面不正常 | **重启手机**再试 | | 电脑往手机打英文多出空格 | 手机「设置 → 通用 → 键盘」关掉**智能标点** | | 界面变了、节点找不到 | 先截图看当前停在哪一屏,再按新文案改匹配 | | 多台一起跑变慢 | 设置里调大单任务最大设备数,改后**重启** | | 想确认实际连了几台 | 浏览器打开 `127.0.0.1:8020/devapi/devicenum` | | 内存一直往上涨 | 调中控的 `ioscenter.vmoptions`,或访问 `127.0.0.1:8020/devapi/gc` 手动回收 | | 要看是哪一步出的错 | 执行历史 + 实时日志,按设备逐步看 | --- ## 哪些活别交给脚本 最后说清楚边界。 脚本负责的是**把已经做好的内容按时发出去**:传素材、开 App、选视频、填字段、点发布、校验结果。这六件事它比人稳,因为它不会做到第四个号就开始糊弄。 但下面这几件留给人:**选题、文案、封面、评论区的互动**。这几件事的价值恰恰在于每次都不一样,交给脚本等于把账号做死。 还有一个更实际的提醒:**别用脚本去刷数据**。发布流程自动化解决的是效率,不是数量。用多个号给同一批内容凑互动,那是另一回事,而且账号会先出问题。 --- 把这条链路跑通之后,老陈早上做的事变成:看一眼前一天的发布结果,确认六个号都发出去了,然后花时间在选题和文案上——那部分才是真正影响播放量的。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册