天天看點

微信工具(Python)實作備注管理和群發消息微信工具(Python)實作備注管理和群發消息

微信工具(Python)實作備注管理和群發消息

過去的一年故事太多,過年實在想換換腦子,可又哪兒去不了,除了陪孩子學習和玩,總得找點兒輕松的事兒做,太大的工程做不了,花兩天寫了個Python微信工具,用來批量更新好友的備注和給好友群發消息,效果如圖:編輯好備注列,選好行,點更新備注;編輯好消息列,選好行,點發送消息。

微信工具(Python)實作備注管理和群發消息微信工具(Python)實作備注管理和群發消息

代碼如下:

import csv
import datetime
import logging
import os
import sys

import itchat
import numpy as np
import pandas as pd
from PyQt5.QtGui import QIcon
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QAbstractItemView, QAction, QTableView, QHeaderView, QVBoxLayout, \
    QWidget, QApplication, QMainWindow
from pandas import DataFrame

CURRENT_WECHAT_USER = ''

logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
file_fh = logging.FileHandler('%s/gui.log' % sys.path[0], mode='a')
file_fh.setLevel(logging.INFO)
file_fh.setFormatter(formatter)
logger.addHandler(file_fh)
console_fh = logging.StreamHandler(sys.stdout)
console_fh.setLevel(logging.INFO)
console_fh.setFormatter(formatter)
logger.addHandler(console_fh)
logger.info(logger.handlers)


class WindowClass(QMainWindow):
    def __init__(self, parent=None):
        super(WindowClass, self).__init__(parent)
        self.setWindowTitle('微信工具')
        self.setWindowIcon(QIcon('icon.jpg'))
        self.layout = QVBoxLayout()
        self.model = QStandardItemModel(1, 1)
        self.friends = DataFrame()
        self.sync_data()

        self.tableView = QTableView()
        self.tableView.setModel(self.model)
        self.layout.addWidget(self.tableView)

        widget = QWidget()
        widget.setLayout(self.layout)
        self.setCentralWidget(widget)

        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        tool = self.addToolBar("File")
        self.action = QAction("同步資料", self)
        self.action2 = QAction("發送消息", self)
        self.action3 = QAction("更新備注", self)
        tool.addAction(self.action)
        tool.addAction(self.action2)
        tool.addAction(self.action3)
        tool.actionTriggered[QAction].connect(self.process_trigger)

        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)

    def sync_data(self):
        self.friends = get_friends_info_from_wechat()
        write_local_persist(self.friends)
        self.model.clear()
        self.model.setHorizontalHeaderLabels(['ID', '昵稱', '備注', '消息'])
        for row in range(len(self.friends)):
            for column in range(3):
                i = QStandardItem(str(self.friends.iat[row, column]))
                self.model.setItem(row, column, i)
            i = QStandardItem('輸入你想發給%s的消息:' % (str(self.friends.iat[row, 2])))
            self.model.setItem(row, 3, i)

    def process_trigger(self, action):
        global CURRENT_WECHAT_USER
        if action.text() == "同步資料":
            self.sync_data()
        if action.text() == "發送消息":
            indexes = self.tableView.selectionModel().selectedRows()
            if indexes:
                for index in indexes:
                    username = self.tableView.model().index(index.row(), 0).data()
                    remarkname = self.tableView.model().index(index.row(), 2).data()
                    nickname = self.tableView.model().index(index.row(), 1).data()
                    dt_ms = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
                    message = '%s\nFrom %s\n@ %s' % (
                        self.tableView.model().index(index.row(), 3).data(), CURRENT_WECHAT_USER, dt_ms)
                    if not itchat.send_msg(message, username):
                        logger.warning('無法成功發送消息,請手工儲存你的消息并點選同步資料菜單後重試')
                        break
                    logger.info('已成功發送消息(%s)給你的朋友%s,TA的備注是%s,目前ID是%s' % (
                        message, nickname, remarkname, username))

        if action.text() == "更新備注":
            indexes = self.tableView.selectionModel().selectedRows()
            if indexes:
                for index in indexes:
                    username = self.tableView.model().index(index.row(), 0).data()
                    remarkname = self.tableView.model().index(index.row(), 2).data()
                    nickname = self.tableView.model().index(index.row(), 1).data()
                    if not itchat.set_alias(username, remarkname):
                        logger.warning('設定備注失敗,将自動同步聯系人')
                        self.sync_data()
                        break
                    self.friends.iat[index.row(), 2] = remarkname
                    logger.info('已為你的朋友%s設定備注%s,TA的ID是%s' % (nickname, remarkname, username))
                write_local_persist(self.friends)


def infoparams(keyparma, friends):
    ret = []
    for f in friends[1:]:
        ret.append(f[keyparma])
    return ret


def get_friends_info_from_wechat():
    logger.info('開始從微信讀取好友資訊')
    global CURRENT_WECHAT_USER
    itchat.login()
    friends = itchat.get_friends(update=True)
    CURRENT_WECHAT_USER = friends[0].NickName
    logger.info('完成從微信讀取好友資訊,登陸賬号昵稱:%s' % CURRENT_WECHAT_USER)
    usernames = infoparams("UserName", friends)
    nicknames = infoparams("NickName", friends)
    pyquanpins = infoparams("PYQuanPin", friends)
    sexes = infoparams("Sex", friends)
    provinces = infoparams("Province", friends)
    cities = infoparams("City", friends)
    remarknames = infoparams("RemarkName", friends)
    remarkpyquanpins = infoparams("RemarkPYQuanPin", friends)
    signatures = infoparams("Signature", friends)
    info = {'UserName': usernames, 'NickName': nicknames, 'RemarkName': remarknames,
            "RemarkPYQuanPin": remarkpyquanpins, "PYQuanPin": pyquanpins, "Sex": sexes, "Province": provinces,
            "City": cities, "Signature": signatures}
    df = DataFrame(info)
    df['RemarkName'].replace('', np.nan, inplace=True)
    df['RemarkName'].fillna(df['NickName'], inplace=True)
    df['RemarkPYQuanPin'].replace('', np.nan, inplace=True)
    df['RemarkPYQuanPin'].fillna(df['PYQuanPin'], inplace=True)
    df.sort_values(by=["RemarkPYQuanPin", "PYQuanPin"], inplace=True)
    logger.info('完成将好友資訊寫入dataframe')
    return df


def write_local_persist(df):
    logger.info('開始将好友資訊寫入本地檔案')
    df.to_csv('friends_info.csv', index=False, encoding='utf8')
    logger.info('完成将好友資訊寫入本地檔案')


def read_local_persist():
    if not os.path.isfile('friends_info.csv'):
        write_local_persist(get_friends_info_from_wechat())
    friends = []
    with open('friends_info.csv', 'r', encoding='utf8') as f:
        reader = csv.reader(f)
        for row in reader:
            friends.append(row)
    df = pd.DataFrame(friends[1:], columns=friends[0])
    return df


def main():
    app = QApplication(sys.argv)
    win = WindowClass()
    win.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()