ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 카카오톡 봇 만들기 ( python, pc 카톡, 비활성 ) - 2편
    python/매크로 2020. 4. 24. 06:50
    반응형

     

    3줄 선 요약

    • 플러스친구 아님
    • 모바일 어플을 활용한 방법 아님
    • pc카톡, python 으로 pc 환경에서 봇을 제작함

    2020/04/21 - [python] - 카카오톡 봇 만들기 ( python, pc 카톡, 비활성 ) - 1편

     

    1편 에서는 봇의 기능 설명과, 메시지 전송 및 대략적인 구조에 대해서 다루었고,

     

    이번 글에서는 친구목록 또는 채팅방 목록선택하는 방법을 다루려 합니다.

     

     

     

    pc카톡의 클래스 구조

    spy++ 로 확인한 pc카카오톡 구조

    소스 설명을 위해 보긴 해야 하는 pc카톡 구조입니다

    최대한 쉽게 필요한 부분만 짚고 넘어갈게요

     

    목적은  빨간색 화살표() 부분

    친구목록 or 채팅목록검색창(Edit) 에 입력을 하려고 한다

     

    검색창의 접근 과정 순서

    친구목록 :     2-1    3 (이때는 첫 번째 화살표 부분이 3 이 된다.)

    채팅목록 :     2-2  →  (파란 배경색 부분)

     

    여기서 주의할 부분이 있는데

    2-12-2 의 클래스 이름이 빨간색 밑줄로 표시한 'EVA_Window' 로 같다

    이 부분은 아래의 코드를 보면서 설명함

     

     

     

    채팅방 목록 검색

    # # 채팅방 목록 검색하는 Edit 핸들 (채팅방이 열려있지 않아도 전송 가능하기 위하여)
    hwndkakao = win32gui.FindWindow(None, "카카오톡")
    hwndkakao_edit1 = win32gui.FindWindowEx( hwndkakao, None, "EVA_ChildWindow", None)
    hwndkakao_edit2_1 = win32gui.FindWindowEx( hwndkakao_edit1, None, "EVA_Window", None)
    hwndkakao_edit2_2 = win32gui.FindWindowEx( hwndkakao_edit1, hwndkakao_edit2_1, "EVA_Window", None)
    hwndkakao_edit3 = win32gui.FindWindowEx( hwndkakao_edit2_2, None, "Edit", None)
    
    # # Edit에 검색 _ 입력되어있는 텍스트가 있어도 덮어쓰기됨
    win32api.SendMessage(hwndkakao_edit3, win32con.WM_SETTEXT, 0, kakao_opentalk_name)
    time.sleep(1)   # 안정성 위해 필요
    SendReturn(hwndkakao_edit3)

    위 코드의 기능은 채팅방을 이름으로 검색해서 들어간다

     

    1편에서 FindWindow / FindWindowEx 사용법은 다루었으니 간략하게 설명하면

     

    FindWindow로 캡션(창 이름) 이 '카카오톡' 이라는 최상위 핸들을 가져오고

    FindWindowEx 로 자식 핸들을 하나씩 타고 내려가

    최종적으로 검색창(Edit) 핸들을 가져온다

     

    이때 순서는 검색창의 접근 과정 순서에 따랐으며

    보기 쉽도록 PC카톡 클래스 구조의 좌측 빨간숫자 0, 1, 2-1, 2-2, 3 에 맞춰, 변수명을

     

    hwndkakao_edit1

    hwndkakao_edit2_1

    hwndkakao_edit2_2

    hwndkakao_edit3

    이라고 지어놨으니 비교해가면서 보면 된다.

     

     

    문제

    문제가 있는 부분은 2-12-2 자식 핸들끼리

    클래스 이름이 'EVA_Window' 로 중복이 되는 문제인데

    FindWindowEx 로 자식 핸들을 탐색할 때

    첫 번째 자식부터 순차적으로 조건이 맞을 때까지 돌아간다

     

    2-1 : 친구 목록

    2-2 : 채팅방 목록

     

    이 글에서는 2-2 채팅방 목록을 가고 싶은데

    2-1 에서 이름이 같아 멈춰버리니 2-2를 갈 수 없게 되어버린다.

     

     

    해결

    올려놓은 코드 중 아래 2-2 코드를 보면

    hwndkakao_edit2_2 = win32gui.FindWindowEx( hwndkakao_edit1, hwndkakao_edit2_1, "EVA_Window", None)

     

    빨간색으로 강조한 매개변수가 자식 핸들을 찾는 시작 포인트를 지정하는 부분이다

    기존엔 None 값을 줬었으며, 처음부터 찾으란 뜻이다

     

    때문에 2-1(친구목록) 의 핸들을 주고 이 다음부터 검색해라~ 라고 했기 때문에

    중복된 이름을 건너뛰고 2-2(채팅방 목록)의 핸들을 가져올 수 있다 

     

     

    만약 채팅방 목록이 아닌 친구목록에서 검색을 하고 싶다면, 아래의 코드를 쓰면 됨

    # # 친구목록 검색하는 Edit (채팅방이 열려있지 않아도 전송 가능하기 위하여)
    hwndkakao = win32gui.FindWindow(None, "카카오톡")
    hwndkakao_edit1 = win32gui.FindWindowEx( hwndkakao, None, "EVA_ChildWindow", None)
    hwndkakao_edit2_1 = win32gui.FindWindowEx( hwndkakao_edit1, None, "EVA_Window", None)
    hwndkakao_edit3 = win32gui.FindWindowEx( hwndkakao_edit2_1, None, "Edit", None)
    
    # # Edit에 검색 _ 입력되어있는 텍스트가 있어도 덮어쓰기됨
    win32api.SendMessage(hwndkakao_edit3, win32con.WM_SETTEXT, 0, kakao_opentalk_name)
    time.sleep(1)   # 안정성 위해 필요
    SendReturn(hwndkakao_edit3)

     

     

     

    아래 코드는 1편과 2편의 코드를 모두 합친 것

    import time, win32con, win32api, win32gui
    
    # # 카톡창 이름, (활성화 상태의 열려있는 창)
    kakao_opentalk_name = '메모장'
    
    
    # # 채팅방에 메시지 전송
    def kakao_sendtext(chatroom_name, text):
        # # 핸들 _ 채팅방
        hwndMain = win32gui.FindWindow( None, chatroom_name)
        hwndEdit = win32gui.FindWindowEx( hwndMain, None, "RichEdit20W", None)
        # hwndListControl = win32gui.FindWindowEx( hwndMain, None, "EVA_VH_ListControl_Dblclk", None)
    
        win32api.SendMessage(hwndEdit, win32con.WM_SETTEXT, 0, text)
        SendReturn(hwndEdit)
    
    
    # # 엔터
    def SendReturn(hwnd):
        win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        time.sleep(0.01)
        win32api.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0)
    
    
    # # 채팅방 열기
    def open_chatroom(chatroom_name):
        # # 채팅방 목록 검색하는 Edit (채팅방이 열려있지 않아도 전송 가능하기 위하여)
        hwndkakao = win32gui.FindWindow(None, "카카오톡")
        hwndkakao_edit1 = win32gui.FindWindowEx( hwndkakao, None, "EVA_ChildWindow", None)
        hwndkakao_edit2_1 = win32gui.FindWindowEx( hwndkakao_edit1, None, "EVA_Window", None)
        hwndkakao_edit2_2 = win32gui.FindWindowEx( hwndkakao_edit1, hwndkakao_edit2_1, "EVA_Window", None)
        hwndkakao_edit3 = win32gui.FindWindowEx( hwndkakao_edit2_2, None, "Edit", None)
    
        # # Edit에 검색 _ 입력되어있는 텍스트가 있어도 덮어쓰기됨
        win32api.SendMessage(hwndkakao_edit3, win32con.WM_SETTEXT, 0, chatroom_name)
        time.sleep(1)   # 안정성 위해 필요
        SendReturn(hwndkakao_edit3)
        time.sleep(1)
    
    
    def main():
        open_chatroom(kakao_opentalk_name)  # 채팅방 열기
    
        text = "test"
        kakao_sendtext(kakao_opentalk_name, text)    # 메시지 전송
    
    
    if __name__ == '__main__':
        main()

    사용법은

     

    kakao_opentalk_name = '메모장'

    여기에서 '메모장' 부분을 원하는 채팅방 이름으로 바꾸고

     

    나머지는 main 함수에 쓴 것만 가지고 쓰면 됨

     


    1~2편 에서 채팅방을 검색하고 들어가 메시지를 전송하는 것까지 해봤는데

    쓰다 보니 생각보다 글이 길어져서 자꾸 자르게 되네요

     

    다음 3편은 1~2편에서 만든 전송 기능을 이용해서

    간단하게 크롤링을 한 후 톡방에 알림 톡을 보내는 봇을 만들어보겠습니다.

    반응형

    댓글

Designed by Tistory.