【发布时间】:2017-05-28 18:56:43
【问题描述】:
我正在尝试使用 Pyautogui 为名为“Graal Online Classic”的 MMO 创建一个机器人。它会读取向他们发送消息的玩家的“PM”(个人消息),然后以适当的响应进行回复。它还会截取玩家姓名的屏幕截图,将其存储在字典中(并存储该特定玩家在机器人响应层次结构中的位置),并使用它来确定玩家之前是否曾向他们发送过消息。
import time
import pyautogui
#option = None
def main():
#find_notification()
name_coords, reply_coords, text_coords = set_message_coords()
option = read_message(text_coords)
player_id(name_coords, option)
answer = response()
reply(reply_coords, answer)
def find_notification(): #looks for a waiting PM and clicks it
while True:
image = pyautogui.locateCenterOnScreen('test.png', grayscale = False, confidence = .9)
print(image)
if image is not None:
print('Found a waiting message')
pyautogui.click(image)
break
def set_message_coords(): # Creates coords for message box and screenshots name
try:
imagex, imagey = pyautogui.locateCenterOnScreen('upper_right_message_corner.png', grayscale = True, confidence = .8)
except:
print('ERROR I SHOULD BE FINDING "upper_right_message_corner.PNG" EXITING PROGRAM')
exit()
name_coords = (imagex - 424), imagey, 378, 50 # The coords of where the players name would be
print('Found an open message')
print(imagex, imagey)
reply_coords = (imagex - 251), (imagey + 255 ) # Coords of the reply button
text_coords = (imagex - 461), (imagey + 45), 430, 45 # Coords of where a players possible response is
return name_coords, reply_coords, text_coords # Returns all coord values to be used by other functions
def player_id(name_coords, option): # Indentifies person who messaged and depending on if this person has messaged before changes response
players = {} # Used to store players names and where in the response is
name_image = pyautogui.screenshot('name_test.png', region = name_coords) # Names are screenshots
if name_image not in players:
print("User was not previously found, adding to dictionary.")
players[name_image] = None
else:
print("User is previous user.")
players[name_image] = players[name_image] + option
return players[name_image]
def reply(reply_coords, response): #Replies to PM
pyautogui.click(reply_coords)
pyautogui.typewrite(response)
pyautogui.press('enter')
def read_message(text_coords): # Reads PM for numbers and sets option the number
if pyautogui.locateCenterOnScreen('1.png',region = text_coords, confidence = .9, grayscale = True):
option = '1'
elif pyautogui.locateCenterOnScreen('2.png',region = text_coords, confidence = .9, grayscale = True):
option = '2'
elif pyautogui.locateCenterOnScreen('3.png',region = text_coords, confidence = .9, grayscale = True):
option = '3'
elif pyautogui.locateCenterOnScreen('4.png',region = text_coords, confidence = .9, grayscale = True):
option = '4'
elif pyautogui.locateCenterOnScreen('5.png',region = text_coords, confidence = .9, grayscale = True):
option = '5'
elif pyautogui.locateCenterOnScreen('6.png',region = text_coords, confidence = .9, grayscale = True):
option = '6'
elif pyautogui.locateCenterOnScreen('7.png',region = text_coords, confidence = .9, grayscale = True):
option = '7'
elif pyautogui.locateCenterOnScreen('8.png',region = text_coords, confidence = .9, grayscale = True):
option = '8'
elif pyautogui.locateCenterOnScreen('9.png',region = text_coords, confidence = .9, grayscale = True):
option = '9'
elif pyautogui.locateCenterOnScreen('0.png',region = text_coords, confidence = .9, grayscale = True):
option = '0'
else:
print('ERROR CANT FIND DIGIT ANSWER')
option = None
#reply(reply_coords,'ERROR PLEASE ENTER A NUMBER RESPONSE!')
#main()
print(option)
return option
def response(option): # All the possible responses the bot can give a player
if option == None:
return "Hello! I am bot made to answer your questions! PM the number for more options! 1: Bounties. 2: Bug Hunting. 3: Looting. 4: Farming."
elif option == '1':
return "The bounty quest allows you to hunt mobs for cash! Location: Castle, steward's room(to the right in the throne room) [PM 1 for specifics, PM 2 for TIPS, PM 3 for possible bounties]"
elif option == '12':
return '1. The bounty box will "drop"(stop following you, and will not pick up anything) after every kill/capture you get, and will require you to call it, or run over it to pick it up again. [PM 1 for more info, PM 9 to go back one level, PM 0 to reset choices]'
elif option == '13':
return '100 green blobs, 20 Lizardons, 75 Pyrats(as homage to the PQ I assume), 75 Rebel soldiers(regular green baddy), 60 dark blobs, 60 rats, 75 snakes, 75 bats, 75 bandits, 80 spiders, 50 archers, or 50 crabs. [PM 9 to go back one level, PM 0 to reset choices]'
main()
它会产生以下错误。
找到一条打开的消息 692 371 错误找不到数字答案 没有任何 回溯(最近一次通话最后): 文件“C:\Users\Pablo\OneDrive\python_projects\chat_bot\main.py”,第 104 行,在 主要的() 文件“C:\Users\Pablo\OneDrive\python_projects\chat_bot\main.py”,第 10 行,在 main player_id(name_coords, 选项) 文件“C:\Users\Pablo\OneDrive\python_projects\chat_bot\main.py”,第 47 行,在 player_id 如果 name_image 不在播放器中: 类型错误:不可散列类型:“图像” 【1.9s完成】
函数 player_id() 发生错误
我对列表和字典没有太多经验,所以我不确定如何处理这个问题。我已经查看了带有错误“TypeError:unhashable type:”的类似线程,但我并不真正理解这些响应。任何帮助将不胜感激,谢谢。
【问题讨论】:
-
无论从
pyautogui.screenshot(在本例中为name_image)返回的不是可散列对象,因此不能用作字典中的键。 -
有什么办法我仍然可以在字典中使用 name_image 吗?或者作为一种方法来确定 name_image 之前是否曾向我的机器人发送过消息?
-
@OzgurVatansever
-
即使它确实有效,您希望如何将
option添加到None的初始化值?而且我对 pyautogui 不熟悉,但有些事情告诉我,在屏幕上截取消息的屏幕截图并不是一种安全/可靠的识别用户的方式。您不应该访问某种底层(基于文本的)事件/消息吗? -
@AndrasDeak 这是游戏中收到的 PM 的图像。 i.imgur.com/JpzsxZ1.png你说得对,使用姓名截图并不是识别用户的最可靠方法,但它确实是我能想到的唯一识别用户的方法。那里有一个明确的名称,但是对 pytesseract 的一些测试告诉我,它不是最可靠的做事方式。(这就是为什么在 read_message() 我寻找图像而不是文本的原因)。关于将选项添加到无,当我们到达 player[name_image] + 选项时,不应该在选项中,我计划在那之前有一个数字覆盖无
标签: python python-3.x dictionary screenshot pyautogui