Practical functions # use Python to upgrade your wechat

Posted by alefort on Wed, 22 Dec 2021 13:02:05 +0100

An automatic recovery robot

Hello, I'm Charlie
Since wechat went online, it has no automatic reply function. It must have their idea. However, some people do have certain needs for this function. I give two chestnuts:

People who don't want to be disturbed by news all the time
People whose messages need batch processing (e.g. wechat merchants)

Several functions are designed:

[x] Automatic reply immediately after receiving the message
[x] Receive the message and delay the reply for a specified time
[x] Customize different reply contents for different friends
[x] Control at any time on the mobile terminal

The principle of itchat is to log in to the remote wechat web end by scanning the code, and then operate on the mobile end and respond on the web end to realize some functions. Although it seems to make a detour, under the restriction of wechat, this seems to be the best way, just like dancing in shackles.

We can first set several global variables as function switches and data containers.

#Automatic return switch
SWITCH_REPLY=True
#Delay reply switch
SWITCH_DELAY=False
#delay time 
DELAY_TIME=120
#Message prefix switch
SWITCH_PREFIX=True
#Message prefix content
PREFIX_CONTENT="[Automatic reply]"
#Reply content dictionary
REPLY_DICT={}
#Delayed reply dictionary
DELAY_REPLY_DICT={}

Then, different operations are performed by judging the string instructions received by the web end in the "file manager". The code of this part is relatively simple and lengthy. It will not be posted here. The complete source code address will be given at the end of the article.

If we receive a message from a friend at this time, we need the program to give an automatic reply.

#Get information about the friend who sent the message
    target_friend=itchat.search_friends(userName = msg['FromUserName'])
    if target_friend:
        #Get ta's nickname
        nickName=target_friend['NickName']
        if not REPLY_DICT.__contains__(nickName):
            #Set default reply
            REPLY_DICT[nickName]="Sorry, I haven't seen the news yet. I'll reply later. If there's anything urgent, you can call me(•ω•`)"
        
        reply_content=REPLY_DICT[nickName]
        #Judge automatic reply switch
        if SWITCH_REPLY:
            #Judgment delay reply switch
            if SWITCH_DELAY:
                localtime = time.time()
                DELAY_REPLY_DICT[nickName]=[localtime,msg['FromUserName']]
                print (DELAY_REPLY_DICT)
                
            if not SWITCH_DELAY:
                #Determine message prefix switch
                if SWITCH_PREFIX:
                    reply_content = PREFIX_CONTENT + REPLY_DICT[nickName]
                else:
                    reply_content = REPLY_DICT[nickName]
                #send message
                itchat.send(reply_content, toUserName=msg['FromUserName'])

It's easy to automatically reply to a friend's message immediately, but how to delay sending a reply message? (the question of whether it is necessary to do this function can be shelved first, but I think this function is needed in many scenarios, and you can also discuss in the comment area what scenarios need to delay automatic reply.) now let's return to the technical question, how to realize delayed automatic reply with settable time.
Let me talk about my ideas first. Generally, sending a message requires a queue to enter and leave the queue. I set up a dictionary here to save the data of the message sender. The key is the nickname of the message sender, and the value is an array with a length of 2, which stores the wechat id of the message sender and the time stamp when receiving the message. In this way, I save each sent friend information in this dictionary, and then compare the set delay time with the sum of the message timestamp and the current timestamp. If the current timestamp is large, I will execute the operation of sending the message.
At this time, another thread is started as a scheduled task, Regularly detect whether each data in the dictionary meets the critical requirements of transmission (current timestamp > = message timestamp + set delay time) there is a module in Python dedicated to timing tasks called sched, but I tried. Sched will block the current main thread and itchat thread, so it is not appropriate. Here, I still use the threading Timer as the Timer, but pay attention to using recursion, otherwise it will run once It's over.

#Function to delay sending messages
def delay_reply():
    #print("start execution")
    global DELAY_REPLY_DICT
    if SWITCH_DELAY:
        while len(DELAY_REPLY_DICT)>0:
            localtime = time.time()
            # print (localtime)
            # print (DELAY_REPLY_DICT[item][0])
            # print (int(DELAY_TIME))
            for item in list(DELAY_REPLY_DICT.keys()):
                if SWITCH_REPLY:
                    reply_content = item + "," + str(round(int(DELAY_TIME) / 60, 1)) + "Minutes passed," + REPLY_DICT[item]
                    itchat.send(reply_content, toUserName=DELAY_REPLY_DICT[item][1])
                    # print ("send message")
                    del DELAY_REPLY_DICT[item]
            print (DELAY_REPLY_DICT)

    global timer1
    timer1=threading.Timer(DELAY_TIME,delay_reply)
    timer1.start()

So far, the main functions have been realized. I have tested my wechat with a test account. Take a look at the following screenshot:

At this time, the function has been basically completed. Is this the end? Don't worry. Think again. Is there anything that needs to be improved? Students who have used wechat web should know that the connection will be lost when the web is not operated for a long time. In our case, if you haven't received wechat messages for a long time, the background program will lose connection with wechat. You need to log on to the server to restart the program again, which is obviously very troublesome. Is there any simple solution? I think that the background of some applications usually makes a heartbeat detection mechanism, so I imitate this idea and regularly send a string to my "file manager" to maintain the connection.

def keep_alive():
text="Stay logged in"
itchat.send(text, toUserName="filehelper")
global timer2
timer2 = threading.Timer(60*60,keep_alive)
timer2.start()

Finally, we need to publish this program on the server and make it serve my wechat 24 / 7.

image

Note here that if you only use Python XXXX Py, closing the shell will end the process, so we need to use nohup Python XXXX Py & comes to the omni-directional daemon. To be wordy here, the functions of nohup and & are different. Many people are easily confused. If you are interested, you can check the data and distinguish them.

So far, wechat has been a little better after our slight adjustment. However, this is far from enough. Ideas can continue to be expanded. For example, it is possible to control the computer on and off through mobile wechat, and the startup and shutdown of computer software. In theory, it is not impossible to even control the air conditioner at home, but it is more difficult.

Simple analysis of wechat friend information

As mentioned above, since we can get friends' information through itchat, name will naturally have a lot of interesting information (no specific analysis here).

Sex ratio
def get_sex():
# Get friend data
my_friends = itchat.get_friends(update=True)[0:]
sex = {"male": 0, "female": 0, "other": 0}
for item in my_friends[1:]:
    s = item["Sex"]
    if s == 1:
        sex["male"] += 1
    elif s == 2:
        sex["female"] += 1
    else:
        sex["other"] += 1
total = len(my_friends[1:])

# Start drawing pie charts
attr = list(sex.keys())
v1 = list(sex.values())
pie = Pie("Sex ratio of friends")
pie.add("", attr, v1, v1, is_label_show=True)
pie.render(path="sex_html/sex.html")

Sex ratio

National and provincial distribution
def friends_province():
# Get friend provinces
province= get_data("Province")
# classification
province_distribution = {}
for item in province:
    #Delete English provinces because they are not in the map of China
    if bool(re.search('[a-z]',item)):
        continue
    elif not province_distribution.__contains__(item):
        province_distribution[item] = 1
    else:
        province_distribution[item] += 1
#Delete the empty province name
province_distribution.pop('')
#Extract the data format required by the map interface
# print(province_distribution)
province_keys=province_distribution.keys()
province_values=province_distribution.values()

return province_keys,province_values
Note: you need to install your own map here, otherwise only the South China Sea islands will be displayed, https://www.jianshu.com/p/20fd061d0b96:

Solution, manually install maps

  1. Global country map: echarts-countries-pypkg (1.9MB): world map and 213 countries, including China map
  2. Provincial map of China: echarts-china-provinces-pypkg (730KB): 23 provinces and 5 autonomous regions
  3. City level map of China: echarts-china-cities-pypkg (3.8MB): 370 Chinese cities

Friends who need these maps can install the pip command line:

pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg

It is specially noted that the map of China is in echarts countries pypkg.

National Friends distribution

Friends tag
def friends_signature():
signature = get_data("Signature")
wash_signature=[]
for item in signature:
    #Remove emoji expressions and other non words
    if "emoji" in item:
        continue
    rep = re.compile("1f\d+\w*|[<>/=[]『』♂ω]")
    item=rep.sub("", item)
    wash_signature.append(item)

words="".join(wash_signature)

print(wash_signature)

wordlist = jieba.cut(words, cut_all=True)
word_space_split = " ".join(wordlist)

global NickName
global Sex

# print(NickName, Sex)

# Image function: the generated image is twice the size of this image
# Select the corresponding gender template according to gender
if Sex == 2:
    coloring = np.array(Image.open("standard/girl.jpg"))
elif Sex == 1:
    coloring = np.array(Image.open("standard/boy.jpg"))
else:
    coloring = np.array(Image.open("standard/num.jpg"))


# simkai.ttf is required. Chinese font is recognized, for example: simkai ttf,
my_wordcloud = WordCloud(background_color="white", max_words=800,
                         mask=coloring, max_font_size=120, random_state=30, scale=2,font_path="fonts/STKAITI.TTF").generate(word_space_split)

image_colors = ImageColorGenerator(coloring)
plt.imshow(my_wordcloud.recolor(color_func=image_colors))
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()

# Save picture
my_wordcloud.to_file('Signature/signature.png')

Explain two points:
1. There must be a label sample layout to generate the corresponding style
2. To add a Chinese font

Topics: Python