• Ошибка в логике многопоточного парсера?

    Как вариант можно запустить несколько экземпляров кода. Да, это больше ресурсов больше "сожрёт", процентов на 50. Но зато реально запускать столько потоков, сколько надо.

    Другой вариант через callback и async всё делать. Там простая проверка завершен код или нет.

    Кидаю код одного из проектов:
    import threading
    import time
    
    
    class ThreadingController:
        _threads = {}
        __thread_max = 1
        __delay_works = []
        __start_time = 0
        __run_delay_works = False
    
        def __init__(self, thread_max: int = 1):
            self.set_max_thread(thread_max=thread_max)
            self.__start_time = time.monotonic()
    
        def add_work(self, coro):
            self.clean_threads()
            thread_id = self.find_free_thread()
    
            if thread_id == 0 and self.__run_delay_works:
                count = len([x for x in self._threads if self._threads[x] is not None])
                if count == 0:
                    self.run_delay_works()
                else:
                    return False
    
            if len(self._threads) >= self.__thread_max and thread_id == 0:
                return False
            if thread_id == 0:
                thread_id = len(self._threads) + 1
            print(self.__thread_max, len(self._threads), thread_id, self._threads)
            threading.Event()
            t1 = threading.Thread(target=coro, args=[thread_id], daemon=True, name=str(thread_id))
            t1.start()
            threading.Event()
            self._threads[thread_id] = t1
            # t1.join()
    
        def add_delay_work(self, coro, *args, **kwargs):
            for work in self.__delay_works:
                if work['coro'] == coro and work['args'] == args and work['kwargs'] == kwargs:
                    return
            self.__delay_works.append({'coro': coro, 'args': args, 'kwargs': kwargs})
    
        def run_delay_works(self):
            from ldplayer import LDPlayer
            from utils import close_process
            from gui import GUI
            GUI.log('')
            if self.__thread_max > 1:
                GUI.log('Запуск отложенных задач')
            LDPlayer().close_all()
            close_process(['adb.exe'])
            close_process()
            for work in self.__delay_works:
                if work['kwargs'].get('title'):
                    GUI.log(work['kwargs'].get('title'))
                try:
                    work['coro'](*work['args'], **work['kwargs'])
                except:
                    pass
            self.__delay_works = []
            self.__start_time = time.monotonic()
            self.__run_delay_works = False
    
        def clean_threads(self):
            for idx in self._threads:
                if isinstance(self._threads[idx], threading.Thread) and not self._threads[idx].is_alive():
                    self._threads[idx].join()
                    self._threads[idx] = None
    
        def find_free_thread(self) -> int:
            delay_run_time = self.__thread_max * 600
            if delay_run_time > 3600:
                delay_run_time = 3600
            if time.monotonic() - self.__start_time > delay_run_time:
                self.__run_delay_works = True
                return 0
            alive_num = 1
            for idx in self._threads:
                if alive_num == idx and self._threads[idx] is not None:
                    alive_num = 0
                if self._threads[idx] is None:
                    alive_num = idx
            print(alive_num, self._threads)
            return alive_num
    
    
    __all__ = ['ThreadingController']

    Суть довольно простая: создаем контроллер (указывая максимум). А потом просто цикле запускаем th.add_work(work, ). Если есть свободный поток, он добавится, если нет, то ничего не делается. Раз в час прекращаются запускаться потоки, чтобы запустить эксклюзивные задачи в один поток (у меня банально - закрытие всех приложений и удаление временных файлов).

    clean_threads - если задача выполнилась, то она будет "освобождена" и удалена из списка
    Написано
  • Как называется нормальный парсер прокси?

    Kristal98, попробуй так
    let items = []; document.querySelectorAll('tr').forEach(item => { items.push(item.querySelectorAll('td')[0]?.innerHTML + ':' + item.querySelectorAll('td')[1]?.innerHTML);}); items
  • Почему не все emoji сохраняются?

    + ещё в базе должны быть таблицы `utf8mb4`
  • Откуда круглогодично можно спарсивать уникальные авторские поздравления с праздниками?

    Я делал как то с использованием чужой нейросетки, наподобии ChatGPT пару лет назад - пишем, кого поздравляем скрипт дописывал остальное в запросы и получаем уникальное поздравление.
  • Аргумент proxies в requests не меняет ip адрес?

    Может поможет, у меня проверка ip вот так делается:

    def get_my_ip_with_proxy(proxy):
        proxies = {
            "http": proxy,
            "https": proxy,
        }
        s = requests.Session()
        ext_ip = s.get('http://ifconfig.me/ip', proxies=proxies, timeout=TIMEOUT, headers=headers())
        return ext_ip
  • Пытаюсь парсить товары с магазина ДНС, но почему получаю всё время array(0) PHP?

    Rab1d, Вообще нет. Парсил, парсю и буду парсить на любом удобном языке. ДНС парсил на и php и python, там не сильно отличается. Но сейчас остановился на связке - парсинг на python, разбор парсинга на php. Тут просто принцип парсинга динамических сайтов не сильно отличается.
  • Можно ли как то оптимизировать запросы в контроллере?

    Ну тут можно немного оптимизировать так:
    Вместо Order::where.. сделать
    $ordersAll = Order::whereIn('status',[0,2])->get();
    $orders = $ordersAll->where('status', 0)->get(); // либо через фильтр
            $ordersWin = $ordersAll->where('status', 2)->get();
    
    // Orders
            $ordersAllWin = $ordersAll->where('status', 2)->get(); // дубль запроса

    Но это просто уберет лишние запросы к бд. Имеет смысл при более сложных выборках, в данном случае просто для примера показано.

    А вот тут можно можно и подумать. Вместо данных запросов
    $performer = $user->where('role_id', 1)->count();
    $customer = $user->where('role_id', 2)->count();

    можно использовать агрегатные функции:
    // пример из документации
    $users = DB::table('users')
                 ->select(DB::raw('count(*) as user_count, status'))
                 ->where('status', '<>', 1)
                 ->groupBy('status')
                 ->get();
  • С какого сайта парсить проскси?

    Я создавал инструмент для загрузки и проверки прокси.
    Работает с докер-образами. Там же собираются списки прокси из разных источников.
  • Как работать в Vite + Laravel без JS-фреймворков?

    Vite работает быстрее, да. Он современный, да. Но он пи.. какой глючный. Это не понимает, то не умеет, ошибки выдает неочем. Банально работа с SASS, с которым он не умеет работать. Когда он ругался на стандартные функции сасс, что это неизвестные фунции (вроде calc, но сейчас точно не помню). Нашел тогда решение использовать форк sass. И куча других. Вот и вопрос, а нафига использовать крутой глючный инструмент, если mix работал отлично. Да сборка у него происходила медленнее, но когда я поставил кучу плагинов, без которых vite не хотел работать, то скорость упала. А ведь проект был простой - css фреймворк и кучка скриптов на native js. Единственный плюс - изменение страницы на лету при измении стилей.

    Сразу вспонимается, что у нас в деревне чел купил спорткар, а ездить не может, так как у нас асфальтирована только одна улица, да и то она с ямами. Вот и тут также.
  • Локальный и удаленный пользователь одновременно?

    RDP Wrapper трубует версию Pro. И он постоянно слетал у меня. Но я использовал компьютер для вывода видео на ТВ. После доглих мучений, я просто в плеере задал использовать определенную звуковую карту, а открытие запоминалось. Так что просто я подходил к компу, запускал плей лист и всё. Стандарные звуки выводились через динамики или наушники
  • Как сделать несколько циклов?

    тут надо использовать очереди и асинхронные запросы. То есть присылается ссылка, ссылка отправляется на парсинг с записью в бд (кто и что отправил). А когда спарсилось, что из базы берем кому отправить результат.

    Вот пример как это делается
  • Как сделать парсинг фотографий из телеграмм чата, Python?

    Если используется telephon, то там есть стандарный метод сохранения:
    await client.download_media(msg, './media/', progress_callback=callback)

    Передается сообщение, куда сохранять и какая функция обработатывает вывод (например, вывод процентов в терминале).

    Код пример. Я просто скачиваю все картинки из чата и записываю из на S3 и данные в бд
  • Почему simple_html_dom.php один сайт парсит, а другой нет?

    А у Леруа скорее всего защита стоит, так как грузится почти пустая страница со скриптом на js.
  • Как парсить динамические сайты типа dns-shop?

    Некоторые сайты можно парсить через scrapy_splash. Да ДНС не получиться парсить через него, но некоторые сайты на JS он может спарсить
  • Как спарсить ozon средствами PHP?

    Единственный минус - это хром. У меня может висеть до 800 потоков от хрома, так как он любит оставлять кучу процессов в работе при закрытии браузера и драйвера. Да и подбор кучи параметров, чтобы он корректно работал и отслеживалось закрытие. Но это проблемы на слабых машинах, на более мощных он работает стабильнее. Сейчас смотрю в сторону Docker, чтобы запускать хром изолированно, а то он везьде лезет и может занимать до 8Гигов места на диске
  • Как спарсить ozon средствами PHP?

    Мне нужны были json файлы с определенного сайта. Там тоже было закрыто. При чем открываешь в браузере - json открывает нормально. Так что написал небольшой скрипт на python, который открывает через селениум в виртульном окне браузер грузит страницу и результат кладет в базу.. Я же уже на php работаю с этой базой.

    Изначально скрипт работал на самом дешевом vds, но там было место мало. Сейчас крутится на 1x2Gh, 500M, 10G, который стоит 150-300 рублей в месяц
  • Миграция фото из Picasa в Synology Photostation?

    Ichi
    @Ichi Автор вопроса
    Я создал одну отдельную папку, и просто туда кидаю. PhotoStation видит изменения и индексирует их (создает превью у видео и пытается распознать лица).

    Права уже можно задать в PhotoStations.

    Другое дело, что у меня он довольно слабый и делает это очень медленно. Ну и не нравится, что сама скорость очень небольшая, если просматриваешь через приложение на смартфоне - долго грузятся альбомы и списки файлов. DMS7 обновления для моего наса нет, он слишком старый. Думаю прикупить бу nas поновее, чисто для фото и установить туда ssd.