自動搶紅包,點贊朋友圈,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。

相關文章
相關標籤/搜索