I tried to make a little keylogger with pynput.
That's my code:
from pynput.keyboard import Key, Listener
import os
import logging
log_dir = "C:\WindowsLogs\dist"
filename = "logging"
logging.basicConfig(filename=(log_dir + filename), level=logging.DEBUG, format='%(asctime)s: %(message)s')
def on_press(key):
logging.info(str(key))
with Listener(on_press=on_press) as listener:
listener.join()
Everything works fine and it also does save every key. But when the exclamation mark is pressed it gets that error:
Traceback (most recent call last):
File "test2.py", line 16, in <module>
listener.join()
File "C:\Python27\lib\site-packages\pynput\_util\__init__.py", line 185, in join
six.reraise(exc_type, exc_value, exc_traceback)
File "C:\Python27\lib\site-packages\pynput\_util\__init__.py", line 140, in inner
return f(self, *args, **kwargs)
File "C:\Python27\lib\site-packages\pynput\keyboard\_win32.py", line 232, in _process
key = self._event_to_key(msg, vk)
File "C:\Python27\lib\site-packages\pynput\keyboard\_win32.py", line 265, in _event_to_key
msg in self._PRESS_MESSAGES))
File "C:\Python27\lib\site-packages\pynput\keyboard\_base.py", line 49, in __init__
'COMBINING ' + unicodedata.name(self.char))
KeyError: "undefined character name 'COMBINING EXCLAMATION MARK'"
What is wrong with the code? And what does that mean?
I got it! It's a bug in pynput. Installed an older version and now it works perfectly!
Related
I am making an application which automatically enters your username and password. Everything works fine but when I try to convert it to .exe using auto-py-to-exe I get this error when I launch main.exe. I have added the modules in the hidden-import menu but it doesn't seem to work. I'm pretty new to this so please keep the answers more simple :D Here is the code of the actual program:
from pynput.mouse import Button
import keyboard
from pynput.keyboard import Key, Controller, Listener, KeyCode
mouse = Controller()
keyboards = Controller()
f = open("parolochetach.txt", "r")
list_of_lists = []
for line in f:
stripped_line = line.strip()
line_list = stripped_line.split()
list_of_lists.append(line_list)
f.close()
while True:
if keyboard.is_pressed('1') or keyboard.is_pressed('2') or keyboard.is_pressed('3') or keyboard.is_pressed('4') or\
keyboard.is_pressed('5') or keyboard.is_pressed('6') or keyboard.is_pressed('7') or keyboard.is_pressed('8')\
or keyboard.is_pressed('9'):
number = int(keyboard.read_key())
if number-1 <= len(list_of_lists):
mouse.position = (404, 415)
mouse.press(Button.left)
mouse.release(Button.left)
keyboards.type(list_of_lists[number-1][0])
mouse.position = (404, 465)
mouse.press(Button.left)
mouse.release(Button.left)
keyboards.type(list_of_lists[number-1][1])
keyboards.press(Key.enter)
keyboards.release(Key.enter)
I also tried to avoid using the keyboard module but I can't make it work. When I do something simple like:
def on_press(key):
if key==KeyCode.from_char('1'):
print("yes")
it works with no errors but when I add the click and type functions:
number = int(key)
if number - 1 <= len(list_of_lists):
mouse.position = (404, 415)
mouse.press(Button.left)
mouse.release(Button.left)
keyboards.type(list_of_lists[number - 1][0])
mouse.position = (404, 465)
mouse.press(Button.left)
mouse.release(Button.left)
keyboards.type(list_of_lists[number - 1][1])
keyboards.press(Key.enter)
keyboards.release(Key.enter)
it stops working and I get multiple errors:
Unhandled exception in listener callback
File"myfile", line 211, ni inner return f(self,*args, **kwargs)
File "", line 284, in _process
self.on_press(key)
File "", line 127, in inner
if f(*args) is False:
File "", line 17, in on_press
number = int(key)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'KeyCode'
Traceback (most recent call last):
File "", line 31, in <module>
listener.join()
File "", line 259, in join
six.reraise(exc_type, exc_value, exc_traceback)
File "", line 718, in reraise
raise value.with_traceback(tb)
File "", line 211, in inner
return f(self, *args, **kwargs)
File "", line 284, in _process
self.on_press(key)
File "", line 127, in inner
if f(*args) is False:
File "", line 17, in on_press
number = int(key)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'KeyCode'
This is my answer for another question here and it did work in that case.
Try using pyinstaller and if it can't find modules try this:
From Documentation
Helping PyInstaller Find Modules
Extending the Path If Analysis recognizes that a module is needed, but
cannot find that module, it is often because the script is
manipulating sys.path. The easiest thing to do in this case is to use
the --paths option to list all the other places that the script might
be searching for imports:
pyi-makespec --paths=/path/to/thisdir
--paths=/path/to/otherdir myscript.py
These paths will be noted in the spec file in the pathex argument.
They will be added to the current sys.path during analysis.
I have a pynput error "COMBINING APOSTROPHY" when inputting a single quote into the listener with the international keyboard. I realize most people won't have this problem, but I want to handle that case.
I've looked it up and it seems to be an issue with pynput==1.6.8 and it's fixed in pynput==1.7.0^.
The problem is that I'm using pyinstaller to convert my script into an executable, and I like pyinstaller because it can also make executables for macOS and Linux, but pyinstaller doesn't work with pynput==1.7.0, the latest version it works with is pynput==1.6.8.
When using pynput==1.7.0, the generated .exe gives the descriptive error: Failed to execute script logger
Is there a way I can skip the combining apostrophe and not have the whole script crash with pynput==1.6.8?
Is there a way I can use pynput==1.7.0^ with pyinstaller?
Are there alternatives to pyinstaller that are better that can still generate executables for other OSs?
Maybe alternatives to pynput? Although I've had a hard time finding something as simple as pynput
I've been doing pyinstaller --onefile -w logger.py to convert my scripts.
The code for my script:
def on_press(key):
global keys, count
print(f"key = {key}")
keys.append(key)
count += 1
# reset
if count >= 1:
count = 0
write_file(keys)
keys = []
def on_release(key):
if key == Key.esc:
return False
if __name__ == "__main__":
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
The error I receive is:
Unhandled exception in listener callback
Traceback (most recent call last):
File "...\Programs\Python\Python39\lib\site-packages\pynput\_util\__init__.py", line 162, in inner
return f(self, *args, **kwargs)
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_win32.py", line 275, in _process
key = self._event_to_key(msg, vk)
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_win32.py", line 314, in _event_to_key
return KeyCode(**self._translate(
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_base.py", line 52, in __init__
self.combining = unicodedata.lookup(
KeyError: "undefined character name 'COMBINING APOSTROPHE'"
Traceback (most recent call last):
File "...\logger.py", line 54, in <module>
listener.join()
File "...\Programs\Python\Python39\lib\site-packages\pynput\_util\__init__.py", line 210, in join
six.reraise(exc_type, exc_value, exc_traceback)
File "...\Programs\Python\Python39\lib\site-packages\six.py", line 702, in reraise
raise value.with_traceback(tb)
File "...\Programs\Python\Python39\lib\site-packages\pynput\_util\__init__.py", line 162, in inner
return f(self, *args, **kwargs)
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_win32.py", line 275, in _process
key = self._event_to_key(msg, vk)
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_win32.py", line 314, in _event_to_key
return KeyCode(**self._translate(
File "...\Programs\Python\Python39\lib\site-packages\pynput\keyboard\_base.py", line 52, in __init__
self.combining = unicodedata.lookup(
KeyError: "undefined character name 'COMBINING APOSTROPHE'"
There won't be any way to fix this without updating to a more recent version of pynput. If pyinstaller does not work for this then you will need to use something else. I don't know any linux executable compilers, but you could try dmgbuild for mac.
You could also try an alternative like pyautogui but it does not have all of the same functionalities as pynput. This just seems to be an issue between pyinstaller and pynput and unfortunately I don't see a lot you could do to fix this.
I'm just trying to make a simple keyboard listener that prints whatever key I press (pynput.keyboard.Listener). Here is my code:
from pynput.keyboard import Listener
def on_press(k):
print(k)
with Listener(on_press=on_press) as lis:
lis.join()
But, when I run it just does nothing. So I press CTRL+C and it shows up these errors:
Traceback (most recent call last):
File "/Users/me/Desktop/py/KeyLogger/keylogger.py", line 8, in <module>
lis.join()
File "/usr/local/lib/python3.7/site-packages/pynput/_util/__init__.py", line 252, in join
super(AbstractListener, self).join(*args)
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1044, in join
self._wait_for_tstate_lock()
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1060, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
Here with anaconda/Python3.8 instead of Python3.7:
Traceback (most recent call last):
File "/Users/me/Desktop/py/KeyLogger/keylogger.py", line 8, in <module>
lis.join()
File "/Users/me/opt/anaconda3/lib/python3.8/site-packages/pynput/_util/__init__.py", line 252, in join
super(AbstractListener, self).join(*args)
File "/Users/me/opt/anaconda3/lib/python3.8/threading.py", line 1011, in join
self._wait_for_tstate_lock()
File "/Users/me/opt/anaconda3/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
It seems the error is when I tell the listener to start. I've been searching for similar issues (threading and join() issues, mostly) but I haven't found the answer to my problem. ¿Could it be a pynput problem?
Thanks.
So I just received an error that I kinda don't understand what is the reason of.
Traceback (most recent call last):
File "C:\Users\utils.py", line 657, in script
logger.warn('Wopsiy! No word found!')
File "C:\Users\utils.py", line 30, in warn
sys.stdout.write("{}{} {}".format(self.__timestamp(), '[' + self.name + '] -', colored(text, "yellow")))
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 40, in write
self.__convertor.write(text)
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 141, in write
self.write_and_convert(text)
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 166, in write_and_convert
self.write_plain_text(text, cursor, start)
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 174, in write_plain_text
self.wrapped.write(text[start:end])
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 40, in write
self.__convertor.write(text)
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 141, in write
self.write_and_convert(text)
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 169, in write_and_convert
self.write_plain_text(text, cursor, len(text))
File "C:\Program Files\Python36\lib\site-packages\colorama\ansitowin32.py", line 174, in write_plain_text
self.wrapped.write(text[start:end])
As I can see it has something with the logger that I have created myself that looks like:
Utils class
from datetime import datetime
from termcolor import cprint, colored
import sys
import colorama
class Logger:
def __init__(self,name):
colorama.init()
self.name = name
#staticmethod
def __timestamp():
timestamp = str(datetime.now().strftime("[%H:%M:%S.%f")[:-3]+"]")
return timestamp
def warn(self, text):
sys.stdout.write("{}{} {}".format(self.__timestamp(), '[' + self.name + '] -', colored(text, "yellow")))
sys.stdout.write("\n")
sys.stdout.flush()
And basically I made also a simple code of how my code looks like as well:
from utils import Logger
logger = Logger('Script')
def main():
logger = Logger("product_info")
word = ['Nope', 'There', 'Is', 'No', 'Word']
while True:
try:
for _ in infinity():
if 'Hello' in word:
print('WORKS!!')
else:
logger.warn('Wopsiy! No word found!')
time.sleep(1)
except Exception as err:
print(err)
time.sleep(1)
continue
So the problem is that after a while it gives me an error of maximum recursion depth exceeded while calling a Python object but I only get it whenever I print out except Exception as err: but when I see through a console it gives me the output that is given at the top.
The question is now that I have actually no idea what the cause of it is.
Edit
from datetime import datetime
from termcolor import cprint, colored
import sys
import colorama
colorama.init()
class Logger:
def __init__(self,name):
self.name = name
#staticmethod
def __timestamp():
timestamp = str(datetime.now().strftime("[%H:%M:%S.%f")[:-3]+"]")
return timestamp
def warn(self, text):
sys.stdout.write("{}{} {}".format(self.__timestamp(), '[' + self.name + '] -', colored(text, "yellow")))
sys.stdout.write("\n")
sys.stdout.flush()
As I understood from the discussion in the comments to the question, you may create multiple instances of the Logger class during the execution of your script. Each creation of a Logger invokes colorama.init(). Each call to colorama.init() forces Colorama to replace sys.stdout and sys.stderr streams with colorama-wrapped versions of them.
After more and more calls to colorama.init your streams turn into fat onions of lots of (uselessly repeated) colorama wrapper layers, and a single call to print has to get passed recursively from layer to layer until it reaches the actual sys.stdout.
When the number of layers exceeds the maximum allowed stack depth, you get your exception. This situation is also referenced in this open colorama issue.
The easiest way to fix the problem would be to move colorama.init() out of the Logger constructor, and have something like that globally instead:
import colorama
colorama.init()
I have a script that is constantly updating a data-frame and saving it to disk (overwriting the old csv-file). I found out that if interrupt the program right at the saving call, df.to_csv("df.csv"), all data is losed, and the df.csv is empty only containing the column-index.
I can perhaps do a workaround by temporarily saving the data to df.temp.csv, and then replacing df.csv. But is there a pythonic, short way to make the saving "Atomary" and prevent data-loss? This is the stack trace I get when interrupting right at the saving call.
Traceback (most recent call last):
File "/opt/homebrew-cask/Caskroom/pycharm/2016.1.3/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1531, in <module>
globals = debugger.run(setup['file'], None, None, is_module)
File "/opt/homebrew-cask/Caskroom/pycharm/2016.1.3/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 938, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "/Users/user/test.py", line 49, in <module>
d.to_csv("out.csv", index=False)
File "/usr/local/lib/python2.7/site-packages/pandas/core/frame.py", line 1344, in to_csv
formatter.save()
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 1551, in save
self._save()
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 1652, in _save
self._save_chunk(start_i, end_i)
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 1666, in _save_chunk
quoting=self.quoting)
File "/usr/local/lib/python2.7/site-packages/pandas/core/internals.py", line 1443, in to_native_types
return formatter.get_result_as_array()
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 2171, in get_result_as_array
formatted_values = format_values_with(float_format)
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 2157, in format_values_with
for val in values.ravel()[imask]])
File "/usr/local/lib/python2.7/site-packages/pandas/formats/format.py", line 2108, in base_formatter
return str(v) if notnull(v) else self.na_rep
File "/usr/local/lib/python2.7/site-packages/pandas/core/common.py", line 250, in notnull
res = isnull(obj)
File "/usr/local/lib/python2.7/site-packages/pandas/core/common.py", line 73, in isnull
def isnull(obj):
File "_pydevd_bundle/pydevd_cython.pyx", line 937, in _pydevd_bundle.pydevd_cython.ThreadTracer.__call__ (_pydevd_bundle/pydevd_cython.c:15522)
File "/opt/homebrew-cask/Caskroom/pycharm/2016.1.3/PyCharm.app/Contents/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py", line 14, in is_thread_alive
def is_thread_alive(t):
KeyboardInterrupt
You can create a context manager to handle your atomic overwriting:
import os
import contextlib
#contextlib.contextmanager
def atomic_overwrite(filename):
temp = filename + '~'
with open(temp, "w") as f:
yield f
os.rename(temp, filename) # this will only happen if no exception was raised
The to_csv method on a Pandas DataFrame will accept a file object instead of a path, so you can use:
with atomic_overwrite("df.csv") as f:
df.to_csv(f)
The temporary filename I chose is the requested filename with a tilde at the end. You can of course change the code to use something else if you want. I'm also not exactly sure what mode the file should be opened with, you may need "wb" instead of just "w".
The best you can do is to implement a signal handler (signal module) which waits with terminating the program until the last write operation has finished.
Something along the lines (pseudo-code):
import signal
import sys
import time
import pandas as pd
lock = threading.Lock()
def handler(signum, frame):
# ensure that latest data is written
sys.exit(1)
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGINT, handler)
while True:
# might exit any time.
pd.to_csv(...)
time.sleep(1)