操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    本教程為新手學習python教程
    廢話少說,下面開始python教程
    我們先用tkinter搭建好腳本的基本界面

    私信小編01即可獲取大量Python學習資源

    import tkinter as tk#[size=3]首先導入tkinter,需要事先用pip安裝進python里(方法自行百度)[/size]
     
    def init_window():
        global cs,wd
        wd = tk.Tk()
        cs = tk.Canvas(wd,
                       width = 800,
                       height = 500,
                       bg = 'white')
        wd.minsize(800, 500)   # 最小尺寸
        wd.maxsize(800, 500)#最大尺寸,使最大化失效
        wd.title('DDTHelper')
        pic = tk.PhotoImage(file="pic.png")#設置背景圖片,最好是800*500和png格式的
        cs.create_image(400,250,image = pic)
        cs.pack()
        bt = tk.Button(wd,
                       text='初始化',
                       bg=('white'),
                       font=('微軟雅黑',20),
                       width=155,
                       height=48,
                       command=BT_onCreat)
        bt.pack()
        cs.create_window(530,70,
                         width=155,
                         height=48,
                         window=bt)
        wd.mainloop()
    def BT_onCreat():
        print("初始化。。。")
    #入口,這行代碼需要一直都待在腳本的最底下
    #設置字典
    hwnd_title = dict()
    init_window()

    (不過在圖片上疊加控件其實有更好的方案,使控件的背景為透明的,但是那篇文章的代碼運行不來)
    運行效果

    現在我們為點擊 初始化 按鈕添加一些事項
    讓他在被點擊的時候識別當前的游戲窗口
    (因為我用的是36jb大廳登錄的游戲,抓取句柄的時候可以根據他的title來區別游戲窗口)
    這里我偷了個懶,利用該登錄器游戲窗口的title來獲取

    更改上面的導入庫和 BT_onCreat()方法

    import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn#需要事先用pip安裝pywin32插件進python里(方法自行百度)
     
    def init_window():
        global cs,wd
        wd = tk.Tk()
        cs = tk.Canvas(wd,
                       width = 800,
                       height = 500,
                       bg = 'white')
        wd.minsize(800, 500)   # 最小尺寸
        wd.maxsize(800, 500)#最大尺寸,使最大化失效
        wd.title('DDTHelper')
        pic = tk.PhotoImage(file="pic.png")#設置背景圖片,最好是800*500和png格式的
        cs.create_image(400,250,image = pic)
        cs.pack()
        bt = tk.Button(wd,
                       text='初始化',
                       bg=('white'),
                       font=('微軟雅黑',20),
                       width=155,
                       height=48,
                       command=BT_onCreat)
        bt.pack()
        cs.create_window(530,70,
                         width=155,
                         height=48,
                         window=bt)
        wd.mainloop()
    def BT_onCreat():
        global is_run,Znum,t1,t2,t3
        Znum = 0#當前已經登陸的游戲賬號數量
        wg.EnumWindows(get_all_hwnd, 0)
        for h,t in hwnd_title.items():
            if "4399" in t:#根據title里包含的 4399 來提取游戲窗口
                hwnd = t.split("|")[3]
                name = t.split("|")[2]
                print("賬號:" + name + "句柄:" + hwnd)
                Znum = Znum + 1
                hwnd = int(hwnd)#將句柄轉化為int,因為句柄是從標題獲取的string,導致了類型錯誤,我就是被這個坑了好久。。
                if Znum==1:#為每一個游戲界面創建一個單獨的操作線程,為了方便用global傳遞,沒有用exec。
                    t1 = xc.Thread(target=Con,args=(hwnd,name,Znum))
                elif Znum==2:
                    t2 = xc.Thread(target=Con,args=(hwnd,name,Znum))
                elif Znum==3:
                    t3 = xc.Thread(target=Con,args=(hwnd,name,Znum))
                init_control(Znum,name)
    #下面再添加幾個方法進去
    #獲取句柄用的
    def get_all_hwnd(hwnd,mouse):
        if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
            hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
    #為每一個線程創建一個對應的控件來控制線程的運行
    def init_control(Znum,name):
        global cs,wd,v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
        if Znum==1:
            v1=tk.IntVar()
            tx1=tk.StringVar()
            txn1=tk.StringVar()
        elif Znum==2:
            v2=tk.IntVar()
            tx2=tk.StringVar()
            txn2=tk.StringVar()
        elif Znum==3:
            v3=tk.IntVar()
            tx3=tk.StringVar()
            txn3=tk.StringVar()
        exec('tx{}.set("未運行")'.format(Znum)) 
        exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
        exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
        exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
        exec('cb{}.pack()'.format(Znum))
        exec('lb{}.pack()'.format(Znum))
        exec('lbn{}.pack()'.format(Znum))
        Ytmp=Znum*100
        Ytmp=Ytmp+70
        exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
        Ytmp=Ytmp+40
        exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
        exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
    #線程方法
    def Con(hwnd,name,xc):
    print("啟動成功")
    #多選框點擊事件
    def BT_onRun1():
        global v1,tx1,t1,ct1
        if v1.get()==1:#判斷是否被選中
            ct1=0
            tx1.set('正運行')
            t1.start()
        else:
            ct1=1#用來控制線程終止
            tx1.set('未運行')  
    def BT_onRun2():
        global v2,tx2,ct2
        if v2.get()==1:#判斷是否被選中
            ct2=0
            tx2.set('正運行')
            t2.start()
        else:
            ct2 = 1
            tx2.set('未運行')
    def BT_onRun3():
        global v3,tx3,ct3
        if v3.get()==1:#判斷是否被選中
            ct3=0
            tx3.set('正運行')
            t3.start()
        else:
            ct3=1
            tx3.set('未運行')
    #入口,這行代碼需要一直都待在腳本的最底下
    #設置字典
    hwnd_title = dict()
    init_window()

    運行后,點擊初始化的效果

    可以看到,當只有一個游戲窗口的時候,腳本就自動識別出了該游戲窗口。(目前最多識別3個,且不能二次點擊初始化,否則會報錯。聽說用exce動態封裝線程時可以用dict來接收,而目前二次識別也有了大致方案)

    并在勾選 未運行 旁邊的 框框 時,運行對應的線程。


    接下來就要到腳本的線程模塊了,而有過py基礎的人都知道,py的線程是沒有stopThread的
    但我們將要實現如何控制腳本執行游戲操作的線程,讓它收放自如

    下面教程開始
    因為接下來的腳本是精簡過的,和上次帖子略有不同,以這次帖子為準
    我們先像上個帖子一樣搭建好一個界面的代碼,以此作為平臺

    import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn,multiprocessing as jc
     
     
     
    def init_window():
        global cs,wd
        wd = tk.Tk()
        cs = tk.Canvas(wd,
                       width = 800,
                       height = 500,
                       bg = 'white')
        wd.minsize(800, 500)   # 最小尺寸
        wd.maxsize(800, 500)
        wd.title('DDTHelper')
        pic = tk.PhotoImage(file="pic.png")
        cs.create_image(400,250,image = pic)
        cs.pack()
        bt = tk.Button(wd,
                       text='初始化',
                       bg=('white'),
                       font=('微軟雅黑',20),
                       width=155,
                       height=48,
                       command=BT_onCreat)
        bt.pack()
        cs.create_window(530,70,
                         width=155,
                         height=48,
                         window=bt)
        wd.mainloop()
    def init_control(Znum,name):
        global v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
        if Znum==1:
            v1=tk.IntVar()
            tx1=tk.StringVar()
            #txn1=tk.StringVar()
        elif Znum==2:
            v2=tk.IntVar()
            tx2=tk.StringVar()
            #txn2=tk.StringVar()
        elif Znum==3:
            v3=tk.IntVar()
            tx3=tk.StringVar()
            #txn3=tk.StringVar()
        exec('tx{}.set("未運行")'.format(Znum)) 
        exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
        #exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
        exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
        exec('cb{}.pack()'.format(Znum))
        exec('lb{}.pack()'.format(Znum))
        #exec('lbn{}.pack()'.format(Znum))
        Ytmp=Znum*100
        Ytmp=Ytmp+70
        exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
        Ytmp=Ytmp+40
        #exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
        exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
     
    def BT_onCreat():
        global Znum,D1,D2,D3,conT
        Znum = 0
        wg.EnumWindows(get_all_hwnd, 0)
        conT=jc.Manager().Array("i",[3,0,0,0])#用來控制進程
        #lock = jc.Lock()#用來給進程運行順序排序,防止顯示錯亂,打包成exe時可以去除(如果出現錯誤 windos 什么的就改成lock = jc.Manager.Lock() 這樣就可以了,或者刪掉Manager)
        #lock不穩定,棄用
        for h,t in hwnd_title.items():
            if "4399" in t:
                hwnd = t.split("|")[3]
                name = t.split("|")[2]
                print("賬號:" + name + "句柄:" + hwnd)
                Znum = Znum + 1
                hwnd = int(hwnd)
                init_control(Znum,name)
                if Znum==1:
                    D1 = jc.Manager().Array("i",[1,hwnd])
                elif Znum==2:
                    D2 = jc.Manager().Array("i",[2,hwnd])
                elif Znum==3:
                    D3 = jc.Manager().Array("i",[3,hwnd])
    def get_all_hwnd(hwnd,mouse):
        if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
            hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
    def Con(data,conT):
        #l.acquire()#鎖
        #try:
        print("運行成功")
        #finally:
            #l.release()
    def onRunMan(Znum):
        if onRunMan2(Znum) == 1:
            conT[Znum]=0
            exec('p{} = jc.Process(target=Con,args=(D{},conT))'.format(Znum,Znum))
            exec('p{}.daemon=True'.format(Znum))
            exec('tx{}.set("運行中")'.format(Znum))
            exec('p{}.start()'.format(Znum))
        else:
            conT[Znum]=1
            exec('tx{}.set("未運行")'.format(Znum))
    def onRunMan2(Znum):
        if Znum ==1:
            return v1.get()
        elif Znum == 2:
            return v2.get()
        elif Znum ==3:
            return v3.get()
    def BT_onRun1():
        onRunMan(1)
    def BT_onRun2():
        onRunMan(2)
    def BT_onRun3():
        onRunMan(3)
     
    if __name__ == '__main__':
        hwnd_title = dict()
        init_window()


    成功識別后,我們勾上運行的鉤子
    成功的話會在終端顯示 成功運行

    這次我在onCreat方法里封裝需要發送給進程的數據
    然后在onRunMain中動態拼裝進程并啟動它

    再讓產生的子進程來生成守護線程,讓守護線程去操控游戲

    然后子進程循環檢測我們是不是發出了停止命令,如果線程檢測到我們發出了停止的命令

    自身的代碼就執行完了,然后帶動他產生的守護線程也被kill掉了。
    這樣就可以實現多線程的隨時停止了



    代碼還巧妙借用了exec指令的“特性”:輸出變量只能在該方法內可見,一旦該方法被重啟,變量就沒了
    也就是說,如果我們直接用 p1 = jc.Process(target=Con,args=(D1,conT))來產生進程
    那么在進程結束后,需要用 del p1來清除掉進程的“尸體”,然后再重新創建它



    設置的Con方法代碼,讓它會自己生產守護線程

    def Con(hwnd,Znum,conT,l):
        #設置守護線程
        time.sleep(1)
        exec('t{} = xc.Thread(target=RunMain,args=(hwnd,Znum))'.format(Znum))#依靠Znum(游戲賬號分配到的id)來動態生成不同的線程
        exec('t{}.setDaemon(True)'.format(Znum))
        exec('t{}.start()'.format(Znum))
        while True:#開始接收我們是否發出了停止的命令
            if conT[Znum] == 0:
                time.sleep(1)
            else:
                break
        print('進程' + str(Znum) +':已退出')

    再補充它生產出的子線程所執行的方法(不可用)

    def RunMain(hwnd,Znum):
        RM=0#運行次數,因為用多進程后無法向用戶節目輸出,所以已棄用
        hdc=wg.GetWindowDC(int(hwnd))#獲取目標頁游(flash)的hdc,用來獲取指定坐標的顏色
        while True:
            while str(wg.GetPixel(hdc,919,280))!=str(10248996):#檢測游戲角色是否處在房間界面(初始需要用戶手動將游戲角色進入房間界面),用于檢測游戲角色是否退出了副本回到了游戲房間
                print("房間")
                doClick(hwnd,5,5)
                time.sleep(1)
            if Chose_FB(hwnd,hdc) == 1:#查看當前兩個副本中又那個副本開放,其實這個設計并不合理,如果當前沒副本開放就出bug了,不過我只會在有副本開放才會運行這個腳本對吧-,-
                FB_MS(hwnd,hdc)#啟動1號副本方案
            else:
                FB_JD(hwnd,hdc)#二號副本方案
            RM = RM + 1

    當然,,現在由于主題和篇幅原因,我就不補充副本的流程方法了, 但這樣可能會導致運行時報錯
    我們可以將它刪減成

    def RunMain(hwnd,Znum):
        white True:
            print("我在運行")
            time.sleep(1)

    這樣在勾選運行的時候,
    終端就會不停地顯示 我在運行
    直到我們把運行的鉤子取消后,就不會再顯示了(線程被kill掉了)

    熟悉按鍵精靈的大佬們都應該用過一個叫大漠的插件
    但先講不依賴大漠的情況下,用微軟官方的指令來實現腳本的操作

    import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,win32api as wa,win32con as wn,multiprocessing as jc
     
     
     
    def init_window():
        global cs,wd
        wd = tk.Tk()
        cs = tk.Canvas(wd,
                       width = 800,
                       height = 500,
                       bg = 'white')
        wd.minsize(800, 500)   # 最小尺寸
        wd.maxsize(800, 500)
        wd.title('DDTHelper')
        pic = tk.PhotoImage(file="pic.png")
        cs.create_image(400,250,image = pic)
        cs.pack()
        bt = tk.Button(wd,
                       text='初始化',
                       bg=('white'),
                       font=('微軟雅黑',20),
                       width=155,
                       height=48,
                       command=BT_onCreat)
        bt.pack()
        cs.create_window(530,70,
                         width=155,
                         height=48,
                         window=bt)
        wd.mainloop()
    def init_control(Znum,name):
        global v1,v2,v3,tx1,t2,tx2,t3,tx3,txn1,txn2,txn3
        if Znum==1:
            v1=tk.IntVar()
            tx1=tk.StringVar()
            #txn1=tk.StringVar()
        elif Znum==2:
            v2=tk.IntVar()
            tx2=tk.StringVar()
            #txn2=tk.StringVar()
        elif Znum==3:
            v3=tk.IntVar()
            tx3=tk.StringVar()
            #txn3=tk.StringVar()
        exec('tx{}.set("未運行")'.format(Znum)) 
        exec('lb{} = tk.Label(wd,text="{}",bg=("#ffffff"),font=("微軟雅黑",20))'.format(Znum,name))
        #exec('lbn{} = tk.Label(wd,textvariable=txn{},bg=("#ffffff"),font=("微軟雅黑",10))'.format(Znum,Znum))
        exec('cb{} = tk.Checkbutton(wd,textvariable=tx{},bg=("#ffffff"),font=("微軟雅黑",10),variable = v{}, height=5,width = 0,command=BT_onRun{})'.format(Znum,Znum,Znum,Znum))
        exec('cb{}.pack()'.format(Znum))
        exec('lb{}.pack()'.format(Znum))
        #exec('lbn{}.pack()'.format(Znum))
        Ytmp=Znum*100
        Ytmp=Ytmp+70
        exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))
        Ytmp=Ytmp+40
        #exec('cs.create_window(630,{},width=35,height=25,window=lbn{})'.format(Ytmp,Znum))
        exec('cs.create_window(710,{},width=70,height=25,window=cb{})'.format(Ytmp,Znum))
     
    def BT_onCreat():
        global Znum,D1,D2,D3,conT
        Znum = 0
        wg.EnumWindows(get_all_hwnd, 0)
        conT = jc.Manager().Array("i",[3,0,0,0])
        for h,t in hwnd_title.items():
            if "4399" in t:
                hwnd = t.split("|")[3]
                name = t.split("|")[2]
                print("賬號:" + name + "句柄:" + hwnd)
                Znum = Znum + 1
                hwnd = int(hwnd)
                init_control(Znum,name)
                if Znum == 1:
                    D1 = jc.Manager().Array("i",[1,hwnd])
                elif Znum == 2:
                    D2 = jc.Manager().Array("i",[2,hwnd])
                elif Znum == 3:
                    D3 = jc.Manager().Array("i",[3,hwnd])
     
    def get_all_hwnd(hwnd,mouse):
        if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd):
            hwnd_title.update({hwnd:wg.GetWindowText(hwnd)})
    def all_run(Znum):
        while Znum >0:
            exec('t{}.start()'.format(Znum))
            Znum = Znum - 1
     
     
    #操作類--------------------------------------------------------------------------------------------------------------
    def climb(hwnd,jl,fx):
        if fx==1:#右邊
            #適應方向及防止無效
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
            #1.3=1屏距
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
            time.sleep(jl*1.3)
            wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
        else:
            #適應方向及防止無效
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
            #1.3=1屏距
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
            time.sleep(jl*1.3)
            wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
    def doAngle(hwnd,jd):
        for i in range(jd):
            time.sleep(0.05)
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,87,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,87,None)
    def doClick(hwnd,cx,cy):
        long_position = wa.MAKELONG(cx, cy)
        wa.SendMessage(hwnd, wn.WM_LBUTTONDOWN, wn.MK_LBUTTON, long_position)
        wa.SendMessage(hwnd, wn.WM_LBUTTONUP, wn.MK_LBUTTON, long_position)
    def doFire(hwnd,ld):
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,66,None)#先摁大
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#先摁技能
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,98,None)
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)#11大招
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,100,None)
        wa.SendMessage(hwnd,wn.WM_KEYDOWN,32,None)
        time.sleep(ld * 0.04)
        wa.SendMessage(hwnd,wn.WM_KEYUP,32,None)
     
     
    #游戲流程處理類---------------------------------------------------------------------------------------------------------
    def Chose_FB(hwnd,hdc):
        doClick(hwnd,600,200)#打開菜單
        time.sleep(1)
        doClick(hwnd,626,188)#單人副本
        time.sleep(1)
        while True:
            doClick(hwnd,5,5)
            if str(wg.GetPixel(hdc,244,237))==str(2041582):
                doClick(hwnd,289,243)#魔石
                FBn=1
                break
            elif str(wg.GetPixel(hdc,337,278))==str(13298869):
                doClick(hwnd,292,299)#技能丹
                FBn=2
                break
        time.sleep(1)
        doClick(hwnd,726,501)#難度
        time.sleep(1)
        doClick(hwnd,504,563)#確定
        time.sleep(1)
        doClick(hwnd,951,491)
        return(FBn)
    def FB_MS(hwnd,hdc):
        time.sleep(24)
        while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測
            doClick(hwnd,5,5)
            time.sleep(0.5)
        while True:
            doClick(hwnd,5,5)
            colx=wg.GetPixel(hdc,917,486)
            if str(colx)==str(36645):
                print("位置1")
                JD=18
                break
            else:
                print("位置2")
                climb(hwnd,0.5,0)
                JD=25
                break
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#波谷專用
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,80,None)#第一次pass
        time.sleep(5)
        for i in range(2):
            while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測
                doClick(hwnd,5,5)
                time.sleep(0.5)
            wa.SendMessage(hwnd, wn.WM_KEYDOWN, 65, None)
            wa.SendMessage(hwnd, wn.WM_KEYUP, 65, None)
            doFire(hwnd,20)
        time.sleep(6)
        doAngle(hwnd,JD)
        time.sleep(10)
        while True:
            #回合循環
            cs = 0
            while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測
                if cs>=20:#超時退出
                    break
                else:
                    doClick(hwnd,5,5)
                    time.sleep(1)
                    cs=cs+1
            #退出
            if cs==20:
                print("退出副本")
                break
            else:
                doFire(hwnd,20)       
    def FB_JD(hwnd,hdc):
        while True:
            cs = 0
            cg = 0
            while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合檢測
                if cs>=20:#超時退出
                    cg=1
                    cs=0
                    break
                else:
                    doClick(hwnd,5,5)
                    time.sleep(1)
                    cs=cs+1
            if cg==1:
                break
            else:
                doFire(hwnd,60)
     
    #程序流程模塊類----------------------------------------------------------------------------------------------------------
    def RunMain(hwnd):
        RM=0
        hdc=wg.GetWindowDC(hwnd)
        while True:
            while str(wg.GetPixel(hdc,919,280))!=str(10248996):#房間檢測
                print("房間")
                doClick(hwnd,5,5)
                time.sleep(1)
            if Chose_FB(hwnd,hdc) == 1:
                FB_MS(hwnd,hdc)
            else:
                FB_JD(hwnd,hdc)
            RM = RM + 1
    def Con(Data,conT):
        #設置守護線程
        Znum = Data[0]
        print(str(Data[0]))
        hwnd = Data[1]
        time.sleep(1)
        exec('t{} = xc.Thread(target=RunMain,args=(hwnd,))'.format(Znum))
        exec('t{}.setDaemon(True)'.format(Znum))
        exec('t{}.start()'.format(Znum))
        while True:
            if conT[Znum] == 0:
                time.sleep(1)
            else:
                break
        print('進程' + str(Znum) +':已退出')
     
     
    def onRunMan(Znum):
        if onRunMan2(Znum) == 1:
            conT[Znum]=0
            exec('tx{}.set("運行中")'.format(Znum))
            exec('p{} = jc.Process(target=Con,args=(D{},conT))'.format(Znum,Znum))
            exec('p{}.daemon=True'.format(Znum))
            exec('p{}.start()'.format(Znum))
        else:
            conT[Znum]=1
            #exec('del p{}'.format(Znum))
            exec('tx{}.set("未運行")'.format(Znum))
    def onRunMan2(Znum):
        if Znum ==1:
            return v1.get()
        elif Znum == 2:
            return v2.get()
        elif Znum ==3:
            return v3.get()
    def onRunMan3(Znum):
        if Znum ==1:
            if p1.is_alive:
                return(1)
            else:
                return(0)
        elif Znum == 2:
            if p2.is_alive:
                return(1)
            else:
                return(0)
        elif Znum ==3:
            if p3.is_alive:
                return(1)
            else:
                return(0)
    def BT_onRun1():
        onRunMan(1)
    def BT_onRun2():
        onRunMan(2)
    def BT_onRun3():
        onRunMan(3)
     
    if __name__ == '__main__':
        hwnd_title = dict()
        init_window()

    我已經將模塊代碼用--區分開來
    之前我們講過了 窗口界面 和 程序線程

    重點在于 操作類

    負責向指定游戲窗口發生鼠標點擊命令的方法

    def doClick(hwnd,cx,cy):
        long_position = wa.MAKELONG(cx, cy)#模擬鼠標指針 傳送到指定坐標
        wa.SendMessage(hwnd, wn.WM_LBUTTONDOWN, wn.MK_LBUTTON, long_position)#模擬鼠標按下
        wa.SendMessage(hwnd, wn.WM_LBUTTONUP, wn.MK_LBUTTON, long_position)#模擬鼠標彈起

    這個方法把原本復雜的代碼壓縮了,于是我們要點擊游戲界面的時候,就可以調用該方法來實現,比如
    doClick(目標窗口句柄,x坐標,y坐標)
    是不是就有內味了?

    再看看其他方法

    def climb(hwnd,jl,fx):
        if fx==1:#右邊
            #適應方向及防止無效
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
            #1.3秒=1屏距
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,68,None)
            time.sleep(jl*1.3)
            wa.SendMessage(hwnd,wn.WM_KEYUP,68,None)
        else:
            #適應方向及防止無效
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
            #1.3=1屏距
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,65,None)
            time.sleep(jl*1.3)
            wa.SendMessage(hwnd,wn.WM_KEYUP,65,None)
    def doAngle(hwnd,jd):
        for i in range(jd):
            time.sleep(0.05)
            wa.SendMessage(hwnd,wn.WM_KEYDOWN,87,None)
            wa.SendMessage(hwnd,wn.WM_KEYUP,87,None)
    def doFire(hwnd,ld):
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,66,None)#先摁大招
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#先摁技能
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,98,None)#如果有大招,
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,97,None)#11大招
        wa.SendMessage(hwnd,wn.WM_KEYFIRST,100,None)
        wa.SendMessage(hwnd,wn.WM_KEYDOWN,32,None)#空格蓄力
        time.sleep(ld * 0.04)#每蓄力1力度約用時0.04秒,受游戲延遲和電腦性能會有誤差,總體可以接受,也可以改成識別力度條(更精準,但因為力度條顏色不純干擾暫且擱置方案)
        wa.SendMessage(hwnd,wn.WM_KEYUP,32,None)#松開空格

    這里的方法基本都是發送一些鍵盤操作的集合
    比如說
    方法climb是用來控制游戲中人物的爬行,
    方法doAngle是用來調整游戲中人物發射炮彈的角度
    方法doFire就是操作游戲人物發動攻擊
    總結以上方法,模擬鍵盤按鍵有3條指令

    wa.SendMessage(游戲窗口句柄,wn.WM_KEYDOWN,按鍵碼,None)
         wa.SendMessage(游戲窗口句柄,wn.WM_KEYUP,按鍵碼,None)
    wa.SendMessage(游戲窗口句柄,wn.WM_KEYFIRST,按鍵碼,None)

    它們分別是向游戲窗口發送 摁下指定按鍵 彈起指定按鍵 和集合摁下和彈起一體的 點擊指定按鍵
    但需要注意的是
    如果需要重復點擊一個按鍵的時候,千萬不要用 點擊指定按鍵 這個代碼
    這樣會產生一個bug,相當于按下了按鍵卻沒有彈起,導致失控
    需要像doAngle方法那樣,使用按下和彈起來保證不會出bug

    然后再到游戲取色
    因為沒有提取的必要,我就沒有單獨分離出來
    取色需要用到hdc(想知道hdc的可以去百度 hdc和hwnd)

    hdc=wg.GetWindowDC(int(hwnd))

    ↑利用hwnd來獲取hdc

    color = wg.GetPixel(hdc,x坐標,y坐標)

    ↑獲取指定點的顏色
    細心的小伙伴們可以發現
    在每個獲取顏色的代碼附近都有doClick的調用
    那是因為防止用戶點擊了游戲界面后又點擊了其他地方,導致游戲窗口失焦,所以使用doClick強制激活窗口

    這里需要注意一點
    因為這個游戲官方允許使用腳本,所以微軟官方的指令是可以用的
    否則的話可以嘗試用大漠插件或者別的插件來發送硬件級別的模擬按鍵信息

    下面講解調用大漠插件的方法
    大漠插件下載:點我下載
    注意:大漠插件是32位的,所以調用時必須使用32位的py,不然會報錯
    下載好后把里面的dm.dll放在和腳本同一個目錄下
    使用

    import win32com.client
      
      
    dm = win32com.client.Dispatch('dm.dmsoft')  #調用大漠插件
    print(dm.ver())#輸出版本號

    就可以成功地調用大漠插件并輸出版本號
    綁定窗口

    dm_ret = dm.BindWindow(hwnd,"gdi", "windows", "windows", 0)

    綁定字典

    dm.setDict(0, '字典.txt')#把字典文件放到和腳本同一個目錄下
    dm.useDict(0)

    可以說,在成功注冊了大漠插件后
    它的使用代碼基本和它里面自帶的說明書里面的使用代碼一致了
    需要的小伙伴可以多看看它自帶的說明書


    不過dm.dll經常被defender報毒。。。導致我想用都用不了

    雖然大漠的識別系統很強大,但畢竟是閉源付費,還強制得換成32位python。。
    還是少用為妙


    作者:打字的小強

    識別驗證碼一直是本人想要做的事情,一直在接觸按鍵精靈,了解到有一個虹魚圖靈識別插件專門做驗證碼和圖像識別,原理就是圖片處理和制作字庫識別,制作字庫我一直覺得很麻煩,工程量太大。不管怎樣,它能夠達到我的目的,并且比機器學習,opencv是要簡單點,那我就講講這個虹魚圖靈識別插件。
    先亮一下成果勾引,嘿嘿

    私信小編001即可獲取大量python學習資料!

    一.收集驗證碼圖片。
    就找一個最常見的藍奏云的下載輸入的驗證碼。fiddler抓一下,說一下這個驗證碼特征,都是數字,1-4個數字,沒有旋轉,沒有在一行,有干擾直線,有干擾點。

    找到鏈接了,接下來寫代碼,這個驗證碼圖片接口,沒有任何反爬。新建一個save_img.py,新建兩個文件夾,一個做字庫,一個做驗證集。一個100張。先爬兩百張圖片。

    import requests
    urls = "https://vip.d0.baidupan.com/file/imagecode.php"
     
    for i in range(100):
        datas = requests.get(urls)
        with open('./verify/'+str(i)+'.png', 'wb') as file:
            file.write(datas.content)

    二.處理圖片,制作字庫
    預先說明,虹魚圖靈識別插件跟大漠一樣,只能用32位的python調用,建議用conda新建python3.7 32位的python虛擬環境,cmd進入環境安裝相關包,不要在pycharm安裝。
    虹魚圖靈識別插件需要事先注冊到系統,下載圖靈2.82(Python公開版),里面有安裝教程,本人測試的系統為win10。

    import TURING
    import easygui
    import cv2
     
    def identi(names):
        img_data = "./pic/"+str(names)+".png"
        TURING.Pixel_FromPicture(img_data)
        im = cv2.imread(img_data)
     
        #切割圖片,保留有效的圖片
        im = im[0:30, 0:99]
        TURING.Filter_Tailor(0,0,99,30)
     
        #色調分離,將整個圖片的顏色分為幾種。下面的函數將圖片分成四種顏色分別為:0,85,170,255。將每一個點的rgb平均值放到四個區間對比。這四個區間為:0-64,64-128,128-192,192-255。落在每個區間就會固定一個顏色值,方便后面的圖像處理
        TURING.Filter_Posterization(4)
     
        #二值化,其中的參數是色階閾值,色階閾值:一個點分為rgb三個值,三個值的平均值為閾值。該函數的作用就是遍歷圖像的每一個點的rgb平均值改變點的顏色,大于閾值為白色。小于閾值為黑色,現在設置閾值為95,處理后就會變成黑白色的圖片了。
        TURING.Filter_Binaryzation("95")
     
     
        #去除雜點,現在是白底黑字,每個像素點周圍一共8個點。周圍大于8個白點是就由白變黑 ,作用就是去除孤立的顏色點
        TURING.Filter_Despeckle(8,0,0)
     
        #顏色反轉 轉前白底黑字 轉后黑底白字,只有黑底白字才能進行字符切割。
        TURING.Filter_InverseColor()
     
     
        #范圍投影字符切割,最重要的一步,非常難解釋。為插件作者獨創的算法,簡單的說一下大概的內容,如有人想仔細了解可以問作者哈哈。作用就是找到切割驗證碼的字符,識別有幾個字符,字符的范圍和位置
        #現在是黑底白字的圖片,以每一個白點為一個字符范圍起始點。字符范圍為一個矩形,需要一個終點才能圈成一個矩形,從上往下從左往右遍歷找終點,第一步就是識別這個白點的右下角的顏色如果也是白色,終點往下移動,(高度+1),如果是黑色,終點就要往右下角移動(高+1,寬+1),直到遇到圖片的邊緣或者超過設置的間隙。
        #這時候要注意一個字可能會被切成兩個部分,就要設置行間隙和列間隙。下面根據實際情況設置最小的行間隙和列間隙就是8,字符之間的間隔最少為8個像素,還可以設置其他的參數,比如矩形框的寬高范圍,不在范圍的框框拋棄
        TURING.Incise_ScopeAisle(8,8)
     
        #獲取切割后的數據,返回值是字符串比較長,每個框的數據以豎杠分割,其中一個框的數據有四個,分別是左上角的坐標,寬高,圖色數據以逗號分割,拿兩個點的數據給大家看看
        #8, 13, 8, 10, 00111111000111110110110001000110001000011000100000110011001101100111100000001100 | 30, 11, 8, 10, 00110000000011000110100001001110000100011000000001110010001101011011100001101100
        datas = TURING.Incise_GetCharData()
     
        # add_num這是要在opencv畫框的邊緣擴充參數,下面會用插件的捕獲到框框數據繪制大一點的框框來制作字庫,好看一點
        add_num = 3
     
        if len(datas)>0:
            datas_list = datas.split("|")
            for j in datas_list:
                data_lists = j.split(",")
                x1 =int(data_lists[0])-add_num  #左上角的x坐標
                y1 = int(data_lists[1])-add_num  #左上角y坐標
                x2 = int(data_lists[0]) +int(data_lists[2])+add_num  #框的寬
                y2 = int(data_lists[1])+int(data_lists[3])+add_num  #框的高
                cv2.rectangle(im,(int(x1),int(y1)),(int(x2),int(y2)),(255,0,255),1)  #繪制框框
            im = cv2.resize(im, None, fx=2.5, fy=2.5, interpolation=cv2.INTER_CUBIC)  # 圖太小了,需要寬高各乘以2.5來看下這個圖以便人工識別這個圖的數字是多少
            cv2.imshow("draw_0", im)
            cv2.moveWindow("draw_0", 800, 300)  # 移動顯示圖片的窗口,因為默認的位置遮擋了下面的輸入彈窗
            #統計識別的字符個數
            data_len = len(datas_list)
             
            #彈窗顯示原始驗證碼,顯示驗證碼的個數,輸入框人工輸入數字
            input_data = easygui.enterbox(msg="請輸入" + str(data_len) + "個字符添加進入字庫:", title=' ', default=' ', strip=True,
                                          image=img_data, root=None)
     
            for k in range(data_len):
                # 組裝字庫的內容
                data_lists = datas_list[k].split(",")
                #制作字庫
                insert_data = input_data[k] + "|" + data_lists[2] + "," + data_lists[3] + "|" + data_lists[4]
                #添加字庫數據進入字庫文件
                print("插入數據:"+input_data[k] + "|" + data_lists[2] + "," + data_lists[3] + "|" + data_lists[4]  )
                with open("識別庫1.lib", 'a+') as f:
                    f.write(insert_data + "\n")
            #關閉所有opencv創建的窗口
            cv2.destroyAllWindows()
        else:
     
            return
     
    #遍歷所有的驗證碼
    for i in range(100):
        identi(i)


    三.來驗證,算一下正確率
    運行的效果就是本貼第一個圖

    import TURING
    import easygui
    def identifys(names):
        #打開圖片,同樣的處理圖片
        TURING.Pixel_FromPicture("./verify/" + str(names) + ".png")
        TURING.Filter_Tailor(0, 0, 99, 30)
        TURING.Filter_Posterization(4)
        TURING.Filter_Binaryzation("95")
        TURING.Filter_Despeckle(8, 0, 0)
        # 顏色反轉 ()轉后黑底白字,轉前白底黑字
        TURING.Filter_InverseColor()
        TURING.Incise_ScopeAisle(8, 8)
        TURING.Lib_Load("識別庫1.lib")  #加載識別字庫
        識別結果 =TURING.OCR(0, 1)  #獲取識別結果,可以設置結果格式,可以顯示相似度,和x,y坐標等等。是一個字符串,以|分割,
        result =識別結果.split("|")[0]
        #來個彈框來肉眼證明結果的準確性
        choices_data = easygui.ccbox(msg='識別結果是'+result, title=' ', choices=('True', 'false'), image="./verify/" + str(names) + ".png")
        return choices_data
    suc = 0
    for i in range(100):
        res = identifys(i)
        if res:
            #統計正確的數量
            suc =suc+1
    print(suc)

    最后總結:
    弄完了賊有成就感,這種驗證碼還是有很多地方在用的,PHP框架里面好多項目都用這種驗證碼,最主要還是要了解圖像處理的原理才會融會貫通,要繼續學習繼續努力,驗證碼越來越難了。
    這還是一個簡單的測試版本,驗證了100個圖片正確了91個,有的人眼分的不是很清楚,已經很可以了如果還想提高準確度,可以再加一些字庫,或者更換圖片處理方式,或者修改人眼識別庫的錯誤等等。感謝大家的欣賞,有幫助給個免費轉發哦,或者多多關注我,才是我繼續下去的動力,哈哈

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有