Scrapy: Предотвращение сохранения данных и загрязнения между запросами в ItemLoader

Вопрос или проблема

Я использую Scrapy для обхода страниц и извлечения данных в файл JSON, но сталкиваюсь с проблемами согласованности данных. В частности, некоторые поля, похоже, сохраняют или дублируют данные из предыдущих ответов, что приводит к неверным значениям полей в выводе.

Проблема

Файл JSON содержит правильное количество элементов, соответствующее количеству URL в файле .txt, и все URL уникальны. Тем не менее, некоторые поля в JSON-выводе неверны и выглядят так, как будто данные из одного запроса сохраняются в другом элементе.

Я проверил, что:

  • Для каждого ответа создается новый экземпляр ItemLoader.
  • Я использовал условные операторы if-else для добавления “NO DATA FOUND”, если данные не найдены по указанному XPath.

Вот пример двух последовательных строк с разными URL, имеющими одинаковые данные:
Строка 20:

Строка 21:

Разумным подходом было бы использовать Spider вместо CrawlSpider. Тем не менее, я намерен добавить дополнительную сложность в код после того, как будет решена эта начальная версия.

Код

Резюме основной структуры

  1. Импорт и Определения:
  • Импорт ключевых модулей Scrapy (Item, Field, CrawlSpider, Rule, ItemLoader и LinkExtractor).
  1. Класс элемента (Claselicitacion):
  • Определяет поля: objeto_contrato, presupuesto_base и url.
  1. Класс паука (LicitacionCrawlSpider):
  • Наследуется от CrawlSpider.
  • Считывает URL-адреса из текстового файла (1_DeepLinks.txt) для инициализации start_urls.
  • Определяет правила для извлечения конкретных ссылок и назначения их на обратный вызов parse_item.
  1. Метод обратного вызова (parse_item):
  • Создает новый экземпляр ItemLoader для каждого ответа.
  • Извлекает данные для каждого поля с помощью XPath.
  • Добавляет URL ответа.
  • Возвращает загруженный элемент (item.load_item()).
  • Вот основная структура моего кода:

Код

from scrapy.item import Item, Field
from scrapy.spiders import CrawlSpider, Rule
from scrapy.loader import ItemLoader
from scrapy.linkextractors import LinkExtractor

class Claselicitacion(Item):
    objeto_contrato = Field()
    presupuesto_base = Field()
    url = Field()

class LicitacionCrawlSpider(CrawlSpider):
    name="licitacion_crawl"
    custom_settings = {
        "REQUEST_FINGERPRINTER_IMPLEMENTATION": "2.7",
        'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
        'FEED_EXPORT_ENCODING': 'utf-8',
        'FEEDS': {
            '2_ProjectFinder.json': {
                'format': 'json',
                'encoding': 'utf-8',
            },
        }
    }

    with open('1_DeepLinks.txt', 'r') as file:
        start_urls = [line.strip() for line in file if line.strip()]

    rules = (
        Rule(
            LinkExtractor(allow=r'deeplink%3Adetalle_licitacion'),
            callback='parse_item',
            follow=False,
        ),
    )

    def parse_item(self, response):
        item = ItemLoader(item=Claselicitacion(), response=response)

        if response.xpath('//li[@id="fila4_columna2"]'):
            item.add_xpath('objeto_contrato', '//li[@id="fila4_columna2"]//span[@class="outputText"]/text()')
        else:
            item.add_value('objeto_contrato', 'NO DATA FOUND')

        if response.xpath('//li[@id="fila5_columna2"]'):
            item.add_xpath('presupuesto_base', '//li[@id="fila5_columna2"]//span[@class="outputText"]/text()')
        else:
            item.add_value('presupuesto_base', 'NO DATA FOUND')

        item.add_value('url', response.url)

        yield item.load_item()

Вопросы

  1. Сохраняет ли ItemLoader значения из предыдущих запросов? Как я могу обеспечить полное разделение данных каждого ответа?
  2. Правильно ли я использую ItemLoader? Есть ли лучший способ справиться с этой настройкой?
  3. Может ли асинхронная обработка Scrapy вызвать путаницу с данными? Как я могу заставить каждый запрос обрабатываться независимо?
  4. Является ли item.add_xpath + yield item.load_item() надежным подходом? Поскольку поля URL последовательно корректны, не может ли быть проблема с моим использованием add_xpath?

Что я пробовал

  • Добавление условий if-else для установки “NO DATA FOUND” в качестве заполнитель, когда данные не найдены.
  • Убедившись, что ItemLoader создается заново для каждого ответа.
  • Подтверждение, что URL-адреса в моем исходном файле правильные.

Ожидаемое поведение

Каждый элемент в выводе должен быть независимым и содержать только данные, относящиеся к его соответствующему URL. Если данные поля недоступны, оно должно явно показывать “NO DATA FOUND”.

Любые идеи или предложения по улучшению моего использования ItemLoader или изоляции состояний запросов в Scrapy будут очень полезны. Заранее спасибо!

Ответ или решение

Многие разработчики Scrapy сталкиваются с проблемами, связанными с сохранением данных между запросами и перекрестным загрязнением результатов при использовании ItemLoader. В данном ответе мы рассмотрим возможные причины ваших проблем и предоставим решения, которые помогут избежать некорректного поведения вашего скрапера.

Проблема: Персистентность данных и загрязнение между запросами

Если данные из одного запроса сохраняются в результате другого, это может происходить по нескольким причинам:

  1. Неправильная инициализация ItemLoader. Ваша предпосылка о том, что вы создаете новый экземпляр ItemLoader для каждого ответа, правильна. Однако стоит дополнительно убедиться, что нет мест, где происходит повторное использование одного экземпляра.

  2. Асинхронная обработка запросов. Scrapy активно использует асинхронный подход, что может привести к ситуации, где данные обрабатываются параллельно, что создает возможность конфликтов и несоответствий.

Ответы на ваши вопросы

  1. Сохраняет ли ItemLoader значения из предыдущих запросов?

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

    • Использование ItemLoader выглядит правильно, но убедитесь, что вы правильно обрабатываете каждый шаг. В качестве оптимизации вы можете рассмотреть использование Compose метода для подключения набора полей в одну цепочку, что может повысить читаемость кода.
  3. Может ли асинхронная обработка Scrapy вызвать смешивание данных?

    • Да, асинхронные запросы могут повредить целостности данных, если используются глобальные состояния. Убедитесь, что у вас нет статических переменных или общих свойств, которые могут использоваться разными экземплярами вашего скрапера.
  4. Насколько надежно использование item.add_xpath и yield item.load_item()?

    • Данный подход является стандартным и надежным. Однако вам стоит проверить XPath выражения на наличие потенциальных ошибок. Можно также использовать add_value для логирования содержимого, если результаты подозрительные. Это поможет уточнить, действительно ли XPath возвращает данные так, как вы ожидаете.

Рекомендации и улучшения

  1. Ревизия XPath выражений:
    Убедитесь, что ваши XPath выражения правильные и обращаются к уникальным элементам DOM страницы. Можно тестировать XPath выражения с помощью инструментов, таких как Chrome DevTools или XPath Tester.

  2. Логирование отладочной информации:
    Включите логирование для проверки данных, возвращаемых предыдущими запросами, например, можно добавить временные метки или уникальные идентификаторы для каждого запроса.

  3. Обработка исключений:
    Добавьте обработку ошибок и исключений, чтобы гарантировать, что ваш скрапер не будет завершать работу в случае непредвиденных обстоятельств.

  4. Масштабируемость:
    Если вы планируете усложнить код в будущем, возможно, имеет смысл перейти на использование Spider вместо CrawlSpider, чтобы обеспечить лучшую предсказуемость и контроль.

  5. Параметры конфигурации:
    Иногда настройки вашего проекта (например, асинхронные ограничения, таймауты и т.д.) могут на это влиять, перепроверьте их.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...