feat: Initialize wxauto WeChat automation project with job extraction tools
- Add wxauto package with WeChat UI automation and message handling capabilities - Implement job_extractor.py for automated job posting extraction from WeChat groups - Add job_extractor_gui.py providing graphical interface for job extraction tool - Create comprehensive documentation in Chinese covering GUI usage, multi-group support, and quick start guides - Add build configuration files (build_exe.py, build_exe.spec) for packaging as standalone executable - Include utility scripts for WeChat interaction (auto_send_msg.py, get_history.py, receive_file_transfer.py) - Add project configuration files (pyproject.toml, setup.cfg, requirements.txt) - Include test files (test_api.py, test_com_fix.py) for API and compatibility validation - Add Apache 2.0 LICENSE and comprehensive README documentation - Configure .gitignore to exclude build artifacts, logs, and temporary files
This commit is contained in:
133
wxauto/msgs/msg.py
Normal file
133
wxauto/msgs/msg.py
Normal file
@@ -0,0 +1,133 @@
|
||||
from .attr import *
|
||||
from .type import OtherMessage
|
||||
from . import self as selfmsg
|
||||
from . import friend as friendmsg
|
||||
from wxauto.languages import *
|
||||
from wxauto.param import WxParam
|
||||
from wxauto import uiautomation as uia
|
||||
from typing import Literal
|
||||
import re
|
||||
|
||||
class MESSAGE_ATTRS:
|
||||
SYS_TEXT_HEIGHT = 33
|
||||
TIME_TEXT_HEIGHT = 34
|
||||
CHAT_TEXT_HEIGHT = 52
|
||||
FILE_MSG_HEIGHT = 115
|
||||
LINK_MSG_HEIGHT = 115
|
||||
VOICE_MSG_HEIGHT = 55
|
||||
|
||||
TEXT_MSG_CONTROL_NUM = (8, 9, 10, 11)
|
||||
TIME_MSG_CONTROL_NUM = (1,)
|
||||
SYS_MSG_CONTROL_NUM = (4,5,6)
|
||||
IMG_MSG_CONTROL_NUM = (9, 10, 11, 12)
|
||||
FILE_MSG_CONTROL_NUM = tuple(i for i in range(15, 30))
|
||||
LINK_MSG_CONTROL_NUM = tuple(i for i in range(15, 30))
|
||||
VOICE_MSG_CONTROL_NUM = tuple(i for i in range(10, 30))
|
||||
VIDEO_MSG_CONTROL_NUM = (13, 14, 15, 16)
|
||||
QUOTE_MSG_CONTROL_NUM = tuple(i for i in range(16, 30))
|
||||
LINK_MSG_CONTROL_NUM = tuple(i for i in range(15, 30))
|
||||
|
||||
def _lang(text: str) -> str:
|
||||
return MESSAGES.get(text, {WxParam.LANGUAGE: text}).get(WxParam.LANGUAGE)
|
||||
|
||||
SEPICIAL_MSGS = [
|
||||
_lang(i)
|
||||
for i in [
|
||||
'[图片]', # ImageMessage
|
||||
'[视频]', # VideoMessage
|
||||
'[语音]', # VoiceMessage
|
||||
'[文件]', # FileMessage
|
||||
'[链接]', # LinkMessage
|
||||
]
|
||||
]
|
||||
|
||||
def parse_msg_attr(
|
||||
control: uia.Control,
|
||||
parent,
|
||||
):
|
||||
msg_rect = control.BoundingRectangle
|
||||
height = msg_rect.height()
|
||||
mid = (msg_rect.left + msg_rect.right) / 2
|
||||
for length, _ in enumerate(uia.WalkControl(control)):length += 1
|
||||
|
||||
# TimeMessage
|
||||
if (
|
||||
length in MESSAGE_ATTRS.TIME_MSG_CONTROL_NUM
|
||||
):
|
||||
return TimeMessage(control, parent)
|
||||
|
||||
# FriendMessage or SelfMessage
|
||||
if (head_control := control.ButtonControl(searchDepth=2)).Exists(0):
|
||||
head_rect = head_control.BoundingRectangle
|
||||
if head_rect.left < mid:
|
||||
return parse_msg_type(control, parent, 'Friend')
|
||||
else:
|
||||
return parse_msg_type(control, parent, 'Self')
|
||||
|
||||
# SystemMessage or TickleMessage
|
||||
else:
|
||||
if length in MESSAGE_ATTRS.SYS_MSG_CONTROL_NUM:
|
||||
return SystemMessage(control, parent)
|
||||
elif control.ListItemControl(RegexName=_lang('re_拍一拍')).Exists(0):
|
||||
return TickleMessage(control, parent)
|
||||
else:
|
||||
return OtherMessage(control, parent)
|
||||
|
||||
def parse_msg_type(
|
||||
control: uia.Control,
|
||||
parent,
|
||||
attr: Literal['Self', 'Friend']
|
||||
):
|
||||
for length, _ in enumerate(uia.WalkControl(control)):length += 1
|
||||
content = control.Name
|
||||
wxlog.debug(f'content: {content}, length: {length}')
|
||||
|
||||
if attr == 'Friend':
|
||||
msgtype = friendmsg
|
||||
else:
|
||||
msgtype = selfmsg
|
||||
|
||||
# Special Message Type
|
||||
if content in SEPICIAL_MSGS:
|
||||
# ImageMessage
|
||||
if content == _lang('[图片]') and length in MESSAGE_ATTRS.IMG_MSG_CONTROL_NUM:
|
||||
return getattr(msgtype, f'{attr}ImageMessage')(control, parent)
|
||||
|
||||
# VideoMessage
|
||||
elif content == _lang('[视频]') and length in MESSAGE_ATTRS.VIDEO_MSG_CONTROL_NUM:
|
||||
return getattr(msgtype, f'{attr}VideoMessage')(control, parent)
|
||||
|
||||
# FileMessage
|
||||
elif content == _lang('[文件]') and length in MESSAGE_ATTRS.FILE_MSG_CONTROL_NUM:
|
||||
return getattr(msgtype, f'{attr}FileMessage')(control, parent)
|
||||
|
||||
# LinkMessage
|
||||
elif content == _lang('[链接]') and length in MESSAGE_ATTRS.LINK_MSG_CONTROL_NUM:
|
||||
return getattr(msgtype, f'{attr}LinkMessage')(control, parent)
|
||||
|
||||
# TextMessage
|
||||
if length in MESSAGE_ATTRS.TEXT_MSG_CONTROL_NUM:
|
||||
return getattr(msgtype, f'{attr}TextMessage')(control, parent)
|
||||
|
||||
# QuoteMessage
|
||||
elif (
|
||||
rematch := re.compile(_lang('re_引用消息'), re.DOTALL).match(content)
|
||||
and length in MESSAGE_ATTRS.QUOTE_MSG_CONTROL_NUM
|
||||
):
|
||||
return getattr(msgtype, f'{attr}QuoteMessage')(control, parent)
|
||||
|
||||
# VoiceMessage
|
||||
elif (
|
||||
rematch := re.compile(_lang('re_语音')).match(content)
|
||||
and length in MESSAGE_ATTRS.VOICE_MSG_CONTROL_NUM
|
||||
):
|
||||
return getattr(msgtype, f'{attr}VoiceMessage')(control, parent)
|
||||
|
||||
return getattr(msgtype, f'{attr}OtherMessage')(control, parent)
|
||||
|
||||
def parse_msg(
|
||||
control: uia.Control,
|
||||
parent
|
||||
):
|
||||
result = parse_msg_attr(control, parent)
|
||||
return result
|
||||
Reference in New Issue
Block a user