Ответы пользователя по тегу Парсинг
  • Как запараллелить выполнение ф-ций в асинхронном парсере?

    @deliro
    1. Создать очередь (asyncio.Queue)
    2. Парсер пишет в очередь, писарь csv читает очередь и пишет в неё.
    3. Парсер и писарь должны запускаться одновременно, то есть, типа такого

    q = asyncio.Queue()  # с maxsize можно поиграться, в данном случае отставание писаря от парсера может быть не более чем на один элемент
    await asyncio.gather(get_pages_data(q), csv_writer(q))

    4. Парсеров, кажется, надо сделать больше одного. То есть, появляется второй asyncio.Queue (назовём его work_queue), куда падают lines из файла, эту очередь слушают N воркеров (скажем, 5 штук), получают элемент, работают с ним, затем пишут в result_queue, который слушает писарь csv и записывает результат в файлик

    Псевдокод будет выглядеть так:

    async def file_reader(work_q, n_parsers):
        with open('all_links_1.txt', 'r') as f:
            lines = [line.strip() for line in f.readlines()]
        for line in lines:
            await work_q.put(line)
        for _ in range(n_parsers):  # говорим парсерам, что работы больше нет
            await work_q.put(None)
    
    async def parser(work_q, results_q):
        while True:
            line = await work_q.get()
            if line is None:
                return
            result = ... магия с походом в http ...
            await results_q.put(result)
    
    async def writer(results_q):
        with open('companys.csv', 'w', newline='') as file:  # возможно, открывать файл имеет смысл при каждом получении элемента и закрывать после записи, так файл всегда будет "целым", но процесс записи будет дольше
            writer = csv.writer(file, delimiter=',')
            while True:
                result = await results_q.get()
                if result is None:
                    return
                writer.writerow([result['name'], result['phone'], result['edrpou']])
    
    
    async def main():
        work_queue = asyncio.Queue()
        results_queue = asyncio.Queue(10)  # парсер не должен ждать, пока писарь запишет в файл (хард может быть занят), поэтому небольшой буфер
        n_parsers = 5
        tasks = []
        parsers = []
        reader_task = asyncio.create_task(file_reader(work_queue, n_parsers))
        tasks.append(tasks)
        for _ in range(n_parsers):
            parser_task = asyncio.create_task(parser(work_queue, results_queue))
            tasks.append(parser_task)
            parsers.append(parser_task)
        tasks.append(asyncio.create_task(writer(results_queue)))
        await asyncio.gather(*parsers)  # ждём все парсеры
        await results_queue.put(None)  # говорим писарю, что больше ничего не будет
        await asyncio.gather(*tasks)  # дожидаемся все остальные таски (вернее, будет только одна — writer)


    Однако нужно понимать, что порядок результатов при таком подходе не будет гарантированным или хоть сколько-то стабильным. Поэтому, если порядок важен, стоит писать в файл какую-то промежуточную структуру (пусть тот же csv, но с доп столбцом link) и под конец всех работ вычитывать её, сортировать и складывать уже в нужном порядке
    Ответ написан
  • Как узнать сколько времени займет поиск значения в тхт-списке?

    @deliro
    Как понять сколько времени будет занимать поиск заданного значения и каким способом эффективнее парсить файл?

    Что известно о файле кроме того, что он есть?

    Если значения в случайном порядке, то сложность будет всегда O(N) в худшем случае

    Если в нём значения отсортированы по какому-то признаку и есть явный разделитель (перевод каретки, например), то можно сделать аналог бинарного поиска (за O(logN)). Ну то есть, тыкаем в середину файла (seek(file_size_in_bytes / 2)), ищем вперёд ближайший разделитель (например, перевод каретки), читаем до следующего разделителя (получается строка), сравниваем ну и дальше как обычно. Но нужно учесть, что если это HDD, то движения головки диска не бесплатные и рандомный seek будет медленней последовательного, так что сравнивать "количество строк в секунду" в лоб не выйдет.

    Если ОЗУ позволяет, то можно вычитать весь файл туда и закинуть в структуру, которая больше подходит. Будь то дерево, сортированный массив или хэш-таблица. Если требуется только ответ на вопрос "есть?", то хэш-таблица будет самым производительным вариантом со сложностью O(1)

    Если ОЗУ не позволяет и большинство запросов заведомо будут "мимо", можно сделать фильтр Блума и сканировать файл только если он "возможно есть" и никогда не сканировать, если его "точно нет" (собственно, эти ответы и даёт фильтр Блума)

    Если ОЗУ не позволяет, но файл можно менять, то можно отсортировать его единоразово и дальше бинарный поиск

    Да можно даже содержимое файла в sqlite залить и решить все проблемы, пусть драйвер сам разбирается, что хранить в ОЗУ
    Ответ написан
    Комментировать
  • Чем веб-парсеры отличаются от реальных пользователей?

    @deliro
    1. Количеством запросов
    2. Нехаотичностью запросов
    3. Отсутствием рантайма для JS
    4. Либо присутсвием рантайма, но отсутствием натурального движения мышью
    5. Списком IP из ренжа AWS/DO/Vultr и других хостингов. Пользователи не сидят с таких IP адресов или делают это очень редко (купили и настроили там VPN)
    6. Резкими всплесками активности из одного сегмента сети (следствие 1 и 5 пунктов)
    7. Капча
    8. Что угодно ещё, хоть fingerprintjs

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

    @deliro
    Парсинг — это чуть ли не первое в списке того, ради чего стоит использовать асинхронность. Чем больше IO операций — тем больше преимуществ у асинхронного подхода перед тредпулом. Если при парсинге необходимо выполнять CPU-bound операции (разбор XML/HTML и прочее) — это выносится в тредпул (для питона — процеспул) и через асинхронные биндинги (например, в питоне это run_in_executor) отдаётся на откуп туда, главный же поток при этом не блокируется.

    Пример на коленке, который парсит граф ссылок с википедии, с процесспулом, lxml и прочими ништяками: тык
    Ответ написан
    4 комментария
  • Почему парсер банит сервер?

    @deliro
    Варианты:

    1. IP на самом деле не меняется
    2. IP меняется, но не в парсере
    3. Тебя забанили по другим признакам
    4. Твой код со временем перестаёт работать

    Коль лучшей инфы ты не приготовил, это самое объёмное, что можно сказать по твоему неуклюжему вопросу.
    Ответ написан
    Комментировать
  • Как справиться с ошибкой 'utf-8' codec can't decode byte 0xc0 in position 199: invalid start byte?

    @deliro
    Раскодировать в правильной кодировке
    Ответ написан
    Комментировать
  • TypeError: object of type 'NoneType' has no len()?

    @deliro
    def get_html(url):
        r = requests.get(url)


    Тут ошибка. Ищи

    P.S. Удобней формировать урлы через модуль urllib.parse, а не вот как ты
    Ответ написан
    1 комментарий
  • Как организовать парсинг товаров ИМ на python?

    @deliro
    Парсить по запросу? Вздор. Ну разве что юзать Celery, отправлять юзера на страницу, где он будет ждать результата. Но результаты парсинга в любом случае сохранять в БД.
    Ответ написан
    Комментировать
  • Как защититься от парсельщиков?

    @deliro
    Нет
    Ответ написан
    Комментировать
  • Какие есть библиотеки для парсинга с возможностью выполнения js?

    @deliro
    You think you do, but you don't Тебе это не нужно.

    Всё, что делает JS, можно сделать без него. Из важного — это только выполнение запросов, которые можно помониторить во вкладке Network и, собственно, самом JSе.

    На селениуме есть смысл только тестировать вёрстку и писать приёмочные тесты.
    Ответ написан
    1 комментарий
  • Поиск лекарств в аптеках?

    @deliro
    Реализуется хоть на чем. Иди читать про парсеры.
    Ответ написан
    Комментировать
  • 'int' object is not subscriptable (парсинг json)?

    @deliro
    1. Переопределён dict
    2. Неправильные отступы
    3. У словаря есть более эффективный метод .items()

    Реши сначала эти вопросы, логика правильная.
    Ответ написан
    2 комментария
  • Как правильно запарсить сайт на python?

    @deliro
    scrapy в руки и вперёд. Мануал тебе почитать на ночь?
    Ответ написан
    1 комментарий
  • Возможно ли написать универсальный парсер (для любого ресурса) под конкретную задачу на Python?

    @deliro
    Обучай нейросеть. Больше никак.
    Ответ написан
    Комментировать
  • Как парсить музыку с зайцев нет?

    @deliro
    Эмм. Там же ничего сложного.
    Кидаешь запрос:
    http://zaycev.net/search.html?query_search=30+seconds+to+mars

    Тебе дают ответ. Там есть div с классом "musicset-track-list__items". В нём перебираешь все дивы-потомки. У каждого дива-потомка есть параметр data-url - ссылка на json в котором лежит прямая ссылка на mp3 (там немного хвост обрезать):
    {"url":"http://cdndl.zaycev.net/1021/790315/30_seconds_to_mars_-_attack.mp3?dlKind=play&format=json"}
    Ответ написан
    2 комментария
  • Как спарсить raw html страницы?

    @deliro
    Это, как раз, обработанные данные, а raw тебе приходит с urlib.
    Используй selenium (окно браузера можно скрыть, используя PhantomJS).
    Ответ написан
    2 комментария
  • Как спарсить профили вк по критериям из глобального поиска?

    @deliro
    Ответ написан
    Комментировать
  • Как спарсить номер телефона?

    @deliro
    selenium. Если номер, конечно, не картинкой.
    Ответ написан
    Комментировать
  • Как парсить теги?

    @deliro
    Тысяча тегов в памяти занимают около 10кб. Можешь держать в памяти.
    Ответ написан
    Комментировать