自动抢红包,点赞朋友圈,AccessibilityService解放你的双手

引言node

其实这一篇原本不是写这个的,在周一开始想作的时候就想好了标题:
《Android与Python的巧妙结合抓取公众号全部历史文章》
搜狗仅显示最近10条群发,想作爬公号历史文章的应该都了解过,
并且文章也愈来愈很差抓了,而利用无障碍服务+Python实现的思路很简单:android

  • 1.写一个无障碍服务,在输入完公众号名字保存后,跳转到公众号历史信息
  • 2.而后获取每条记录,点击进入,右上角复制连接,保存起来
  • 3.当前页面的获取完,滚动加载更多,继续获取
  • 4.直到获取到已无更多的节点,表明获取完毕
  • 5.把这个存有全部连接的文件发送到PC电脑
  • 6.而后多线程+代理ip访问连接,新建一个文章对应的文件夹,保存为HTML文件
  • 7.利用之前写过的抓取微信文章里图片,音频,视频的脚本把数据爬到本地
  • 8.替换HTML对应资源处的href连接,指向本地资源

之因此要执行第八步的缘由是保存到本地的HTML直接打开不少图片都会裂开(连接失效)
而后呢,我花了三天都没折腾出来,最终卡在没法得到微信x5浏览器网页节点
这个节骨眼 上,没法再进分毫...git

无障碍服务利用的是UI Automation,而后呢,这玩意是不支持WebView的!!!
尽管能遍历打印出结点的信息,可是模拟点击一点用都没有...
webview里的东西,AccessibilityService就无能为力了。我...
github

后来群里童鞋说移动端自动化测试框架Appuim支持webview,我立马花了半天 去撸文档(不得不说相比起AccessibilityService只能依靠res-id和text来查找 节点,appium支持xpath等方式,找节点,不能爽太多,
不过缺点的话是 反应会慢一些,特别是在edittext输入的时候),可是这里有个坎又把我给卡住了 appuim
每次运行本身的脚本,微信都须要从新登陆,每次运行都要登陆的结果 就是:个人三个小号由于登陆过于频繁,
当天都没法登陆了... (有知道如何规避每次运行脚本都要从新的登陆的务必告知下~) 放弃了,太耗费时间了!web

另外还有一个套路是微信利用的x5浏览器,能够在微信里打开这个连接: debugx5.qq.com 接着选择信息,勾选:chrome

接着打开谷歌浏览器,输入:chrome://inspect/#devices 接着随手打开一篇文章,就会有这样的东西:浏览器

点击inspect,而后能够获得整个页面的结构,能够拿到和 搜狗获取的同样类型的文章连接,连接很长,并且失效都是12小时微信

若是是手机用户点击查看文章,而后复制连接,是这样的短链接,
时效还不知道是多久(Maybe永久):http://mp.weixin.qq.com/s/O00w469tkOrr507drGln9A
多线程

关于如何得到微信公众号历史文章目前知道的比较简单的套路就这些, 至于抓包破解之类的,
目前level还不够,折腾不过来,先放一放, 后面说不定get√了新的姿式点,问题一会儿就解了呢?嘿嘿~app

另外爬取微信文章里图片,音频视频可见以前写过的: 小猪的Python学习之旅 —— 10.三分钟上手Requests库

上节利用AccessibilityService实现了自动加好友和拉人进群聊,感受还没用起来,
这不,又加了自动抢红包和朋友圈自动点赞~

另外,在AccessibilityService除了Webview这个坑外,经过red-id来 查找控件,
在每一个版本的APP中均可能是不同的,好比微信就是, 本节代码仅保证在6.6.6版本上是可用的,
其余版本须要你自行去 适配啦!另外,项目是用Kotlin写的哈,顺道复习一波语法~


1.自动抢红包

这个确定是没有xposed抢得快的,就是监听Notification信息,若是有 微信红包的字眼,自动打开聊天页面,遍历列表,找到未打开的红包, 自动点开,领取后自动关闭。

运行效果图

啧啧,三个红包几下子就抢完了,速度仍是杠杠的,了解了原理,之后换其余 应用,好比钉钉之类的,另外这个脚本目前只支持抢页面可见的红包, 能够开启listview滚动监听,滑动的时候去判断页面有无红包,而后抢。 不过监听了这个玩意的话,页面会挺卡的,不建议开启,本身点红包, 直接就能开了~


2.朋友圈自动点赞

这个功能就不说啦,及时点赞,拉近同事朋友感情,天天点赞那么勤, 别人还觉得你对她有意思呢?啧啧,有兴趣的还能够自行扩展,对别 人的说说内容进行下过滤,根据不一样的内容发送不一样的评论~ 好比:

附:

PS:说想接入机器人自动回复评论的,只利用AccessibilityService的话就 别想了,大家怕是忘了AccessibilityService是用来优化残障人士的使用体验的吧... 若是要接机器人的话,考虑appuim自动化测试吧~

运行效果图

是的,就是这么屌~


小结

本节开始讲了下利用相似于按键精灵的套路得到公众号全部历史文章的套路, 接着写了两个很实用的实例,抢红包和朋友圈点赞,关于AccessibilityService 的东东基本也就那么多了,后续再折腾这些就该上xposed了~


附:关键代码(均可以在:github.com/coder-pig/W… 找到):

class HelperService : AccessibilityService() {

    private val TAG = "HelperService"
    private val handler = Handler()
    private var nameList = mutableListOf<String>()

    override fun onInterrupt() {
    }

    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        val eventType = event.eventType
        val classNameChr = event.className
        val className = classNameChr.toString()
        Log.d(TAG, event.toString())
        when (eventType) {
            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
                if (Hawk.get(Constant.RED_PACKET, false)) {
                    when (className) {
                        "com.tencent.mm.ui.LauncherUI" -> openRedPacket()
                        "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI" -> clickRedPacket()
                        "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI" -> performBackClick()
                    }
                    //com.tencent.mm:id/ad8
                }
                if (Hawk.get(Constant.ADD_FRIENDS, false) && Hawk.get(Constant.GROUP_NAME, "") != "") {
                    when (className) {
                        "com.tencent.mm.plugin.subapp.ui.friend.FMessageConversationUI" -> addFriends()
                        "com.tencent.mm.plugin.profile.ui.SayHiWithSnsPermissionUI" -> verifyFriend()
                        "com.tencent.mm.plugin.profile.ui.ContactInfoUI" -> contactInfo()
                        "com.tencent.mm.ui.LauncherUI" -> openGroup()
                        "com.tencent.mm.ui.contact.ChatroomContactUI" -> {
                            if (nameList.size > 0) searchGroup() else performBackClick()
                        }
                        "com.tencent.mm.ui.chatting.ChattingUI" -> openGroupSetting()
                        "com.tencent.mm.plugin.chatroom.ui.ChatroomInfoUI" -> {
                            if (nameList.size > 0) addToGroup() else performBackClick()
                        }
                        "com.tencent.mm.ui.base.i" -> dialogClick()
                    }
                }
                if (Hawk.get(Constant.FRIEND_SQUARE,false)) {
                    if (className == "com.tencent.mm.plugin.sns.ui.SnsTimeLineUI") {
                        autoZan()
                    }
                }

            }
            AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED -> {
                if (event.parcelableData != null && event.parcelableData is Notification) {
                    val notification = event.parcelableData as Notification
                    val content = notification.tickerText.toString()
                    if (content.contains("[微信红包]")) {
                        val pendingIntent = notification.contentIntent
                        try {
                            pendingIntent.send()
                        } catch (e: PendingIntent.CanceledException) {
                            e.printStackTrace()
                        }

                    }
                }
            }
            //滚动的时候也去监听红包,不过有点卡
// AccessibilityEvent.TYPE_VIEW_SCROLLED -> {
// if (className == "android.widget.ListView") {
// openRedPacket()
// }
// }
        }
    }

    //添加好友
    private fun addFriends() {
        val nodeInfo = rootInActiveWindow
        if (nodeInfo != null) {
            val list = nodeInfo.findAccessibilityNodeInfosByText("接受")
            if (list != null && list.size > 0) {
                list[0].performAction(AccessibilityNodeInfo.ACTION_CLICK)
                val nameText: List<AccessibilityNodeInfo>? = list[0].parent.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/b8s")
                nameList.add(nameText?.get(0)?.text.toString())
            } else {
                performBackClick()
            }
        }
    }

    //完成验证
    private fun verifyFriend() {
        val nodeInfo = rootInActiveWindow
        if (nodeInfo != null) {
            val finishNode = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/hh")[0]
            finishNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        }
    }

    //好友详细资料页
    private fun contactInfo() {
        val nodeInfo = rootInActiveWindow
        if (nodeInfo != null) {
            val nameNode = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/q0")[0]
            Log.i(TAG, nameNode.toString())
            if (nameList.contains(nameNode.text.toString().trim())) performBackClick()
        }
    }

    //打开群聊
    private fun openGroup() {
        if (nameList.size > 0) {
            val nodeInfo = rootInActiveWindow
            if (nodeInfo != null) {
                val tabNodes = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/c9f")
                for (tabNode in tabNodes) {
                    if (tabNode.text.toString() == "通信录") {
                        tabNode.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                        handler.postDelayed({
                            val newNodeInfo = rootInActiveWindow
                            if (newNodeInfo != null) {
                                val tagNodes = newNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/jk")
                                for (tagNode in tagNodes) {
                                    if (tagNode.text.toString() == "群聊") {
                                        tagNode.parent.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                                        break
                                    }
                                }
                            }
                        }, 500L)
                    }
                }
            }
        }
    }

    //搜索群聊
    private fun searchGroup() {
        val nodeInfo = rootInActiveWindow
        if (nodeInfo != null) {
            val nodes = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/a9t")
            for (info in nodes) {
                if (info.text.toString() == Hawk.get(Constant.GROUP_NAME)) {
                    info.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                    break
                }
            }
        }
    }

    //打开群聊设置
    private fun openGroupSetting() {
        if (nameList.size > 0) {
            val nodeInfo = rootInActiveWindow
            if (nodeInfo != null) {
                nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/hi")[0].performAction(AccessibilityNodeInfo.ACTION_CLICK)
            }
        }
    }

    //添加到群聊里
    private fun addToGroup() {
        if (nameList.size > 0) {
            val nodeInfo = rootInActiveWindow
            if (nodeInfo != null) {
                val listNodes = nodeInfo.findAccessibilityNodeInfosByViewId("android:id/list")
                if (listNodes != null && listNodes.size > 0) {
                    val listNode = listNodes[0]
                    listNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
                    listNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
                    val scrollNodeInfo = rootInActiveWindow
                    if (scrollNodeInfo != null) {
                        handler.postDelayed({
                            val nodes = scrollNodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/cz1")
                            for (info in nodes) {
                                if (info.contentDescription.toString() == "添加成员") {
                                    info.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                                    break
                                }
                            }
                        }, 1000L)
                        handler.postDelayed({
                            val editNodes = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/arx")
                            if (editNodes != null && editNodes.size > 0) {
                                val editNode = editNodes[0]
                                val arguments = Bundle()
                                arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, nameList[0])
                                editNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)
                                nameList.removeAt(0)
                            }
                        }, 2300L)
                        handler.postDelayed({
                            val cbNodes = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/l7")
                            if (cbNodes != null) {
                                var cbNode: AccessibilityNodeInfo? = null
                                if (cbNodes.size == 1) {
                                    cbNode = cbNodes[0]
                                } else if (cbNodes.size == 2) {
                                    cbNode = cbNodes[1]
                                }
                                if (cbNode != null) {
                                    cbNode.parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                                    val sureNode = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/hh")[0]
                                    sureNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                                }
                            }
                        }, 3000L)
                    }
                }
            }
        }
    }

    //对话框处理
    private fun dialogClick() {
        val inviteNode = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/all")[0]
        inviteNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        handler.postDelayed({
            val sureNodes = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/all")
            if (sureNodes != null && sureNodes.size > 0) {
                val sureNode = sureNodes[0]
                sureNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
            }
        }, 1000L)
    }

    //自动点赞
    private fun autoZan() {
        val nodeInfo = rootInActiveWindow
        if (nodeInfo != null) {
            while (true) {
                val rootNode = rootInActiveWindow
                if (rootNode != null) {
                    val listNodes = rootNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ddn")
                    if (listNodes != null && listNodes.size > 0) {
                        val listNode = listNodes[0]
                        val zanNodes = listNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/dao")
                        for (zan in zanNodes) {
                            zan.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                            Thread.sleep(300)
                            val zsNodes = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/d_m")
                            Thread.sleep(300)
                            if (zsNodes != null && zsNodes.size > 0) {
                                if (zsNodes[0].findAccessibilityNodeInfosByText("赞").size > 0) {
                                    zsNodes[0].performAction(AccessibilityNodeInfo.ACTION_CLICK)
                                }
                            }
                            Thread.sleep(300)
                        }
                        listNode.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
                    }
                } else {
                    break
                }
            }
        }
    }

    //遍历得到未打开红包
    private fun openRedPacket() {
        val rootNode = rootInActiveWindow
        if(rootNode != null) {
            val listNode = rootNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/a_c")
            if (listNode != null && listNode.size > 0) {
                val msgNodes = listNode[0].findAccessibilityNodeInfosByViewId("com.tencent.mm:id/ad8")
                if (msgNodes != null && msgNodes.size > 0) {
                    for(rpNode in msgNodes) {
                        val rpStatusNode = rpNode.findAccessibilityNodeInfosByText("领取红包")
                        if (rpStatusNode != null && rpStatusNode.size > 0) {
                            rpNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                            break
                        }
                    }
                }
            }
        }
    }

    //打开红包
    private fun clickRedPacket() {
        val nodeInfo = rootInActiveWindow
        val clickNode = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/c31")
        if (clickNode != null && clickNode.size > 0) {
            clickNode[0].performAction(AccessibilityNodeInfo.ACTION_CLICK)
        } else {
            performBackClick()
        }
    }
    private fun performBackClick() {
        handler.postDelayed({ performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK) }, 300L)
    }

}
复制代码

来啊,Py交易啊

想加群一块儿学习Py的能够加下,智障机器人小Pig

验证经过后会自动发送群聊连接加群连接,点击加入便可 (不要和机器人聊天=-=,就挂着拉人的,有问题到群里讲!)

欢迎各类像我同样的Py初学者,Py大神加入,一块儿愉快地交流学♂习,van♂转py。

相关文章
相关标签/搜索