• Как добиться последовательной работы скрипта Python с выводом результатов?

    @voland700 Автор вопроса
    Либо окно не обновляется, пока не завершиться процесс.

    Благодарю! Действительно:
    root.update()

    Обновление окна на разных этапах работы скрипта решило проблему.
  • Как добиться последовательной работы скрипта Python с выводом результатов?

    @voland700 Автор вопроса
    Александр Нестеров, Полагаю, дело не в коде, а недопонимании принципов работы. Хотя могу ошибаться конечно. Тут одним фалом, портянка конечно, сложно будет разобраться со стороны.
    spoiler

    from tkinter import *
    from tkinter import ttk
    from tkinter import PhotoImage
    from module import *
    import os
    import pyperclip
    
    
    root = Tk()
    root.title('Парсер товаров Везувий')
    root.iconbitmap('parser.ico')
    root.geometry('650x450+700+300')
    root.update_idletasks()
    
    # Кнопка - открыть деррикторию с результатами парсинга
    def open_folder():
        os.startfile('upload')
    
    # Кнопка -  очистить все, удалить информационные сообщения
    def clean_all():
        tb1_entry.delete(0, END)
        lb1_valid['text'] = ''
        lb1_label_info_1['text']=''
        lb1_label_info_2['text'] = ''
        lb1_label_info_3['text'] = ''
    
    # Вызов и обработка всплывающего меню - вставка/копирование/очистка поля ввода ссылки на категорию товаров
    def popup(event):
        global x, y
        x = event.x
        y = event.y
        menu.post(event.x_root, event.y_root)
    
    x = 0
    y = 0
    
    def inToFromBuffer():
        buffer = pyperclip.paste()
        if buffer: tb1_entry.insert(END, buffer)
    
    def clearField():
        tb1_entry.delete(0, END)
        lb1_valid['text'] = ''
    
    def copyToBuffer():
        buffer = tb1_entry.get()
        if buffer: pyperclip.copy(buffer)
    
    # Вызов и обработка всплывающего меню - вставка/копирование/очистка поля ввода ссылки на список ссылок
    
    def popup_text(event):
        global x, y
        x = event.x
        y = event.y
        menu2.post(event.x_root, event.y_root)
    def inToFromBuffer_text():
        buffer = pyperclip.paste()
        if buffer: tb2_text.insert(END, buffer)
    def copyToBuffer_text():
        buffer = tb2_text.get("1.0", END)
        if buffer: pyperclip.copy(buffer)
    def clearField_text():
        tb2_text.delete("1.0", END)
    
    # Кнопка очистить текстовое поле - список ссылок:
    def clean_links():
        tb2_text.delete("1.0", END)
        lb2_valid['text'] = ''
        lb2_valid['fg'] = '#000000'
    
    
    
    # 1.  Прарсинг товаров по ссылке на категорию:
    # 1.1 Валидация ссылки на категорию товаров
    def startPars():
        if lb1_valid['text']:
            lb1_valid['text'] = ''
        if lb1_label_info_1['text']:
            lb1_label_info_1['text']=''
        if lb1_label_info_2['text']:
            lb1_label_info_2['text'] = ''
        if lb1_label_info_3['text']:
            lb1_label_info_3['text'] = ''
    
        link = tb1_entry.get()
        if not isLink(link):
            lb1_valid['text'] = 'Укажите корректную ссылку на категорию товаров'
            return
        else:
            lb1_valid['text'] = ''
        if not isLinkCorrect(link):
            lb1_valid['text'] = 'Ссылка должна вести на сайты производителя Везувий'
            return
        else:
            lb1_valid['text'] = ''
    
        # Валидация пройдена, старт персинга
        lb1_label_info_1['text'] = 'Старт парсинга...'
    
        # 1.1 Получаем ссылки на товары указанной категории
        a = DataGetLinks(link)
        listLinks = a.get()
    
        # 1.2 Парсинг данных по полученным ссылкам, получаем данные количества товаров
        if len(listLinks) > 0:
            resault = []
            productCount = 0
            lb1_label_info_1['text'] = f'Получены ссылоки на товары: {len(listLinks)}.'
            for itemUrl in listLinks:
                page = DataPage(itemUrl)
                item = page.get()
                if item['is']:
                    tpl = item.copy()
                    resault.append(tpl)
                    productCount += 1
    
            if len(resault) > 0:
                lb1_label_info_2['text'] = 'Полученны данные товаров: ' + str(productCount)
                # 1.3 Запись полученных данных в excel файл
                line = ExcelFile(resault)
                res = line.get()
                if res:
                    lb1_label_info_3['text']='Создан файл: ' + res
                    return # Парсинг завершен
            else:
                lb1_label_info_3['text'] = f"Данные товаров не получены"
                lb1_label_info_3['foreground']='#db0303'
                return
        else:
            lb1_valid['text'] = 'Не получены ссылки на товары'
            return
    
    
    # 2.  Прарсинг товаров по списку ссылок:
    def startParsByLinks():
        if lb2_valid['text']:
            lb2_valid['text'] = ''
            lb2_valid['fg'] = '#000000'
        if lb2_label_info_2['text']:
            lb2_label_info_2['text'] = ''
        listLinks = []
        resault =[]
        productCount = 0
    
        notDomens = 0  # Количество: не ссответсвует доменам
        data = tb2_text.get("1.0", END)
    
        if data:
            lines = data.split('\n')
            for line in lines:
                link = re.sub("^\s+|\n|\r|\s+$", '', line)
                if not line:
                    continue
                if not isLink(link):
                    continue
                if not isLinkCorrect(link):
                    notDomens += 1
                    continue
                listLinks.append(link)
    
        if len(listLinks) > 0:
            #answer_1 = ''
            if not notDomens: answer_1 = f'Получено: {len(listLinks)} ссылок для парсинга.'
            else: answer_1 = f'Получено: {len(listLinks)} ссылок для парсинга. В списке ссылок {notDomens} - не соответсвуют доменам Везувий'
            lb2_valid['text'] = answer_1
            lb2_valid['fg'] = '#000000'
    
            for itemUrl in listLinks:
                page = DataPage(itemUrl)
                item = page.get()
                if item['is']:
                    tpl = item.copy()
                    resault.append(tpl)
                    productCount += 1
    
            if len(resault) > 0:
                line = ExcelFile(resault)
                res = line.get()
                if productCount > 0 and res:
                    lb1_label_info_2['text'] = f"Получен данные товаров: {productCount}, создан файл {res}"
                    lb1_label_info_2['fg'] = '#000000'
                else:
                    lb1_label_info_2['text'] = 'Данные товаров не получены'
                    lb1_label_info_2['fg'] = '#db0303'
        else:
            lb2_valid['text'] = 'Нет ссылок для парсинга'
            lb2_valid['fg'] = '#db0303'
            return
    
    #  --- GUI TKINTER
    tab_control = ttk.Notebook(root)
    tab1 = ttk.Frame(tab_control, padding=[5, 5])
    tab2 = ttk.Frame(tab_control, padding=[5, 5])
    
    tab_control.add(tab1, text="Категорий")
    tab_control.add(tab2, text="По ссылкам")
    
    # first tab1
    descripTab1 =  """
        Парсинг категорий товаров c cайтов производителя отопительного оборудования Везувий: 
        - vezuviy.su 
        - everest-pech.com
        - etna-pech.ru
        Для парсинга товаров небхдимо указать ссылку на категорию товаров на одном из указанных сайтов. 
    """
    
    lb1 = Label(tab1, text=descripTab1, justify=LEFT, font=("Arial", 10))
    lb1.place(height=100,  relwidth=1)
    
    lb1_label = Label(tab1, text='', justify=LEFT, font=("Arial", 8, "bold"), anchor=NW)
    lb1_label.place(x=10, y=105, anchor=NW)
    
    tb1_entry = ttk.Entry(tab1, justify=LEFT, font=("Arial", 11), width=45)
    tb1_entry.place(x=10, y=130, anchor=NW)
    
    tb1_entry.bind("<Button-3>", popup)
    menu = Menu(tearoff=0)
    menu.add_command(label="Вставить", command=inToFromBuffer)
    menu.add_command(label="Копировать", command=copyToBuffer)
    menu.add_command(label="Очистить", command=clearField)
    
    
    tb1_btn_start = ttk.Button(tab1, text="Start", command=startPars)
    tb1_btn_start.place(x=382, y=129, anchor=NW)
    
    folder_open = PhotoImage(file="folder-open.png")
    tb1_btn_folder = ttk.Button(tab1, image=folder_open, width=20, command=open_folder)
    tb1_btn_folder.place(x=462, y=129, anchor=NW)
    
    trash = PhotoImage(file="trash-can.png")
    tb1_btn_trash = ttk.Button(tab1, image=trash, width=20, command=clean_all)
    tb1_btn_trash.place(x=495, y=129, anchor=NW)
    
    # Вывод информации. Tab1 - валидайия и результаты парсинга
    lb1_valid = Label(tab1, text='', justify=LEFT, fg='#db0303', font=("Arial", 9, "italic"), anchor=NW)
    lb1_valid.place(x=10, y=155, anchor=NW)
    
    lb1_label_info_1 = Label(tab1, text='', justify=LEFT, font=("Arial", 10, 'italic'))
    lb1_label_info_1.place(x=10, y=175, anchor=NW)
    
    lb1_label_info_2 = Label(tab1, text='',  justify=LEFT, font=("Arial", 10, 'italic'))
    lb1_label_info_2.place(x=10, y=195, anchor=NW)
    
    lb1_label_info_3 = Label(tab1, text='', justify=LEFT, font=("Arial", 10, 'italic'), anchor=NW)
    lb1_label_info_3.place(x=10, y=215, anchor=NW)
    
    
    # ------------**********-------------------
    
    # Second tab2
    lb2 = Label(tab2, text="Укажите список ссылок товаров для парсинга:", justify=LEFT, font=("Arial", 9), padx=10)
    lb2.pack(anchor=NW)
    
    
    # Текстовое поле со скролом
    tb2_frame = ttk.Frame(tab2)
    tb2_frame.pack(fill=X, anchor=NW)
    
    tb2_text = Text(tb2_frame, font=("Arial", 9),  padx=10, pady=10,  width=30, height=15)
    tb2_text.pack(fill=X, expand=1, side=LEFT, anchor=NW)
    
    tb2_scroll = Scrollbar(tb2_frame, command=tb2_text.yview)
    tb2_scroll.pack(fill=Y, side=LEFT)
    tb2_text.config(yscrollcommand=tb2_scroll.set)
    
    # Вызов контестного меню на поле списка ссылок
    tb2_text.bind("<Button-3>", popup_text)
    menu2 = Menu(tearoff=0)
    menu2.add_command(label="Вставить", command=inToFromBuffer_text)
    menu2.add_command(label="Копировать", command=copyToBuffer_text)
    menu2.add_command(label="Очистить", command=clearField_text)
    
    
    # Кнопки управления
    tb2_frame_btn = ttk.Frame(tab2, height=45, padding=[8, 10, 6, 5])
    tb2_frame_btn.pack(fill=X, expand=0,  anchor=NW)
    
    tb2_btn_start = ttk.Button(tb2_frame_btn, text="Start", command=startParsByLinks)
    tb2_btn_start.place(x=443, y=0, anchor=NW)
    
    tb2_btn_folder = ttk.Button(tb2_frame_btn, image=folder_open, width=20, command=open_folder)
    tb2_btn_folder.place(x=525, y=0, anchor=NW)
    
    tb2_btn_trash = ttk.Button(tb2_frame_btn, image=trash, width=20, command=clean_links)
    tb2_btn_trash.place(x=560, y=0, anchor=NW)
    
    # Вывод информации. Tab2 - валидайия и результаты парсинга
    tb2_frame_info = ttk.Frame(tab2, height=75, padding=[8, 10, 0, 0])
    tb2_frame_info.pack(fill=X, expand=0,  anchor=NW)
    
    lb2_valid = Label(tb2_frame_info, text='', justify=LEFT, font=("Arial", 9, "italic"), anchor=NW)
    lb2_valid.place(x=0, y=0, anchor=NW)
    
    lb2_label_info_2 = Label(tb2_frame_info, text='', justify=LEFT, font=("Arial", 10, 'italic'))
    lb2_label_info_2.place(x=0, y=20, anchor=NW)
    
    tab_control.pack(expand=1, fill='both')
    
    root.mainloop()


  • Сайт открывается на чужом домене, совпадают IP адреса, как настроить Ahache правильно?

    @voland700 Автор вопроса
    Drno,
    + кинь абуз письмом в бегет


    Бегет послал, точнее вежливо отказал, рекомендовал решать проблему лично с владельцем домена. Прислал ответ:


    Здравствуйте!

    В данном случае к сожалению мы не можем ограничивать своих пользователей в установке DNS записей, которые они ставят, вы можете составить обращение к владельцу домена и отправить его в форме по данной ссылке: https://beget.com/ru/domains/contact
  • Ошибка Network error – при загрузки картинок на Bitrix. Как поправить?

    @voland700 Автор вопроса
    Благодарю,
    В инструментах - сообщение об ошибке:
    You don't have permission to access /bitrix/tools/upload.php on this server.


    С правами, что то. Хотя в медиабиблиотеку Bitrix файлы грузятся без проблем.

    Проблема появилась после обновления БУС до последней версии. До обновления все работало.
  • После переполнения диска на хостинге полетел MySql – повреждена база данных, как восстановить?

    @voland700 Автор вопроса
    Дмитрий, Благодарю!
    Так и есть! Сработало.
    Действительно - в таблице b_stat_session_data - содержатся данные статистики о предыдущих посещениях сайта, в моем случае, не самая важная информация для работы интернет-магазина.
    Создал дамп базы с исключением битой таблицы b_stat_session_data ,
    Развернул свежую версию БУС и отдельно сделал дамп чистой таблицы базы данных b_stat_session_data
    На локальном сервере создал базу и импортировал полученные данные из двух фалов дампов.

    Все работает! Еще раз благодарю за идею!
  • После переполнения диска на хостинге полетел MySql – повреждена база данных, как восстановить?

    @voland700 Автор вопроса
    Melkij, Sorry... Каноничный mysqldump - это что? Можно чуть подробнее? Гугл сразу не дает ответа что это такое.
  • После переполнения диска на хостинге полетел MySql – повреждена база данных, как восстановить?

    @voland700 Автор вопроса
    Melkij, Благодарю за совет. Пробовал, к сожалению не получилось.
    Создал Дамп базы, и попытался развернуть на локальном хостинге копию сайта. Однако после экспорта данных - получаю битую базу данных - MySQL Query Error!

    Да и сам, полученный дамп подозрительно большого размера, что не удивительно, проблемная таблица b_stat_session_data занимает почти 5 гигов.
    62fb9ce164ca2869878116.jpeg
  • Как отправить форму?

    А разве axios при отправке POST запроса не требует передачи заголовков и СSRF токена, что-то вроде этого?
    headers: {
         X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content,
         'Content-Type': 'application/json'
    }
  • Как предать клиенту данные о результатах валидации Laravel отправленной формы?

    @voland700 Автор вопроса
    Kentavr16, Не понимаю, почему, но из контролера, при наличии ошибок валидации, форма с ошибками заново рендерится и отправляется клиенту со статусом 200.
    Это кусок из контроллера возвращает форму с ошибками со статусом 200.

    if ($validator->fails()) {
                return redirect('/user-register')
                    ->withErrors($validator)
                    ->withInput();
            }
  • Как предать клиенту данные о результатах валидации Laravel отправленной формы?

    @voland700 Автор вопроса
    Kentavr16,
    В данном случае, при наличии ошибок валидации, console.log(response.status); возвращает статус: 200
  • Как настроить Supervisor на сервере для двух сайтов на Laravel, для отправки почтовых уведомлений с использованием механизма очередей?

    @voland700 Автор вопроса
    Valdemar Smörman,
    Я правильно понял, что artisan - это php-скрипт?

    Да, абсолютно верно - это скрипт. Но данная часть коде взята из документации к фреймворку Lravel.

    Там приведены примеры написания воркеров. Примерно так и есть, без расширения исполняемого php-скрипта artisan.

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

    @voland700 Автор вопроса
    Valdemar Smörman, Ну да, запущено... Благодарю, за подробное разъяснение о настройках.
    Судя по всему Supervisor отрабатывает, только почтовые сообщения не уходят. В log -файле пишет:
    [2022-02-22 08:40:23][63] Processing: App\Mail\Callback
    [2022-02-22 08:40:44][64] Processing: App\Mail\Callback
    [2022-02-22 08:41:05][65] Processing: App\Mail\Callback
    [2022-02-22 08:41:25][65] Failed:     App\Mail\Callback

    Буду искать причину, может в конфигах напутал...
  • Как настроить Supervisor на сервере для двух сайтов на Laravel, для отправки почтовых уведомлений с использованием механизма очередей?

    @voland700 Автор вопроса
    Valdemar Smörman, Благодарю, с этой проблемой разобрался. Указанные в ошибке "No such file or directory" файлы Python в наличии, но были доступны только root - пользователю. С правами напутал. Поправил. Теперь в порядке.

    Вот только другие траблы вылези.

    Фалы - *.conf в папке conf.d созданы, supervisord.conf полный создан и необходимые изменения внесены.

    spoiler

    ; supervisor config file /etc/supervisor/conf.d/legenda-worker.conf

    [program:legenda-worker]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/site.ru/artisan queue:work --tries=3
    autostart=true
    autorestart=true
    user=master
    numprocs=4
    redirect_stderr=true
    stdout_logfile=/var/log/supervisor/legenda-queue.log

    ; supervisor config file /etc/supervisor/conf.d/quiz-worker.conf

    [program:quiz-worker]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/quiz.site.ru/artisan queue:work --tries=3
    autostart=true
    autorestart=true
    user=master
    numprocs=4
    redirect_stderr=true
    stdout_logfile=/var/log/supervisor/quiz-queue.log

    Но командf: sudo supervisorctl reread
    No config updates to processes

    sudo supervisorctl
    62148e316f250771288306.jpeg
    Вроде работает,
    Но почтовые сообщения, поставленные в очередь laravel не приходят.
  • Как настроить Supervisor на сервере для двух сайтов на Laravel, для отправки почтовых уведомлений с использованием механизма очередей?

    @voland700 Автор вопроса
    Valdemar Smörman, Благодарю за подробное и доступное для понимания изложение.
    Решил удалить и заново переустановить Supervisor на сервер с правильным конфигами.
    Но столкнулся с другой проблемой. После создания воркеров, команда:

    sudo supervisorctl reread

    Выдает ошибку:

    error: <class 'FileNotFoundError'>, [Errno 2] No such file or directory: file: /usr/lib/python3/dist-packages/supervisor/xmlrpc.py


    Требует библиотеку Paython3

    Не подскажите, как поправить. Google по данному вопросу какой-то мусор выдает.
  • После установки SSL сертификата и перехода на HTTPS – ошибка: Сайт выполнил переадресацию слишком много раз. Как исправить?

    @voland700 Автор вопроса
    Не, в моем случае проблема в другом. Не использую CloudFlare. И панель управления хостингом тоже...
  • После установки SSL сертификата и перехода на HTTPS – ошибка: Сайт выполнил переадресацию слишком много раз. Как исправить?

    @voland700 Автор вопроса
    Sorry... Не работает. При размещении данного фрагмента кода в фале хоста - сервер не доступен - 502 ошибка.
  • Как сделать активными пункты меню, вложенных категорий Nested Set?

    @voland700 Автор вопроса
    проверяете, что текущая открытая категория лежит внутри границ родительской и всё

    Честно говоря - не совсем понятно, как это сделать.
    Получаю нужные пункты меню, точнее разделы первого уровня во View Composer. Ну а как лучше определить на какой странице открыт сайт: раздел каталога, страница товара, или другие страницы сайта не имеющие отношения к каталога?
    Понимаю, что для многих, имеющих опыт работы - эта задача проблем не вызывает.
    Но как решить её лучше, оптимально и менее ресурсозатратно не представляю. В документации и сети решений не нашел. Поэтому и хотелось бы получить нужную ин формацию. В идеале конечно было бы посмотреть на фрагменты кода.
  • Как изменить data() свойство компонента VUE полученными с сервера данными?

    @voland700 Автор вопроса
    Sorry...
    Благодарю, за совет. Воспользуюсь. Появился вопрос, буду признателен за ответ. Если не трудно.
    В приведенном Вами примере:
    6183ec09bfc15524561476.jpeg

    this.dataFromAPI = response.data - возвращаемые сервером данные передаются реактивному свойству и они обновляются без перезагрузки. Почему-то у меня не получается.

    Путем генерации событий в дочернем компоненте и их обработке в родительском, я решил проблему получения обновленных данных с сервера в родительском компоненте. Но в моем случае,
    ...
        data() {
            return {
                items: {!! json_encode($data) !!},
            }
        }
    ...
        success: function (response){
            this.items = response;
    	},
    ...

    При успешном получении ответа сервера, this.items = response; не получается изменить реактивное свойство items, и изменить страницу без перезагрузки.
    Хотя, console.log(response); - показывает, что данные приходят с сервера с изменениями.

    Что может быть не так?
    Заранее благодарю за ответ.