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

    Vindicar
    @Vindicar
    RTFM!
    Я исхожу из того, что ты можешь сопоставить пользователя, открывшего страницу, с пользователем, подписанным на твоего телеграм-бота. Надеюсь, ты в курсе, что боты ограничены в возможностях инициации контакта с пользователем - пользователь должен послать сообщение или войти в чат, где бот является админом.

    Я думаю, схема будет такая:
    1. При входе на целевую страницу, JS генерирует AJAX запрос с помощью fetch() или XMLHttpRequest, на твой выбор. Форму запроса (GET/POST) и передаваемые данные определяешь ты сам, но их должно быть достаточно для идентификации пользователя. В простейшем случае URL целевой страницы должен быть уникальным для каждого пользователя, и тогда можно будет передать этот уникальный идентификатор.
    2. Есть небольшой HTTP-сервер, который принимает эти запросы, записывает их в локальную базу данных и даёт отклик вида "успех/неудача". На чем он написан - неважно, но для простоты можно использовать Flask. Там будет строк 100 от силы. В качестве базы можно использовать sqlite.
    3. Есть Python бот, использующий одну из библиотек под телегу, который периодически смотрит в эту базу и проверяет наличие необслуженных запросов. Если таковые находятся, бот их перебирает, определяет для каждого запроса соответствующего пользователя, отправляет файл, и помечает запрос как обслуженный (ну или просто удаляет).
    61ceec5390670627570751.png

    Есть соблазн совместить пункты 2 и 3 в одном процессе, но это может оказаться нетривиально - тебе придётся крутить работу веб-сервера в главном потоке, а работу бота - в дополнительном. Тогда вместо базы данных можно будет использовать очередь (threading.Queue) - главный поток (Flask) кладёт задания в очередь, а поток бота - выбирает и обслуживает.
    61ceedcee35a5542427561.png
    Плюсы - один Python-скрипт вместо двух, отсутствие промежуточной БД.
    Минусы - повышенная сложность скрипта, при внезапной остановке скрипта текущие задания в очереди будут потеряны, труднее вести статистику обслуживания ботом пользователей.
    Решай сам, стоит ли оно того.
    Ответ написан
    7 комментариев
  • Сортировка словаря по нескольким значениям с условием по time.time()?

    Vindicar
    @Vindicar
    RTFM!
    Ну во-первых, обычные словари сортировке не особенно поддаются. Порядок перебора ключей в словаре не определён, если я не путаю - нет гарантии, что на разных машинах, или на разных версиях питона, или даже при разных запусках скрипта порядок будет одним и тем же.
    Есть, правда, collections.OrderedDict - вот они запоминают порядок ключей, но это порядок всегда хронологический - самый поздний заданный ключ всегда будет последним при переборе.
    Во-вторых, лучше декомпозируй задачу на две. Сначала отфильтруй нужное, потом уже сортируй. Делать всё за один проход трудно, да и нужно ли?

    Я бы вообще посоветовал временно представить словарь как список кортежей (ключ, значение), и фильтровать/сортировать этот список.
    Ответ написан
  • Подскажете аналог set(), но для словаря?

    Vindicar
    @Vindicar
    RTFM!
    Даже не знаю с чего начать.
    Во-первых, массивы в питоне - это array, и они используются нечасто. Я сильно подозреваю, что ты имел ввиду списки (list).
    Во-вторых, set() к спискам отношения не имеет, это абсолютно самостоятельная структура данных - множество. От того, что есть идиома без_повторов = list(set(с_повторами)) set() не становится методом списка или чем-то подобным. Эта идиома прекрасно работает с любым коллекциями - списками, кортежами (tuple), да с чем угодно.
    В-третьих, повторы чего ты хочешь устранить? Ключей? Значений?
    Если ключей, то в словарях ключи и так не повторяются, как уже написали выше. Повторяющийся ключ просто заменит собой старый.
    Если значений, то тебе сначала придётся решить, какой из ключей с одинаковым значением сохранить.
    Ответ написан
    Комментировать
  • Как узнать индекс динамического виджета tkinter?

    Vindicar
    @Vindicar
    RTFM!
    Есть два подхода. Один основан на лямбдах:
    for i in range(2):
        buttonFrame_update=Button(frame,text="Добавить", command= lambda arg=i: update_main_db(arg))

    Приём с аргументом лямбды необходим, чтобы сохранить текущее значение i - иначе в момент вызова лямбды она прочитает последнее значение i, а оно будет указывать на последнюю строку.

    Второй способ, которя я бы выбрал - написать свой виджет - строку таблицы. Тогда обработчик нажатия на кнопку сможет брать данные из экземплярной переменной.
    class MyTableRow(Frame):
        def __init__(self, master, *args, **kwargs):
            super().__init__(master, *args, **kwargs)
            self.widgets = []
            for i in range(3):
                widget = Entry(frame)
                widget.pack(side="left")
                self.widgets.append(widget)
            self.update_btn = Button(self, text = "Добавить", command = self.update_clicked)
            self.update_btn.pack(side="right")
            self.delete_btn = Button(self, text = "Удалить", command = self.delete_clicked)
            self.delete_btn.pack(side="right")
      
        def update_clicked(self):
            print(self.widgets[0].get())
        
        def delete_clicked(self):
            print("whatever")
    
    
    for i in range(2):
        item = MyTableRow(doth, borderwidth=2, relief="groove")
        frames.append(item)
        item.pack(side="top", fill="x")
    Ответ написан
    5 комментариев
  • Не свосем юзербот на discord.py?

    Vindicar
    @Vindicar
    RTFM!
    Нельзя. И хорошо что нельзя.

    Можно подставить имя пользователя в начало текста, но всё равно будет видно, кто писал на самом деле.
    Ответ написан
    Комментировать
  • Защита софта на Python?

    Vindicar
    @Vindicar
    RTFM!
    Вопрос вообще "как идентифицировать компьютер". И это нетривиально.
    1. Получить MAC адрес сетевой карты и проверить его на вхождение в список. Простейший способ его получить - примерно такой:
    import uuid
    print(hex(uuid.getnode()))

    * неясно, как поведет себя функция, если на компе несколько сетевых адаптеров.
    * смена сетевой карты сломает программу
    * MAC адрес сетевой карты часто можно сменить
    2. Можно попробовать использовать CPUID, например, так.
    Но я без понятия, какие процессоры это поддерживают!
    3. Можно разместить секретное значение в реестре целевых машин, и проверять его наличие.

    Самая большая проблема - эту проверку может отломать любой, более-менее знакомый с языком.

    Можешь использовать пакет типа pyarmor, он вроде предоставляет механизм создания "лицензий" и обфусцирует исходный код, чтобы его труднее было анализировать и изменить. Но и pyarmor тоже отламывается при желании.

    Так что главный вопрос: а нафига?
    Ответ написан
    2 комментария
  • Как вывести все данные из БД?

    Vindicar
    @Vindicar
    RTFM!
    value, create = Choose.objects.get_or_create(voter=request.user)


    Может, поэтому?
    Ответ написан
    Комментировать
  • Как настроить ssh туннель для smb?

    Vindicar
    @Vindicar
    RTFM!
    В ssh есть три варианта проброски портов.
    -L lport:remote.host:rport задаёт проброску клиентского порта, т.е.
    1. клиент SSH слушает порт lport на своей машине. По умолчанию на всех сетевых интерфейсах, но можно указать желаемый адрес, который будет слушаться, так: bind.address:lport:remote.host:rport
    2. когда к этому порту кто-то коннектится, клиент сообщает серверу
    3. сервер коннектится на remote.host:rport
    4. В дальнейшем данные пробрасываются через этот туннель.

    -R rport:local.host:lport работает наоборот
    1. сервер SSH слушает порт rport на своей стороне. По умолчанию на всех сетевых интерфейсах, но можно указать желаемый адрес, который будет слушаться, так: bind.address:rport:local.host:lport
    2. когда к этому порту кто-то коннектится, сервер уведомляет клиента
    3. клиент коннектится на local.host:lport
    4. В дальнейшем данные пробрасываются через этот туннель

    И последний, самый практичный, но самый трудно контролируемый.
    -D lport или -D bind.address:lport
    1. клиент слушает порт lport на своей стороне
    2. когда к этому порту кто-то коннектится, клиент пробрасывает соединение на ssh сервер
    3. ssh сервер отвечает по протоколу прокси SOCKS4/SOCKS5, и выполняет дальнейшие соединения в зависимости от желаний подключившегося приложения.
    Т.е. чтобы это работало, нужно чтобы приложение умело работать с SOCKS-прокси.

    Не помогает - значит нужно отлаживать. Я не вполне понял, где расположена smb-шара - на том же хосте, что и ssh сервер? Или на другом? Также стоит убедиться, что соединение с ssh сервером устанавливается нормально.
    Наконец, стоит выделить под такие туннели отдельного пользователя на сервере, и ограничить его в правах на всё, кроме использования туннеля.
    Ответ написан
  • Хэш и соль пароля в файл?

    Vindicar
    @Vindicar
    RTFM!
    1. Читаешь из файла соль и хэш пароля.
    2. К введенному паролю добавляешь соль (так же, как она была добавлена к сохранённому) и хэшируешь.
    3. Сравниваешь два хэша - полученный и прочитанный. Если они совпали, пароль верен.
    Ответ написан
    2 комментария
  • Как переметить нулевые значения в конец списка?

    Vindicar
    @Vindicar
    RTFM!
    original_list = [0,1,8,3,0,4,5,0,0] #исходный список
    new_list = [x for x in original_list if x != 0] #только ненулевые элементы
    how_many_zeros =  len(original_list) - len(new_list) #сколько нулей потеряли?
    new_list.extend( [0] * how_many_zeros ) # добавляем нужное количество нулей в конец
    Ответ написан
    1 комментарий
  • Как еще чуть ускорить алгоритм?

    Vindicar
    @Vindicar
    RTFM!
    А не проще ли будет сделать в два прохода.
    Прямым проходом делаем так: если 0, то счетчик в ноль, иначе счетчик + 1 и элемент приравниваем счетчику.
    Потом то же самое делаем обратным проходом, но изменяем элемент только если он больше счетчика.
    Отсюда получаем:
    lst=[5, 3, 0, 2, 0, 3, 8, 2, 9, 7, 0, 0, 7, 1, 5, 3]
    L = len(lst)
    # если в начале списка не 0, то мы сможем задать корректные значения только на обратном ходе
    # так что ставим заведомо большее значение счетчика
    counter = len(lst) if lst[0] != 0 else 0
    for i in range(0, L):
      if lst[i] == 0:
        counter = 0
      else:
        counter += 1
        lst[i] = counter
    # обратный ход
    counter = lst[-1] - 1 #чтобы не запороть последние элементы
    for i in range(L-1, -1, -1):
      if lst[i] == 0:
        counter = 0
      else:
        counter += 1
        lst[i] = min(counter, lst[i])
    
    print(lst)
    # [2, 1, 0, 1, 0, 1, 2, 3, 2, 1, 0, 0, 1, 2, 3, 4]

    Правда, это даст некорректный результат, если список не содержит нулей. Но это можно обнаружить в ходе первого прохода.
    Ответ написан
    2 комментария
  • Что то не то в скрипте?

    Vindicar
    @Vindicar
    RTFM!
    Перечитывать файл каждый раз при обработке сообщения - не лучшая идея.

    Вместо этого сделай отдельную команду, которая будет его перечитывать.
    blacklist = []
    def load_stoplist():
        global blacklist #чтобы можно было изменить глобальную переменную
        inputfile = '1.txt'
        # учись как правильно работать с файлами
        with open(inputfile, mode='r', encoding='utf-8') as f:
            blacklist = list(map(str.strip, f.readlines()))
    
    @bot.message_handler(commands=['reload'])
    def reload_blacklist(message):
        #тут имеет смысл вставить проверку, чтобы бот игнорировал эту команду от других юзеров
        load_stoplist()
    
    #ну и так далее. А в конце скрипта
    if __name__ == "__main__":
        load_stoplist()
        bot.infinity_polling()
    Ответ написан
  • Discord.py кортеж и split,в чем проблема?

    Vindicar
    @Vindicar
    RTFM!
    Ты пытаешься сделать рандомный выбор из введённых значений?
    А на кой пельмень ты вообще соединяешь args? Если они разделяются пробелом, то так
    # команда вызывается как !choice вариант1 вариант_2 "вариант 3"
    @commands.command(pass_context=True)
    async def choice(self, ctx, *args:str):
      chosen = random.choice(args)

    А если прямо нужно через запятую, то лучше так:
    # команда вызывается как !choice вариант1, вариант 2, вариант 3
    @commands.command(pass_context=True)
    # discord.py интерпретирует * как "всю остальную строку засунь в следующий параметр" 
    async def choice(self, ctx, *, args:str): 
      choices = [arg.strip() for arg in args.split(',')]
      chosen = random.choice(choices)
    Ответ написан
  • Как всё таки работает асинхронность?

    Vindicar
    @Vindicar
    RTFM!
    Передразнивая одного человека, асинхронность это кооперативная многозадачность плюс цикл обработки событий.

    Упрощенно, есть набор функций, умеющих приостанавливать и возобновлять своё выполнение - корутин.
    Корутины обычно приостанавливают своё выполнение после запроса операции ввода/вывода, но могут и по другим поводам - например, просто ожидание, или ожидание завершения другой корутины, или ещё что.

    Ядром асинхронной программы является паттерн "реактор" - рабочий цикл. В контексте клиентского JS это рабочий цикл браузера, в контексте ноды - что-то отдельное, я полагаю (с нодой не работал).
    Цикл делает следующее:
    - ожидает завершения одной из операций ввода/вывода или ожидания (любой)
    - определяет, какая корутина ожидала эту операцию
    - передаёт ей управление
    - корутина делает своё дело, обрабатывая результат операции
    - потом корутина либо завершается, либо планирует еще одну операцию. И цикл возобновляется.

    Отсюда и вытекают все плюсы и минусы. С одной стороны, переключение между корутинами происходит в явно указанные моменты времени, так что меньше возни с синхронизацией.
    С другой стороны, длинные вычисления так не распараллелишь - только ввод/вывод. Ну или в длинном вычислении время от времени делать паузу, но выигрыша все равно не будет. Так что это имеет смысл только для IO-bound программ.
    Ответ написан
    3 комментария
  • Снижается версия Python почему?

    Vindicar
    @Vindicar
    RTFM!
    Нужно немножко включить голову и почитать про то, как работает SSH и оболочка Unix системы. Гуглинг типа "SSH keep program running" быстро бы вывел тебя на то что нужно.
    1. Когда ты подключаешься по SSH, сервер запускает копию bash или sh (или какая там оболочка используется) с правами твоего пользователя.
    <br>
    sshd<br>
      - bash<br>

    При вводе команды в этой оболочке программа ищется в системном PATH, а в нём находится второй питон.

    2. Потом, когда ты делаешь activate, ты переходишь в виртуальное окружение. Оно отличается тем, что питон там ищется по умолчанию другой, так как там поменян PATH (и ещё кое что). И происходит этот переход за счёт запуска дочерней командной оболочки.
    <br>
    sshd<br>
      - bash<br>
          - activate <br>
              - bash<br>


    3. Ты запускаешь свой скрипт. Он запускается из под оболочки внутри activate.
    <br>
    sshd<br>
      - bash<br>
          - activate<br>
              - bash<br>
                  - python3 your_script.py<br>


    4. Ты закрываешь putty. SSH сервер регистрирует отключение клиента, и посылает дочернему bash сигнал HUP - обычно он интерпретируется как сигнал на завершение. Тот передаёт этот сигнал своему дочернему процессу, и так далее.
    <br>
    sshd "sshd: эй, bash, завершайся"<br>
      - bash "bash: эй, activate, завершайся. А теперь я сам завершусь."<br>
          - activate "activate: эй, bash, завершайся. А теперь я сам завершусь"<br>
              - bash "bash: эй, python3, завершайся. А теперь я сам завершусь"<br>
                  - python3 your_script.py "python3: хорошо, завершаюсь."<br>

    В итоге получаем только работающий ssh сервер
    sshd
    И когда ты переоткрываешь сессию, activate уже перестал существовать, и ты снова попадаешь в обычный bash, где в PATH прописан только второй питон.

    Теперь главное: как же это обойти? Нужно сделать так, чтобы python3 проигнорировал сигнал о завершении. Есть несколько способов.
    Самый простой - использовать такой синтаксис:
    nohup python3 your_script.py &
    Амперсанд в конце означает "запусти программу и вернись в оболочку, не дожидаясь когда программа закончит работать". А команда nohup запускает указанную программу с указанными аргументами, но при этом она проигнорирует сигнал HUP, т.е. "эй, завершайся". А потому когда ты закроешь putty, бот должен остаться работать.
    Минус - после переподключения ты не будешь видеть вывод бота в консоль. Так что пиши логи!
    Чтобы остановить бота, придётся использовать ps чтобы узнать ID его процесса, и kill чтобы этот процесс прибить. Ну или можешь предусмотреть команду выхода в самом боте, которая завершит работу скрипта изнутри. Это удобнее.

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

    Третий способ - сделать так, чтобы бот запускался при загрузке, через init.d скрипт или systemd модуль. Но так как у тебя минимальные права, скорее всего это не прокатит.
    Ответ написан
    1 комментарий
  • Как написать функцию расшифровки этого алгоритма?

    Vindicar
    @Vindicar
    RTFM!
    А не факт что это вообще обратимо, так как при умножении на 31663 гарантированно произойдёт переполнение 16-разрядного целого, и старшие разряды будут потеряны.

    Можешь попробовать так, конечно: создай массив всех возможных 16-разрядных чисел: 0, 1, 2, ..., 65535.
    Затем каждый элемент этого массива зашифруй этим алгоритмом.
    Если в полученном массиве какие-то элементы повторяются, то полностью обратить операцию невозможно - только частично, только для уникальных элементов в массиве.
    Если же все элементы массива уникальны, то можно обратить операцию, просто определив индекс входной пары байт в этом массиве. Этот индекс и будет исходным значением. Тут уже есть простор для оптимизации.
    Ответ написан
  • Пишет лишнюю букву?

    Vindicar
    @Vindicar
    RTFM!
    А зачем тебе вообще цикл for i in password:?
    Если тебе нужно в консоль и в файл вывести одно и то же, то выполни F.write(f'{n} {password}\n') и всё.
    Ну и приём с with, который я показал в твоём предыдущем вопрос, тоже стоит применить.
    Ответ написан
  • Текст накладывается сам на себя?

    Vindicar
    @Vindicar
    RTFM!
    Добавлю, что
    F.close
    Не делает ровным счётом ничего, так как вы не вызываете метод close.
    Должно быть
    F.close()
    А ещё лучше заменить вот это:
    F = open("txt","w")
      for i in password:
        F.write(str(n)+ password + '\n')
        F.close

    На вот это
    with open("txt","w") as F:
        for i in password:
          F.write(str(n)+ password + '\n')
    Ответ написан
    Комментировать
  • Можно ли получить список пользователей дискорд через http url запрос?

    Vindicar
    @Vindicar
    RTFM!
    Не будучи на сервере - нет, насколько я знаю.
    Ответ написан
    Комментировать
  • Как сделать чат для трех и более компьютеров в python socket?

    Vindicar
    @Vindicar
    RTFM!
    Выдели кому-то роль сервера, пусть он слушает соединения и хранит список уже подключенных клиентов.
    По приёму сообщения от подключенного клиента, нужно переслать его всем, кроме отправителя.
    Клиенты просто слушают сообщения от сервера и выводят на экран.
    Альтернатива - использовать широковещательный UDP, но TCP-сервер надёжнее.

    Я бы посоветовал разобраться с asyncio, оно может сильно упростить написание сервера.
    Самое сложное будет написать клиента, так как нужно будет подружить asyncio с пользовательским интерфейсом клиента. Даже элементарный input() будет нетривиально использовать.
    Так что можно сразу использовать qasync, чтобы подружить pyqt и asyncio.
    Ответ написан
    Комментировать