Вопрос или проблема
Я использую Scrapy для обхода страниц и извлечения данных в файл JSON, но сталкиваюсь с проблемами согласованности данных. В частности, некоторые поля, похоже, сохраняют или дублируют данные из предыдущих ответов, что приводит к неверным значениям полей в выводе.
Проблема
Файл JSON содержит правильное количество элементов, соответствующее количеству URL в файле .txt
, и все URL уникальны. Тем не менее, некоторые поля в JSON-выводе неверны и выглядят так, как будто данные из одного запроса сохраняются в другом элементе.
Я проверил, что:
- Для каждого ответа создается новый экземпляр
ItemLoader
. - Я использовал условные операторы if-else для добавления “NO DATA FOUND”, если данные не найдены по указанному XPath.
Вот пример двух последовательных строк с разными URL, имеющими одинаковые данные:
Строка 20:
- Objeto del contrato: Ejecución proyecto “Abastecimiento caseríos […]”
- Presupuesto base: 247,576.09 €
- URL: Ссылка на сайт государственной контрактации
Строка 21:
- Objeto del contrato: Ejecución proyecto “Abastecimiento caseríos […]”
- Presupuesto base: 247,576.09 €
- URL: Ссылка на сайт государственной контрактации
Разумным подходом было бы использовать Spider вместо CrawlSpider. Тем не менее, я намерен добавить дополнительную сложность в код после того, как будет решена эта начальная версия.
Код
Резюме основной структуры
- Импорт и Определения:
- Импорт ключевых модулей Scrapy (Item, Field, CrawlSpider, Rule, ItemLoader и LinkExtractor).
- Класс элемента (Claselicitacion):
- Определяет поля: objeto_contrato, presupuesto_base и url.
- Класс паука (LicitacionCrawlSpider):
- Наследуется от CrawlSpider.
- Считывает URL-адреса из текстового файла (1_DeepLinks.txt) для инициализации start_urls.
- Определяет правила для извлечения конкретных ссылок и назначения их на обратный вызов parse_item.
- Метод обратного вызова (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()
Вопросы
- Сохраняет ли
ItemLoader
значения из предыдущих запросов? Как я могу обеспечить полное разделение данных каждого ответа? - Правильно ли я использую
ItemLoader
? Есть ли лучший способ справиться с этой настройкой? - Может ли асинхронная обработка Scrapy вызвать путаницу с данными? Как я могу заставить каждый запрос обрабатываться независимо?
- Является ли
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
. В данном ответе мы рассмотрим возможные причины ваших проблем и предоставим решения, которые помогут избежать некорректного поведения вашего скрапера.
Проблема: Персистентность данных и загрязнение между запросами
Если данные из одного запроса сохраняются в результате другого, это может происходить по нескольким причинам:
-
Неправильная инициализация
ItemLoader
. Ваша предпосылка о том, что вы создаете новый экземплярItemLoader
для каждого ответа, правильна. Однако стоит дополнительно убедиться, что нет мест, где происходит повторное использование одного экземпляра. -
Асинхронная обработка запросов. Scrapy активно использует асинхронный подход, что может привести к ситуации, где данные обрабатываются параллельно, что создает возможность конфликтов и несоответствий.
Ответы на ваши вопросы
-
Сохраняет ли
ItemLoader
значения из предыдущих запросов?- Инстанс
ItemLoader
должен быть независимым и не сохранять значения между разными запросами, если он создан каждый раз заново. Проверьте, что у вас нет глобальных переменных или статических данных, которые могут быть использованы несколькими экземплярамиItemLoader
.
- Инстанс
-
Использую ли я
ItemLoader
корректно?- Использование
ItemLoader
выглядит правильно, но убедитесь, что вы правильно обрабатываете каждый шаг. В качестве оптимизации вы можете рассмотреть использованиеCompose
метода для подключения набора полей в одну цепочку, что может повысить читаемость кода.
- Использование
-
Может ли асинхронная обработка Scrapy вызвать смешивание данных?
- Да, асинхронные запросы могут повредить целостности данных, если используются глобальные состояния. Убедитесь, что у вас нет статических переменных или общих свойств, которые могут использоваться разными экземплярами вашего скрапера.
-
Насколько надежно использование
item.add_xpath
иyield item.load_item()
?- Данный подход является стандартным и надежным. Однако вам стоит проверить XPath выражения на наличие потенциальных ошибок. Можно также использовать
add_value
для логирования содержимого, если результаты подозрительные. Это поможет уточнить, действительно ли XPath возвращает данные так, как вы ожидаете.
- Данный подход является стандартным и надежным. Однако вам стоит проверить XPath выражения на наличие потенциальных ошибок. Можно также использовать
Рекомендации и улучшения
-
Ревизия XPath выражений:
Убедитесь, что ваши XPath выражения правильные и обращаются к уникальным элементам DOM страницы. Можно тестировать XPath выражения с помощью инструментов, таких как Chrome DevTools или XPath Tester. -
Логирование отладочной информации:
Включите логирование для проверки данных, возвращаемых предыдущими запросами, например, можно добавить временные метки или уникальные идентификаторы для каждого запроса. -
Обработка исключений:
Добавьте обработку ошибок и исключений, чтобы гарантировать, что ваш скрапер не будет завершать работу в случае непредвиденных обстоятельств. -
Масштабируемость:
Если вы планируете усложнить код в будущем, возможно, имеет смысл перейти на использованиеSpider
вместоCrawlSpider
, чтобы обеспечить лучшую предсказуемость и контроль. -
Параметры конфигурации:
Иногда настройки вашего проекта (например, асинхронные ограничения, таймауты и т.д.) могут на это влиять, перепроверьте их.
Заключение
Ваш опыт с Scrapy подчеркивает важность глубокого понимания механизма работы фреймворка. Несмотря на то, что вы уже сделали множество правильных шагов, акцент на правильной структуре, использовании логирования и оценке вашего подхода к асинхронной обработке данных поможет значительно улучшить надежность и актуальность данных, которые вы получаете. Настоятельно рекомендую при исправлении вашего кода проделывать тестирование на небольшом наборе данных, чтобы убедиться в корректности изменений, прежде чем разворачивать их на больших выборках.