Write a Weibo milk tea recommendation robot

If you want to try this function, please send us Weibo @Drink something today, the script is opened from time to time

A few days ago, I saw someone on Weibo @ What to Eat Today’s bot, and then I would receive a random dish recommendation in seconds. This is simply a blessing for the difficulty of choosing. As a big milk tea producer, I want to make a bot that recommends milk tea.

I found a lot of information on the Internet, but there is no similar bot. The most recent similar code is from 2015, which is completely unusable.

Principle

The principle is actually very simple, use python to log in to Weibo –> use Weibo’s official API: statuses/mentions, get the latest mentions Log in to the user’s Weibo list, i.e. @My Weibo –> Get the Weibo id, and use comments/create to reply to that Weibo Bo.

login

I never thought that logging in is the longest step for me. There are many ways to log in online, but because we need to use the official API, we need to register a [web application] on the Weibo open platform first (https://open.weibo. com/connect).

Then get Access Token in API testing tool:

Click on the app you just created in My Apps, and get the App Key and App Secret in App Information –> Basic Information.

There is a Weibo login package in PyPi, which can be used even now.

The introduction said to set the authorization callback page in the advanced information, but I am just a script, there is no URI to use, and finally I found the official default callback page for the mobile phone, and it can be used:
https://api.weibo.com/oauth2/default.html

The other methods of use are similar to those written in the introduction, so I will go directly to the code:

``` python
API_KEY = ‘Your Key’
API_SECRET = ‘Your Secret’
REDIRECT_URI = ‘Your URI’
access = ‘Your Access Token’
code = ‘Your code’

def logInWeibo():

# If the code expires, you need to restart the following three lines, and then update the code
# userLogIn = Client(api_key=API_KEY, api_secret=API_SECRET, redirect_uri=REDIRECT_URI)
# userLogIn.authorize_url
# 'https://api.weibo.com/oauth2/authorize?redirect_uri=Your_URI&client_id=Your_Key'

# Set code, record token
# userLogIn.set_code(code)
# token = userLogIn.token
# print(token)
# After recording, you can directly log in to Weibo within a certain period of time
token = 'the token you printed out'
client = Client(api_key=API_KEY, api_secret=API_SECRET, redirect_uri=REDIRECT_URI, token=token)
client.get('users/show', uid=2703275934)
print("Login to Weibo completed")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## call API
The first API is to get the latest @ own account's Weibo, so after requesting the official link, it will return a json value, and the id of the Weibo will be found after the layers are uncovered.

I also mention here that I can’t open the link given in the official document. After I borrowed the code from 6 years ago and modified it, I found a link that can return a value.
``` python
def getMessageId():
# Official API, you can view the latest @own account's Weibo
responseHandler = urllib.request.urlopen('https://api.weibo.com/2/statuses/mentions.json?count=1&access_token=' + access)
jsonData = json.loads(responseHandler.read().decode('utf-8'))
# first level dictionary
statuses = jsonData['statuses'][0]
# The second layer dictionary, idstr is the same as id: the id of the current microblog
currentMessageId = str(statuses['id'])
# The person who posted the Weibo
currentMessageUser = statuses['user']
UserName = str(currentMessageUser['screen_name'])
print("User name is: ", UserName, '\nWeibo Id is: ', currentMessageId)
return currentMessageId

The second API is to send comments. I didn’t encounter any setbacks in this part, and I went directly to the code:

``` python
def replyMessageToUser(messageId):
text = ‘If you want to type’
postData = urllib.parse.urlencode({‘comment’: text, ‘id’: messageId, ‘access_token’: access}).encode(‘utf-8’)
try:
urllib.request.urlopen(‘https://api.weibo.com/2/comments/create.json', postData, context=context)
print(“Sent ‘“, text, “‘ to Weibo ID: “, messageId)
except urllib.error.URLError as e:
if hasattr(e, “code”):
print(e.code)
if hasattr(e, “reason”):
print(e.reason)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Retrospect and Outlook
The above is the core code. Because it has not passed the application review, it is not possible to send comments to users frequently (the interval set before is 20s, and it will be 403 forbidden after five minutes). It should be no problem to set 60s now,~~As long as it doesn't happen once a minute, @ me once~~.

If it will be optimized in the future, the direction of optimization is roughly:
* Update milk tea list every month (this is the most important!)
* Use stack to save unprocessed Weibo IDs to prevent missing every @ (but because getting the latest @ also needs to call the API, that is, it happens once every 60s, so the top priority is to pass the application audit)
* Another way of thinking is to use the crawler to directly get all the users who @ me but I did not reply, and then store them in the stack
* Upload the bot to Alibaba Cloud to run (~~I tried to run it from morning to noon today, I think the real bot will never use a computer to run the script on the Internet~~)

---
# Update on 7/31
## Record all Weibo IDs
In the script usage for a week, it was found that if the user deletes the Weibo after @bot, the script will automatically send the recommendation of milk tea to the previous @bot user, which makes some users receive two recommended recommendations. situation happens. Of course, it's not the user's problem! So I optimized the script so that it records every Weibo ID after running. If the new ID is in the record, no new push will be sent.
``` python
# Enter the ID of the latest Weibo
def writeIdIntoNotebook(messageId):
messageId = str(messageId)
# Check if there is a new ID in the record file
messageIdWriter = open('current-message-id.txt', 'r')
line = messageIdWriter.readlines()
messageIdWriter.close()
# If the record file is empty, record the new ID
if not line:
print("empty list")
print('Write Id: ' + messageId)
messageIdWriter = open('current-message-id.txt', 'a')
messageIdWriter.write(messageId + "\n")
messageIdWriter.close()
return 0
else:
# Convert the ID in the txt file to a list
for i in range(len(line)):
line[i] = line[i].replace('\n', '')
# if the new ID is in the list
if messageId in line:
print("No new messages")
return 1
# Write a new ID if it's not there
else:
print('Write Id: ' + messageId)
messageIdWriter = open('current-message-id.txt', 'a')
messageIdWriter.write(messageId + "\n")
messageIdWriter.close()
print("New message")
return 2

log

I found that the content printed in the terminal is still very useful for reference, such as time, user, sent content, etc. These content will disappear every time I stop the script running, so I decided to write a task log TaskLog to record the output content.

Milk tea list update and probability modification

This time, the menus of Chabaidao and Michelle Bingcheng have been updated, but because Michelle Bingcheng only recommends four drinks, the price of Hey Tea is too expensive for me, and their probability is the same as other drinks, 20%. It doesn’t seem reasonable. So changed to

A little bit : HEYTEA : COCO : Tea Baidao : Michelle Ice City = 25 : 12.5 : 25 : 25 : 12.5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Random milk tea recommendation!
def randomBubbleTea():
menu = []
# The specific menu is below
a_little = []
heyTea = []
coco = []
chaBaiDao = []
miXueIceCream = []
menu.append(a_little)
menu.append(heyTea)
menu.append(coco)
menu.append(chaBaiDao)
menu.append(miXueIceCream)
randomNoOne = random.randint(0, 7)
if randomNoOne == 0 or randomNoOne == 1:
randomNoTwo = random.randint(0, 21)
text = 'Recommend a little: ' + menu[0][randomNoTwo]
return text
elif randomNoOne == 2:
randomNoTwo = random.randint(0, 8)
text = 'Recommend HEYTEA: ' + menu[1][randomNoTwo]
return text
elif randomNoOne == 3 or randomNoOne == 4:
randomNoTwo = random.randint(0, 9)
text = 'Recommend COCO: ' + menu[2][randomNoTwo]
return text
elif randomNoOne == 5 or randomNoOne == 6:
randomNoTwo = random.randint(0, 13)
text = 'Recommended tea path: ' + menu[3][randomNoTwo]
return text
elif randomNoOne == 7:
randomNoTwo = random.randint(0, 3)
text = 'Recommend Mixue Ice City: ' + menu[4][randomNoTwo]
return text

8/6 Update

Get latest comments

Someone @bot in the comments the other day, but the bot obviously doesn’t know how to deal with a situation like this, it’s certainly not the user’s problem! So we started updating the bot so that he could reply to @bot + comments on any tweet.

This time, the official api is also used: [Get the latest comment referring to the currently logged in user] (https://open.weibo.com/wiki/2/comments/mentions), because subsequent replies require comment id and micro There are two blog ids, so it is more complicated to extract. I also obtained the user name, user id, and comment content by the way. If I want to customize the user’s personalized recommendation, I will prepare in advance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Reply to comment @
def getReplyId():
# Return two values, comment id and original text id
reply_list = []
# Official API, you can view the comments of the latest @ own account
responseHandler = urllib.request.urlopen('https://api.weibo.com/2/comments/mentions.json?count=1&access_token='
+ access, context=context)
jsonData = json.loads(responseHandler.read().decode('utf-8'))
comments = jsonData["comments"][0]
# comment id
comments_Id = str(comments["id"])
reply_list.append(comments_Id)
# Commentator
comments_user = comments["user"]
# commenter name
comments_user_name = comments_user["screen_name"]
# commenter id
comments_user_id = str(comments_user["id"])
# comments
comments_text = comments["text"]
status = comments["status"]
# Weibo original
original_text = status["text"]
# Weibo id
original_text_id = str(status["id"])
reply_list.append(original_text_id)
# Weibo original user
original_user = status["user"]
# Weibo original user id
original_user_id = str(original_user["id"])
# Weibo original username
original_user_name = original_user["screen_name"]
print("@My username is: " + comments_user_name + " User id is: " + comments_user_id + " Comment content is: " + comments_text +
" Comment ID is: " + comments_Id)
taskLog.write("@My username is: " + comments_user_name + " User id is: " + comments_user_id + " Comment content is: " + comments_text
+ " Comment ID is: " + comments_Id + "\n")
print("The original user name is: " + original_user_name + " The user id is: " + original_user_id + " Weibo content is: " + original_text,
" Weibo ID is: " + original_text_id)
taskLog.write("The original username is: " + original_user_name + " User id is: " + original_user_id + " Weibo content is: " + original_text
+ " Weibo ID is: " + original_text_id + "\n")
return reply_list

Reply to a comment

To use the API of Weibo reply to comments, you need cid (comment id) and id (weibo id), and access token to log in.

``` python

Reply to comments

def replyMessageToComment(cid, id):
global taskLog
text = randomBubbleTea()
postData = urllib.parse.urlencode({‘comment’: text, ‘cid’: cid, ‘id’: id, ‘access_token’: access}).encode(‘utf-8’)
try:
urllib.request.urlopen(‘https://api.weibo.com/2/comments/reply.json', postData, context=context)
print(“Sent ‘“ + text + “‘ to Weibo ID: “ + id + “ Comment ID: “ + cid)
taskLog.write(“Sent ‘“ + text + “‘ to Weibo ID: “ + id + “ Comment ID: “ + cid + “\n”)
except urllib.error.URLError as e:
if hasattr(e, “code”):
print(e.code)
taskLog.write(e.code)
if hasattr(e, “reason”):
print(e.reason)
taskLog.write(e.reason)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Modifications of other minor details have been uploaded to github.
# 8/7 Update
I received a user @bot today and said bluntly: "I just want to drink tea." Obviously the bot doesn't know what this sentence means, of course, this is not the user's problem! Therefore, the method of random milk tea was modified. First, the content posted by the user was obtained, and then it was compared with the milk tea brand. If the comparison was successful, only the products of that brand would be recommended.
``` python
def randomBubbleTea(message):
global menu
if "a little" in message:
randomNoTwo = random.randint(0, len(menu[0]) - 1)
text = 'Recommend a little: ' + menu[0][randomNoTwo]
return text
elif "Hey Tea" in message:
randomNoTwo = random.randint(0, len(menu[1]) - 1)
text = 'Recommend HEYTEA: ' + menu[1][randomNoTwo]
return text
elif "COCO" in message or "coco" in message:
randomNoTwo = random.randint(0, len(menu[2]) - 1)
text = 'Recommend COCO: ' + menu[2][randomNoTwo]
return text
elif "Tea Baidao" in message:
randomNoTwo = random.randint(0, len(menu[3]) - 1)
text = 'Recommended tea path: ' + menu[3][randomNoTwo]
return text
elif "Michelle" in message:
randomNoTwo = random.randint(0, len(menu[4]) - 1)
text = 'Recommend Mixue Ice City: ' + menu[4][randomNoTwo]
return text
else:
randomNoOne = random.randint(0, 7)
if randomNoOne == 0 or randomNoOne == 1:
randomNoTwo = random.randint(0, len(menu[0]) - 1)
text = 'Recommend a little: ' + menu[0][randomNoTwo]
return text
elif randomNoOne == 2:
randomNoTwo = random.randint(0, len(menu[1]) - 1)
text = 'Recommend HEYTEA: ' + menu[1][randomNoTwo]
return text
elif randomNoOne == 3 or randomNoOne == 4:
randomNoTwo = random.randint(0, len(menu[2]) - 1)
text = 'Recommend COCO: ' + menu[2][randomNoTwo]
return text
elif randomNoOne == 5 or randomNoOne == 6:
randomNoTwo = random.randint(0, len(menu[3]) - 1)
text = 'Recommended tea path: ' + menu[3][randomNoTwo]
return text
elif randomNoOne == 7:
randomNoTwo = random.randint(0, len(menu[4]) - 1)
text = 'Recommend Mixue Ice City: ' + menu[4][randomNoTwo]
return text

Milk tea list

A little bit

Jasmine Green Tea

Assam tea

Four Seasons Spring Tea

Fragrant Oolong Tea

matcha

Brown sugar black tea

Emerald Lemon

honey green

Yakult Green

ice cream black tea

grapefruit green

Passion Green

boba milk tea

Boba Milk Green

Boba Red/Black

Boba Green/Blue

bubble tea

Pearl milk green

Pearl red/black

Pearl green/cyan

Coconut Milk Tea

fairy grass jelly

Red Bean QQ Milk Tea

four seasons

pudding milk tea

Oat Milk Tea

Passion Trio

coffee custard

Four Seasons Milk Green

oolong milk tea

Black tea macchiato

Oolong Macchiato

Ovaltine

matcha milk tea

Cocoa Milk Tea (Golden Ratio)

Caramel Milk Tea

Brown sugar milk tea

Kumquat Lemon

lemon honey

Lemon Yakult

Season limited: Milk green mango

Season limited: Pomelo is excited

Season limited: Passion YOYO green

Season limited: Mango YOYO green

Season limited: Peanut Bean Flower Milk Tea

HEYTEA

Succulent grapes + taro balls

Zhizhi Mango + Taro Ball Bobo

Cheese Raspberry Peach

Milk Tea Bobo Ice + Brown Sugar Bobo

Pure Lvyan for Milk Tea Base + Osmanthus Jelly

Jinfeng Tea King + Crispy Bobo

Snow Mountain Homesick Longan Seasonal Limitation: Wang Zhuyou Tangerine

Season limited: Double squeezed carambola citrus

Frozen lemon

Succulent Mango Mango

Original Whipped Coconut Coconut Milk Jelly

Cup full of red grapefruit

Roasted Brown Sugar Bobo Milk
##COCO
New: Flame Blue Coconut

Snow Top Honey Peach

Bai Yufen Li

Baiyu Lychee Tea

A lot of white jade lychees

Avocado Pudding

Fresh Apple Passion

Starry Grape

Buckwheat Light Milk Tea

Buckwheat Light Tea

mango green tea

Mango Toto

Lemon Bar

Seabuckthorn Passion Double Cannon

sea ​​buckthorn shake

Fresh Taro Milk Tea + Highland Barley + Sugar Free

Tieguanyin Pearl Tea Latte + Highland Barley + Milk Cap + Taro

Double Ball Ice Cream Black Tea + Cream + Pearl De-icing Half Sugar

Fresh Passion Fragrant Double Cannon + Coconut Nut Less Rock and Half Sugar

fresh lemon tea

light tea shake

French Cream Tea Fresh Taro Milk Sago + Red Bean + Taro Sugar Free and Less Ice

Jasmine Milk Tea + Pearl + Immortal Grass

Double ball ice cream black tea + taro + pearls, ice-free, sugar-free

Jasmine Milk Tea + Fresh Taro + Highland Barley + Pearl De-ice, Sugar Free

Poplar Nectar + Coconut Fruit Less Ice

Miss Hongguo + Cream Half Sugar

Tea Baidao

Seasonal Fruit Tea: Jasmine White Peach

Seasonal Fruit Tea: White Peach Cheese

Seasonal Fruit Tea: Fresh Strawberry Cheese

mango mango coconut

Raw Coconut Slam

poplar nectar

watermelon boo boo

Passion Pineapple

Hand pounded mango green

Super Cup Fruit Tea

Oreo Cake

Matcha Red Bean Cake

Signature Taro Ball Milk Tea

Soy Milk Jade Kirin

Jasmine Milk Green

Golden Coconut Oolong

Blood Glutinous Rice Milk Tea

Oreo Milk Tea

Jasmine Green Tea

ice oolong

Sea Salt Cheese Matcha

Michelle Ice City

lemonade!

waffle ice cream

Brown Sugar Pearl Sundaes

Snow Top Coffee