Задать вопрос
  • Как правильно регистрировать ID пользователя через телеграмм?

    Vindicar
    @Vindicar
    RTFM!
    По твоей схеме - никак. Или бот должен заранее знать ID пользователя, или пользователь должен доказать, что логин - его.

    Я бы на сайте генерил пользователю уникальный одноразовый код и сохранял бы его в БД.
    А в боте по /start выводил бы сообщение, мол, введите свой код. При вводе кода ищи его в БД, если нашел - помечаешь пользователя как зареганного и записываешь его ID.
    Нужно будет навесить пару прибабахов типа возможности запросить новый код, защиту от попыток перебора кодов, и т.п., но суть от этого не меняется.
    Ответ написан
    1 комментарий
  • Как определить большинство и меньшинство по числовой характеристике?

    Vindicar
    @Vindicar
    RTFM!
    Т.е. ты ищешь выбросы (outliers) в данных? Ну вот в этом направлении и гугли. Можно начать с чего-то попроще, скажем, доверительного интервала.
    Или другой подход: если у тебя есть примеры таких наборов данных (а их надо иметь! вслепую много не напишешь), то ты можешь оценить закон распределения расстояний. Например, будет ли распределение похоже на нормальное (гауссово)? Если будет то можно будет оценить параметры распределения (среднее и дисперсию), и для каждого из значений оценить его вероятность. Например, значение, близкое к среднему, будет иметь высокую вероятность, а далёкое от среднего - низкую. Тогда можно будет по некоторому выбранному порогу отсекать "маловероятные" значения.
    Но это будет работать только для достаточно больших групп, хотя бы несколько десятков человек. Для трёх с половиной человек результаты будут очень неточными.
    Ответ написан
    2 комментария
  • Как имитировать физическое движение мыши?

    Vindicar
    @Vindicar
    RTFM!
    Сделай USB-устройство на базе arduino или чего-то подобного, которое имитирует мышь с точки зрения ОС и позволяет управлять собой через какой-то отдельный интерфейс. Всё остальное детектится при желании. А у разрабов игр желание детектить и банить ботов нередко присутствует.
    Ответ написан
    Комментировать
  • По какой логике нарисовать линии для древовидной структуре комментариев?

    Vindicar
    @Vindicar
    RTFM!
    Я бы озадачил дочерний коммент рисованием линии. Тогда ты можешь использовать проверку на вложенность для определения наличия линии, и псевдоселектор :last-child чтобы понять, завершать ли линию на этом уровне, или делать ответвление.
    Ответ написан
    Комментировать
  • Ошибка IndexError: list index out of range. Что делать?

    Vindicar
    @Vindicar
    RTFM!
    Включить голову и подумать, что же ещё.
    value = call.data.upper().split('/')
    Ты ожидаешь, что call.data будет содержать хотя бы один знак /, тогда value будет содержать два элемента - с индексом 0 и индексом 1. Раз IndexError, значит, скорее всего, value содержит только один элемент. А это слуится если call.data не содержит разделителя, в твоём случае /.
    b1 = types.InlineKeyboardButton('USD/EUR', callback_data='usdeur')

    Ну собственно, ты и задаёшь значения callback_data, не содержащие /. Вот и вся разгадка.
    Ответ написан
    Комментировать
  • Как сделать команду которую может использовать только владелец сервера?

    Vindicar
    @Vindicar
    RTFM!
    Читаем доки на has_guild_permissions().
    Similar to has_permissions(), but operates on guild wide permissions instead of the current channel permissions.


    "Работает похоже на has_permissions()"? Окей, тыц по ссылке.
    A check() that is added that checks if the member has all of the permissions necessary.
    Note that this check operates on the current channel permissions, not the guild wide permissions.
    The permissions passed in must be exactly like the properties shown under discord.Permissions.

    И пример кода
    @bot.command()
    @commands.has_permissions(manage_messages=True)  # имя параметра должно быть взято из discord.Permissions
    async def test(ctx):
        await ctx.send('You can manage messages.')

    Тыц по ссылке discord.Permissions, видим большоооой список разрешений. Читаем внимательно, owner нет, но в самом верху есть administrator.
    Значит, нужно has_guild_permissions(administrator=True).

    Делов на две минуты.
    Ответ написан
    1 комментарий
  • Как преобразовать html страницу в картинку на стороне сервера?

    Vindicar
    @Vindicar
    RTFM!
    а браузера на сервере не будет.

    Нет ножек - нет мультиков (с)
    Ты или используешь готовый движок HTML рендеринга и исполнения скриптов (т.е. браузер), или пишешь свой.
    Сразу скажу, последнее - нереально.

    Лучше зайди с другой стороны. Ты можешь использовать matplotlib для генерации статического изображения, так как он умеет не только графики, но и TeX-разметку для формул. А уже это изображение можно закэшировать и вставлять в HTML или в PDF, по желанию юзера.
    Ответ написан
    Комментировать
  • Какое различие между этими функциями?

    Vindicar
    @Vindicar
    RTFM!
    ЕМНИП, нормальное (второе) объявление будет автоматически поднято в начало текущего блока, что позволит вызывать функцию до её формального объявления.
    В первом случае это просто присваивание значения константе, а значит, функция будет доступна только ниже.
    Ответ написан
    Комментировать
  • Как сделать функцию горячих клавиш в telegram боте?

    Vindicar
    @Vindicar
    RTFM!
    Не надо пытаться описывать обработчик в обработчике. Это никогда не сработает так, как ты ожидаешь.
    Если бы дал себе труд погуглить, вышел бы на register_next_step_handler() и как им пользоваться.

    Ну и да, ты спалил токен от бота. Его теперь могут увести, если токен не сменишь.
    Ответ написан
    Комментировать
  • Как произвести сортировку в таблице SQLite3, после удаления записи?

    Vindicar
    @Vindicar
    RTFM!
    Ты просто не понимаешь сути первичного ключа.
    Это значение, которое однозначно идентифицирует строку, независимо от наличия и количества других строк в таблице. И точка. Он не должен меняться вообще за время жизни строки.
    Бывают случаи, когда у нас уже есть уникальное значение, которое можно использовать как ключ.
    Но куда чаще используются синтетические ключи, т.е. просто числа, которые пользователь по-хорошему и видеть-то не должен никогда. А раз так, то какая разница, есть ли дырки в нумерации?
    Я больше скажу, иногда сплошная нумерация - это слабое место в системе.
    Ответ написан
    Комментировать
  • Как реализовать передачу данных между компьютером и сервером?

    Vindicar
    @Vindicar
    RTFM!
    У пользователя белого IP не будет почти гарантированно, это не бесплатное удовольствие и далеко не все провайдеры его вообще предоставляют.
    PythonAnywhere также жёстко ограничивает адреса, на которые можно обращаться бесплатному аккаунту. Так что при таких вводных особо ничего не поделаешь.
    Хотя можно инвертировать - пусть пользовали стучатся на сервер по старому доброму HTTP, а твоё приложение это обслуживает.

    Вообще встаёт вопрос, а нахрена такая архитектура? Зачем пользователю вообще запускать у себя твоё приложение? Ботнет мутишь?
    Ответ написан
  • Почему не парсятся ссылки на python?

    Vindicar
    @Vindicar
    RTFM!
    Ну значит тут что-то накосячил:
    images = [img.strip() for img in lines[2][8:].split(',')]

    Не видя перед собой примера данных, трудно сказать что именно.

    EDIT: Проблема в строке lines = article.strip().split('\n')
    Ты почему-то думаешь, что у тебя весь текст статьи будет на одной строке. Это далеко не так.
    Единственный маркер, который у тебя есть - Images: в начале одной из строк. И да, если такое встретится в тексте статьи - парсер сломается.
    Ответ написан
    1 комментарий
  • Как войти в аккаунт на сайте с помощью python requests?

    Vindicar
    @Vindicar
    RTFM!
    Добавь заголовки запроса, в качестве реферера поставь тот же URL.
    Как это сделать, читай в доках requests.
    Ответ написан
    Комментировать
  • Почему то при запуске кода в pycharm срабатывает ошибка 0, и тг бот не реагирует на команды. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Учи азы программирования.
    Exit code 0 в практически любой операционной системе означает, что программа завершилась без ошибок. Это относится и к программам на питоне - они завершаются с кодом 0, если выполнение спокойно дошло до конца файла без непойманных исключений. Есть ещё функция sys.exit(), но про неё сам почитаешь.

    А в твоём случае ты накосячил в обёртке тела программы. Правильно будет
    if __name__ == "__main__":
    Тоже советую погуглить и почитать, что это, как работает, и зачем оно.
    Ответ написан
    5 комментариев
  • Не работают кнопки в discord.py, что делать?

    Vindicar
    @Vindicar
    RTFM!
    @Code.bot.command()
    На момент выполнения этого декоратора класс ещё не закончил создаваться, а значит, не был присвоен имени Code.
    Почитай документацию на либу, как правильно создавать коги и каким декоратором в них отмечать команды.
    Для discord.py это @commands.command().
    Ответ написан
  • Как вы боритесь с циклическими импортами в Python?

    Vindicar
    @Vindicar
    RTFM!
    Если речь идёт об импорте только ради type hinting, то typing.TYPE_CHEKING в помощь.
    Ответ написан
    Комментировать
  • Как обработку данных вывести в отдельный route?

    Vindicar
    @Vindicar
    RTFM!
    Код у тебя странный. asyncio.get_event_loop().run_forever() не будет вызвано, так как app.run() блокирует программу. run_ssh_command() использует asyncio только для ожидания. А смысл?

    Имей ввиду, Flask запускает каждый роут в отдельном event loop, так что фоновую задачу через create_task() запустить не выйдет.
    Тебе нужно будет запустить отдельный воркер в отдельном потоке. Задачей этого воркера будет выполнять ssh команды, а также сообщать текущий статус команды и результат её выполнения. Так что API у воркера должно быть несложное.
    Очередь (queue.Queue) команд принимает на вход описание команды, которую нужно выполнить, и какой-то ID запроса (чтобы понять, где чья команда).
    Воркер ждёт значение из очереди, выполняет команду, и помещает отклик команды в хранилище ответов вместе с ID. Соответственно должен быть метод, который по ID проверит наличие ответа в хранилище, и вернёт его, если он есть. Хранилище стоит защить мьютексом (threading.Lock), и время от времени чистить от старых ответов.

    Соответственно во Flask ты делаешь отдельный роут, который принимает ID запроса, и дергаёт этот метод воркера на предмет наличия ответа. А на стороне клиента дёргаешь этот роут периодически, пока не получишь ответ в удобном для тебя формате (например, JSON).
    Вот пример реализации воркера

    from typing import Union, Dict
    import threading
    import time
    import queue
    import uuid
    import paramiko
    
    
    class SSHWorker(threading.Thread):
        def __init__(self, hostname: str, username: str, password: str):
            super().__init__(daemon=True)
            self.__client = paramiko.SSHClient()
            self.__client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.__hostinfo = (hostname, username, password)  # если сохраним эти данные, можно будет сделать реконнект
            self.__commands = queue.Queue(maxsize=10)  # очередь на выполнение не более 10 команд
            self.__responses = {}  # ответы команд
            self.__response_lock = threading.Lock()
            self.__run = True  
        
        def add_command(self, command: str) -> Union[str, None]:
            """Добавляет в очередь команду и возвращает её уникальный id, если это прошло успешно. Иначе вернёт None."""
            cmdid = str(uuid.uuid4())
            try:
                self.__commands.put_nowait((cmdid, command))
            except queue.Full:
                return None
            else:
                return cmdid
        
        def check_command(self, cmdid: str) -> Union[dict, None]:
            """Проверяет, выполнилась ли команда. Вернёт None если нет, или ответ если да."""
            with self.__response_lock:
                return self.__responses.get(cmdid, default=None)
        
        def stop(self) -> None:
            """Говорит потоку остановиться. Фактическая остановка произойдёт позднее, смотря по таймауту ожидания команды."""
            self.__run = False
        
        def run(self) -> None:
            self.__client.connect(self.__hostinfo[0], username=self.__hostinfo[1], password=self.__hostinfo[2])
            while self.__run:
                try:
                    cmdid, command = self.__commands.get(timeout=5.0)  # есть ли команда в очереди?
                except queue.Empty:  # нет
                    # это позволяет остановить поток, если self.__run станет False, а также удалить старые незапрошенные ответы
                    too_old = time.monotonic() - 300.0  # удаляем все ответы старее 300 секунд, чтобы память не утекала
                    with self.__response_lock:
                        for cmdid, response in list(self.__responses.items()):
                            if response['timestamp'] < too_old:
                                del self.__responses[cmdid]
                else:  # что-то есть - выполняем
                    try:
                        stdin, stdout, stderr = self.__client.exec_command(f'/sbin/{command}', get_pty=True)
                        time.sleep(4.0)
                        response = stdout.read().decode('utf-8')
                    except Exception as err:
                        with self.__response_lock:
                            self.__responses[cmdid] = {'success': False, 'error': f'[{err.__class__.__name__}]: {err!s}', 'timestamp': time.monotonic()}
                    else:
                        with self.__response_lock:
                            self.__responses[cmdid] = {'success': True, 'output': response, 'timestamp': time.monotonic()}
                    self.__commands.task_done()


    Ну и да, ты спалил данные SSH. =)
    Ответ написан
  • Есть ли способ аннотировать аргументы метода переменной класса?

    Vindicar
    @Vindicar
    RTFM!
    Если у тебя config может различаться во время выполнения, то нельзя. Статический анализ не выполняет анализируемый код.
    Ответ написан
  • Почему бот телеграмма завершается сам по себе?

    Vindicar
    @Vindicar
    RTFM!
    У тебя bot.polling() почему-то с отступом. Как будто он внутри save_vk_id_to_database().
    Проверь код ещё раз. Отступы в питоне критичны!
    Ответ написан
    Комментировать
  • Как заставить клиента ждать запуска сервера?

    Vindicar
    @Vindicar
    RTFM!
    Ну если простейшее решение...
    Таймаут на connect(), connect() завернуть в try-except, который ловит socket.timeout и спит несколько секунд. Всё это завернуть в while True.
    Ответ написан
    Комментировать