Задать вопрос
  • Как сделать так,чтобы при отправке любого сообщения бот реагировал?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Тут аж несколько проблем.

    Зачем бот отправляет пользователю пустое сообщение? Скорее всего, на это выскочит ошибка.

    Зачем секция вызова поллинга бота засунута в обработчик, а не находится в основном теле бота? Такой бот просто молча завершится.

    Зачем сравнивать строку message.text с модулем random? Всегда будет False, очевидно же.

    Весьма настоятельно рекомендую учебник и получение элементарных знаний. Даже тривиальный бот совсем без функционала вызывает такие огромные проблемы при написании, и это явно неслучайно.
    Ответ написан
    Комментировать
  • Возможно ли узнать список файлов доступных для загрузки, если страница с прямой ссылкой на их скачивание удалена, но прямая ссылка работает?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В общем случае - нет, нельзя. Но кое-что сделать можно.

    Во-первых, можно посмотреть в Web Archive наличие страниц и даже самих файлов. Не всегда удаётся, но всё же.

    Во-вторых, если файлы были доступны недавно, то можно попытаться поискать их в кэше поисковика. Например, можно поискать "altered_state.zip site:fatapejungle.com"

    В данном случае всё это не помогает, но в других случаях может помочь. Например, я как-то восстанавливал из веб-архива и частично из кэша гугла один удалённый в результате конфликта среди его владельцев сайт.
    Ответ написан
    Комментировать
  • Callback-кнопка в модуле telebot (язык python) не обновляет свое содержание. Что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что при каждом вызове sayanswer будет создаваться новый обработчик callback_query_handler(func=lambda callback: callback.data), добавляясь к списку уже имеющихся. И естественно, что тот, который "застолбил" позицию первым, будет вызываться до скончания жизни запущенного бота. И естественно, что в нём значение url будет таким, каким было при первом запуске sayanswer.

    Главная ошибка тут в том, что НЕЛЬЗЯ внутри функции объявлять другие функции, не понимая чётко, зачем это нужно. Иногда так делают для решения конкретных задач. Но в данном случае это совершенно не нужно и создаёт незапланированное поведение. Функцию check выносим на уровень выше. И не используем в ней переменные из функции sayanswer. Если нужно что-то передать в check - передаём через callback_data.

    Например, можно передать "btn1:кот". В check использовать декоратор с фильтром func=lambda callback: callback.data.startswith("btn1:"). В самой функции откусывать btn1: от начала и уже только тогда формировать запрос к внешнему сервису.
    Ответ написан
    Комментировать
  • Как сделать чтобы один State реагировал на два хендлера?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Если это сторонний API, который не выполняет следующий запрос до завершения текущего, то бесполезно что-то у себя ковырять, всё равно пока запрос первого не будет обработан, запрос второго обрабатывать не начнёт. Тут ничего уже не поможет.

    Если же проблема в том, что обращение к API делается синхронным кодом... Ну так это и надо лечить. Например, если API работает по протоколу http, то меняем библиотеку requests (или что там используется?) на aiohttp. Тогда следующий запрос может выполняться до завершения уже начатого.
    Ответ написан
    Комментировать
  • Как исправить ошибку sqlite3.IntegrityError: UNIQUE constraint failed: users.user_id?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Нет, эта ошибка возникает при INSERT либо UPDATE, если в результате операции в таблице users появятся две записи с одинаковым user_id. От SELECT такого быть не может. Я бы рекомендовал всё же проверить точный номер нужной строки, чтобы убедиться в этом.

    Чтобы этого не происходило, нужно уметь следить за тем, чтобы пользователи второй раз не вставлялись таблицу или чтобы их id не изменялись на конфликтующие при UPDATE. Но тут, скорее всего, влияет только INSERT. Вот с ним и надо делать аккуратно, вставлять только новых пользователей, а если пользователь уже есть - ничего не делать либо обновлять имеющуюся запись (смотря как именно требуется для логики приложения).

    Как вариант, можно сделать совсем по-простому: вместо INSERT использовать REPLACE, который комбинирует INSERT и UPDATE - если при вставке запись с таким id уже есть и случается ошибка, то фактически выполняется UPDATE соответствующей записи с изменением всех перечисленных полей. Например, для REPLACE INTO users (user_id, referrer_id) фактически выполнится что-то типа UPDATE users SET referrer_id=... WHERE user_id=...
    Ответ написан
    Комментировать
  • Как получить кол-во просмотров на посте в тг, с помощью тг бота (node js)?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Никак. Боты работают на событиях: пришло сообщение, человек вступил в группу... Получать историческую информацию по сообщениям невозможно.

    Достать такую информацию можно только с помощью клиентского API (MTProto).
    Ответ написан
    2 комментария
  • Почему Zabbix agent подключается к не понятным IP?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    172.17.0.1 это обычно локальный IP интерфейса docker0. Вся сеть 172.17.0.0/24.

    Модно посмотреть вывод ip addr list dev docker0 и docker network ls, чтобы убедиться.
    Ответ написан
    4 комментария
  • Aiogram бот выдаёт ошибку. TypeError: rezume() missing 1 required positional argument: 'message' что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что плохо читаем документацию. Потому что копипастим куски кода без понимания как они работают.

    message_handler принимает один аргумент - Message.

    callback_query_handler принимает один аргумент - CallbackQuery.

    Тут зачем-то в callback_query_handler два аргумента - call и message. Но бот-то вызывает его так, как и требуется по документации - с одним аргументом. И python обоснованно жалуется, что второй аргумент (message) не передавался.

    До кучи, никогда (НИКОГДА!) нельзя объявлять новые handler'ы внутри имеющихся. Это работает не так, как ты думаешь, и может вызвать очень забавные глюки. Вообще, я не знаю, где люди такому учатся, но на этом сайте с таким приходят регулярно.

    Например...
    Если есть в двух разных функциях-обработчиках "верхнего уровня" есть обработчики с одинаковым фильтром в декораторе (вариант: обработчики могут покрывать общее подмножество случаев), то бот зарегистрирует первым тот "суб-обработчик", для которого "верхнеуровневый обработчик" вызвался первым. В итоге другой обработчик не будет вызываться вообще никогда, а поведение бота может быть весьма неожиданным.


    Далее, в обработчике надо ответить пользователю, установить следующее состояние и сразу же завершить работу этого обработчика. Всю дальнейшую обработку следует выполнять в следующих обработчиках. А сейчас в этом коде все вопросы задаются подряд в одной и той же функции по имени rezume подряд, безо всякого ожидания ответа от пользователя. Короче, сейчас в коде полная лажа, так работать не будет вообще никак.

    PS: Слово "резюме" по-английски пишется совсем не так.
    Ответ написан
    Комментировать
  • Как сделать чтобы бот запоминал следующее сообщение после слеш-команды?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В общем случае это плохая идея. А вдруг сообщение напишет другой пользователь, чем отправил команду?

    Правильнее использовать параметры, лучше с type hinting, чтобы Discord сам подсказывал параметры и приводил типы. Примерно так:

    @bot.slash_command(name='set', description='...')
    async def settings(ctx, selected_channel: discord.Channel):
        await ctx.send(f"Вы выбрали канал {selected_channel.mention}")
    Ответ написан
    6 комментариев
  • Код Telegram бота на компьютере работает нормально, залил на хостинг, парсер не работает, выдаёт ошибку, что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В бесплатных тарифах на pythonanywhere ограничен список адресов, к которым можно обращаться:

    https://www.pythonanywhere.com/whitelist/

    Указанного адреса нет (но есть похожие). Может, надо обращться к одному из похожих?
    Ответ написан
    3 комментария
  • Как взять часть url и подставить в proxy_pass?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Смотрим в документации варианты синтаксиса location. Например, можно сделать так:

    location ~ ^/api-test/(.*)$ {
        proxy_pass http://10.0.0.247:8170/api/service/$1$is_args$args;
    }


    Советую не спешить копипастить, а всё же прочитать и так не слишком длинную документацию. Чтобы лучше понимать, как это работает, и реализовать оптимальным для своей задачи образом.
    Ответ написан
    Комментировать
  • Как сделать регистрацию команд из базы данных Disnake.py?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В документации disnake (впрочем, и в discord.py тоже) какая-то ерунда написана. Вот как выглядит описание Command.__init__ в коде:

    def __init__(
            self,
            func: CommandCallback[CogT, ContextT, P, T],
            **kwargs: Any,
        ) -> None:
    
        ...
    
        self.callback = func


    То есть callback на самом деле это обязательный позиционный параметр.
    Ответ написан
    2 комментария
  • Как получить chat_id из обьекта query | Aiogram?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Очевидно, в данном случае запрос делается из группового чата, а у групповых чатов user_id не совпадает с chat_id. Это вообще очень распространённая ошибка. Я вообще рекомендую всем всегда явно использовать chat_id, потому что в теории Телеграм может когда-нибудь даже для личных чатов начать использовать id, отличные от id пользователей.

    В query есть объект query.message, который содержит исходное сообщение, в котором нажали на кнопку. А в нём, соответственно, есть query.message.chat с объектом чата. А в query.message.chat уже есть id.
    Ответ написан
    Комментировать
  • Как сделать меню с inline - стрелками влево - вправо?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Например, пусть у нас есть каруселька из N элементов с номерами от 1 до N. Тогда можно просто показывать элемент 1, а у него две кнопки "влево" с callback=item:N и "вправо" с item:2. При нажатии на кнопку с callback=item:k редактировать это сообщение, выводя в него содержание элемента k и клавиатуру с кнопками item:(k-1) и item:(k+1).

    Это в общих чертах. Конкретная реализация может сильно различаться в зависимости от уровня хотелок, структуры данных итд итп. Например, можно показывать список категорий (в том числе с постраничным выводом), а в категориях уже позволять листать элементы категорий. Или можно позволить сделать поиск и устроить карусель из результатов поиска. Человеческая фантазия практически безгранична.
    Ответ написан
    Комментировать
  • Проблема с python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что надо учить язык, читать документацию и официальные примеры, а не по видео пытаться что-то там сделать. Где в этом коде делается поллинг? Естественно, без него скрипт будет сразу завершаться и работать не начнёт.
    Ответ написан
    2 комментария
  • Как запретить давать атрибуты функции без ключей?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    def func(param1, param2, *, param3, param4, ...):

    * означает, что дальше будут только keyword-аргументы. До звёздочки будут обычные позиционные аргументы.
    Ответ написан
    Комментировать
  • Как сделать скрипт на python запускающий батник?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Надо было лучше гуглить.

    os.system
    os.startfile
    Ответ написан
    Комментировать
  • Telegram Bot API как боту отправить контакт?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Бот может отправить пользователю кнопку, при нажатии на которую пользователь разрешает передать боту свои контактные данные.

    См. опцию request_contact в документации.
    Ответ написан
    5 комментариев
  • Как работает asyncio.sleep?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Есть такой системный вызов select (а также подобные ему poll, epoll итд), суть которого - передать массив файловых дескрипторов (частный случай - сетевых соединений) и затем при получении событий ввода-вывода получить список тех дескрипторов, в которых произошёл ввод-вывод. Важно понимать, что при это программа "засыпает", передаёт управление ОС и не тратит ресурсов. ОС сама разбудит программу при наступлении нужных событий (записался файл, пришли новые сетевые байтики итд). Высокопроизводительные сетевые приложения (типа nginx, haproxy итд) используют подобный подход для того, чтобы эффективно обрабатывать большое количество сетевого трафика одновременно.

    asyncio работает как раз примерно по тому же принципу. Когда случается ввод-вывод, нужная функция "засыпает", а управление передаётся потоку событий. Соответственно, он либо находит задачу, которая ожидает выполнения и передаёт ей управление, либо видит, что все задачи уже одидают какого-нибудь ввода-вывода и запускает select на все ожидающие дескрипторы (возможно, в реальности используется не select, а какой-то из его аналогов, но это для нас сейчас непринципиально). Как только приходит событие, программа просыпается, поток событий находит нужное событие и передаёт управление соответствующей задаче, которая его ожидала. Это позволяет очень эффективно в один поток работать с задачами, которые много ожидают ввода-вывода, но мало выполняют реальной процессорной работы.

    Обычный ввод/вывод является блокирующим: пока не будет выполнена операция (чтение/запись/передача/приём), программа приостанавливает свою работу в ожидании. В asyncio весь ввод-вывод является неблокирующим: операции ввода-вывода не приостанавливают работу программы, а позволяют перейти к другим ожидающим задачам.

    Обычный вызов sleep приводит к приостановке и засыпанию программы на указанное время (с передачей управления ОС), и в ней в это время ничего не выполняется. Как только время истечёт, ОС вернёт управление программе. Всё это время программа не работает, события ввода-вывода не обрабатывает.

    В то же время asyncio.sleep возвращает управление потоку событий, а не ОС, что позволяет переключиться на выполнение других задач, обработать новые события итд итп. Программа не останавливается и управление ОС не передаёт (ну, кроме сна в процессе исполнения select), поэтому asyncio.sleep приводит к неблокирующему засыпанию, не мешающему выполнять задачи, которым ждать окончания сна одной конкретной задачи не нужно. Когда истечёт не менее чем указанное в asyncio.sleep время, поток событий вернёт управление приостановленной задаче.

    Важно отметить, что и sleep, и asyncio.sleep не гарантируют, что функция возобновит работу через указанное число секунд, а не позже, но при этом sleep делает это значительно точнее. Потому что возврат в вызвавшую asyncio.sleep функцию может произойти только из потока событий и только при условии, что поток событий не вернёт управление какой-то другой задаче.

    Например, пусть есть функция, которая делает asyncio.sleep(1), затем три секунды работает числомолотилка без ввода-вывода. Тогда если у нас выполняются подряд с интервалами 0.1 с три таких функции, то первая задержит на 2.9 секунд возврат управления второй, а вторая - на 5.8 с третьей.

    Это общий принцип, разумеется, там много нюансов и особенностей реализации.
    Ответ написан
    Комментировать
  • Если сменить номер телефона в Telegram, сменится ли api_id и api_hash?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    api_id и api_hash - это реквизиты не аккаунта, а клиента Telegram. Соответственно, используя их, войти в твой аккаунт не получится. Конечно, если вместе с ними утёк дамп сессии, то это уже другое дело.

    Сменить api_id и api_hash нельзя. Только удалить свой аккаунт целиком и создать новый. Собственно, на странице https://my.telegram.org/apps предупреждают, что их надо хранить в секрете.
    Ответ написан