Scrapy - Загрузчики предметов

Описание

Загрузчики предметов предоставляют удобный способ заполнения предметов, взятых с веб-сайтов.

Объявление загрузчиков предметов

Объявление Item Loaders похоже на Items.

Например -

from scrapy.loader import ItemLoader 
from scrapy.loader.processors import TakeFirst, MapCompose, Join  

class DemoLoader(ItemLoader):  
   default_output_processor = TakeFirst()  
   title_in = MapCompose(unicode.title) 
   title_out = Join()  
   size_in = MapCompose(unicode.strip)  
   # you can continue scraping here

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

В ItemLoader.default_input_processor и ItemLoader.default_output_processor атрибуты используются для объявления процессоров ввода / вывода по умолчанию.

Использование загрузчиков элементов для заполнения элементов

Чтобы использовать Item Loader, сначала создайте экземпляр с dict-подобным объектом или без объекта, где элемент использует класс Item, указанный в ItemLoader.default_item_class атрибут.

  • Вы можете использовать селекторы для сбора значений в загрузчике элементов.

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

Следующий код демонстрирует, как элементы заполняются с помощью загрузчиков элементов.

from scrapy.loader import ItemLoader 
from demoproject.items import Demo  

def parse(self, response): 
   l = ItemLoader(item = Product(), response = response)
   l.add_xpath("title", "//div[@class = 'product_title']")
   l.add_xpath("title", "//div[@class = 'product_name']")
   l.add_xpath("desc", "//div[@class = 'desc']")
   l.add_css("size", "div#size]")
   l.add_value("last_updated", "yesterday")
   return l.load_item()

Как показано выше, есть два разных XPath, из которых title поле извлекается с помощью add_xpath() метод -

1. //div[@class = "product_title"] 
2. //div[@class = "product_name"]

После этого аналогичный запрос используется для descполе. Данные о размере извлекаются с использованиемadd_css() метод и last_updated заполняется значением "вчера" с использованием add_value() метод.

Как только все данные будут собраны, позвоните ItemLoader.load_item() метод, который возвращает элементы, заполненные данными, извлеченными с помощью add_xpath(), add_css() и add_value() методы.

Процессоры ввода и вывода

Каждое поле загрузчика элементов содержит один процессор ввода и один процессор вывода.

  • Когда данные извлекаются, процессор ввода обрабатывает их, и его результат сохраняется в ItemLoader.

  • Затем, после сбора данных, вызовите метод ItemLoader.load_item (), чтобы получить заполненный объект Item.

  • Наконец, элементу можно присвоить результат процессора вывода.

Следующий код демонстрирует, как вызвать процессоры ввода и вывода для определенного поля.

l = ItemLoader(Product(), some_selector)
l.add_xpath("title", xpath1) # [1]
l.add_xpath("title", xpath2) # [2]
l.add_css("title", css)      # [3]
l.add_value("title", "demo") # [4]
return l.load_item()         # [5]

Line 1 - Данные title извлекаются из xpath1 и передаются через процессор ввода, а их результат собирается и сохраняется в ItemLoader.

Line 2 - Точно так же заголовок извлекается из xpath2 и передается через тот же процессор ввода, а его результат добавляется к данным, собранным для [1].

Line 3 - Заголовок извлекается из селектора CSS и передается через тот же процессор ввода, а результат добавляется к данным, собранным для [1] и [2].

Line 4 - Затем присваивается значение «демо» и передается через процессоры ввода.

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

Объявление процессоров ввода и вывода

Процессоры ввода и вывода объявлены в определении ItemLoader. Помимо этого, они также могут быть указаны вItem Field метаданные.

Например -

import scrapy 
from scrapy.loader.processors import Join, MapCompose, TakeFirst 
from w3lib.html import remove_tags  

def filter_size(value): 
   if value.isdigit(): 
      return value  

class Item(scrapy.Item): 
   name = scrapy.Field( 
      input_processor = MapCompose(remove_tags), 
      output_processor = Join(), 
   )
   size = scrapy.Field( 
      input_processor = MapCompose(remove_tags, filter_price), 
      output_processor = TakeFirst(), 
   ) 

>>> from scrapy.loader import ItemLoader 
>>> il = ItemLoader(item = Product()) 
>>> il.add_value('title', [u'Hello', u'<strong>world</strong>']) 
>>> il.add_value('size', [u'<span>100 kg</span>']) 
>>> il.load_item()

Он отображает вывод как -

{'title': u'Hello world', 'size': u'100 kg'}

Контекст загрузчика предметов

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

Например, предположим, что у вас есть функция parse_length -

def parse_length(text, loader_context): 
   unit = loader_context.get('unit', 'cm') 
   
   # You can write parsing code of length here  
   return parsed_length

Получая аргументы loader_context, он сообщает загрузчику элементов, что он может получить контекст загрузчика элементов. Есть несколько способов изменить значение контекста загрузчика предметов:

  • Изменить текущий активный контекст загрузчика предметов -

loader = ItemLoader (product)
loader.context ["unit"] = "mm"
  • При создании экземпляра загрузчика предметов -

loader = ItemLoader(product, unit = "mm")
  • В объявлении загрузчика элементов для процессоров ввода / вывода, которые создаются в контексте загрузчика элементов -

class ProductLoader(ItemLoader):
   length_out = MapCompose(parse_length, unit = "mm")

Объекты ItemLoader

Это объект, который возвращает загрузчик нового элемента для заполнения данного элемента. Он имеет следующий класс -

class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)

В следующей таблице показаны параметры объектов ItemLoader -

Старший Нет Параметр и описание
1

item

Это элемент, который нужно заполнить путем вызова add_xpath (), add_css () или add_value ().

2

selector

Он используется для извлечения данных с веб-сайтов.

3

response

Он используется для создания селектора с использованием default_selector_class.

В следующей таблице показаны методы объектов ItemLoader -

Старший Нет Метод и описание пример
1

get_value(value, *processors, **kwargs)

По заданным аргументам процессора и ключевого слова значение обрабатывается методом get_value ().

>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'title: demoweb', TakeFirst(), 
unicode.upper, re = 'title: (.+)')
'DEMOWEB`
2

add_value(field_name, value, *processors, **kwargs)

Он обрабатывает значение и добавляет его в поле, в которое оно сначала передается через get_value, передавая аргументы процессорам и ключевым словам перед прохождением через процессор ввода поля.

loader.add_value('title', u'DVD')
loader.add_value('colors', [u'black', u'white'])
loader.add_value('length', u'80')
loader.add_value('price', u'2500')
3

replace_value(field_name, value, *processors, **kwargs)

Он заменяет собранные данные новым значением.

loader.replace_value('title', u'DVD')
loader.replace_value('colors', [u'black', 
u'white'])
loader.replace_value('length', u'80')
loader.replace_value('price', u'2500')
4

get_xpath(xpath, *processors, **kwargs)

Он используется для извлечения строк Unicode путем предоставления аргументов процессорам и ключевым словам путем получения XPath .

# HTML code: <div class = "item-name">DVD</div>
loader.get_xpath("//div[@class = 
'item-name']")

# HTML code: <div id = "length">the length is 
45cm</div>
loader.get_xpath("//div[@id = 'length']", TakeFirst(), 
re = "the length is (.*)")
5

add_xpath(field_name, xpath, *processors, **kwargs)

Он получает XPath в поле, которое извлекает строки Unicode.

# HTML code: <div class = "item-name">DVD</div>
loader.add_xpath('name', '//div
[@class = "item-name"]')

# HTML code: <div id = "length">the length is 
45cm</div>
loader.add_xpath('length', '//div[@id = "length"]',
 re = 'the length is (.*)')
6

replace_xpath(field_name, xpath, *processors, **kwargs)

Он заменяет собранные данные с помощью XPath с сайтов.

# HTML code: <div class = "item-name">DVD</div>
loader.replace_xpath('name', '
//div[@class = "item-name"]')

# HTML code: <div id = "length">the length is
 45cm</div>
loader.replace_xpath('length', '
//div[@id = "length"]', re = 'the length is (.*)')
7

get_css(css, *processors, **kwargs)

Он получает селектор CSS, используемый для извлечения строк Unicode.

loader.get_css("div.item-name")
loader.get_css("div#length", TakeFirst(), 
re = "the length is (.*)")
8

add_css(field_name, css, *processors, **kwargs)

Он похож на метод add_value () с той разницей, что он добавляет в поле селектор CSS.

loader.add_css('name', 'div.item-name')
loader.add_css('length', 'div#length', 
re = 'the length is (.*)')
9

replace_css(field_name, css, *processors, **kwargs)

Он заменяет извлеченные данные с помощью селектора CSS.

loader.replace_css('name', 'div.item-name')
loader.replace_css('length', 'div#length',
 re = 'the length is (.*)')
10

load_item()

Когда данные собраны, этот метод заполняет элемент собранными данными и возвращает их.

def parse(self, response):
l = ItemLoader(item = Product(), 
response = response)
l.add_xpath('title', '//
div[@class = "product_title"]')
loader.load_item()
11

nested_xpath(xpath)

Он используется для создания вложенных загрузчиков с помощью селектора XPath.

loader = ItemLoader(item = Item())
loader.add_xpath('social', '
a[@class = "social"]/@href')
loader.add_xpath('email', '
a[@class = "email"]/@href')
12

nested_css(css)

Он используется для создания вложенных загрузчиков с помощью селектора CSS.

loader = ItemLoader(item = Item())
loader.add_css('social', 'a[@class = "social"]/@href')
loader.add_css('email', 'a[@class = "email"]/@href')

В следующей таблице показаны атрибуты объектов ItemLoader -

Старший Нет Атрибут и описание
1

item

Это объект, анализируемый загрузчиком предметов.

2

context

Активен текущий контекст загрузчика предметов.

3

default_item_class

Он используется для представления элементов, если не указан в конструкторе.

4

default_input_processor

Поля, в которых не указан процессор ввода, являются единственными, для которых используются default_input_processors.

5

default_output_processor

Поля, в которых не указан выходной процессор, являются единственными, для которых используются default_output_processors.

6

default_selector_class

Это класс, используемый для создания селектора, если он не указан в конструкторе.

7

selector

Это объект, который можно использовать для извлечения данных с сайтов.

Вложенные загрузчики

Он используется для создания вложенных загрузчиков при анализе значений из подраздела документа. Если вы не создаете вложенные загрузчики, вам необходимо указать полный XPath или CSS для каждого значения, которое вы хотите извлечь.

Например, предположим, что данные извлекаются из страницы заголовка -

<header>
   <a class = "social" href = "http://facebook.com/whatever">facebook</a>
   <a class = "social" href = "http://twitter.com/whatever">twitter</a>
   <a class = "email" href = "mailto:[email protected]">send mail</a>
</header>

Затем вы можете создать вложенный загрузчик с селектором заголовка, добавив связанные значения в заголовок -

loader = ItemLoader(item = Item())
header_loader = loader.nested_xpath('//header')
header_loader.add_xpath('social', 'a[@class = "social"]/@href')
header_loader.add_xpath('email', 'a[@class = "email"]/@href')
loader.load_item()

Повторное использование и расширение загрузчиков предметов

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

Например, предположим, что на сайте название продукта заключено в три тире (например, --DVD ---). Вы можете удалить эти дефисы, повторно используя загрузчик элементов продукта по умолчанию, если вы не хотите, чтобы он был в конечных названиях продуктов, как показано в следующем коде -

from scrapy.loader.processors import MapCompose 
from demoproject.ItemLoaders import DemoLoader  

def strip_dashes(x): 
   return x.strip('-')  

class SiteSpecificLoader(DemoLoader): 
   title_in = MapCompose(strip_dashes, DemoLoader.title_in)

Доступные встроенные процессоры

Ниже приведены некоторые из наиболее часто используемых встроенных процессоров.

класс scrapy.loader.processors.Identity

Он возвращает исходное значение, не изменяя его. Например -

>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['a', 'b', 'c'])
['a', 'b', 'c']

класс scrapy.loader.processors.TakeFirst

Он возвращает первое значение, которое не является нулевым / непустым из списка полученных значений. Например -

>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'a', 'b', 'c'])
'a'

класс scrapy.loader.processors.Join (separator = u '')

Он возвращает значение, прикрепленное к разделителю. Разделителем по умолчанию является u '', и он эквивалентен функцииu' '.join. Например -

>>> from scrapy.loader.processors import Join
>>> proc = Join()
>>> proc(['a', 'b', 'c'])
u'a b c'
>>> proc = Join('<br>')
>>> proc(['a', 'b', 'c'])
u'a<br>b<br>c'

класс scrapy.loader.processors.Compose (* функции, ** default_loader_context)

Он определяется процессором, в котором каждое его входное значение передается первой функции, а результат этой функции передается второй функции и так далее, пока функция ast не вернет окончательное значение в качестве выходного.

Например -

>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['python', 'scrapy'])
'PYTHON'

класс scrapy.loader.processors.MapCompose (* функции, ** default_loader_context)

Это процессор, в котором входное значение повторяется, а первая функция применяется к каждому элементу. Затем результат этих вызовов функций объединяется для создания новой итерации, которая затем применяется ко второй функции и так далее, до последней функции.

Например -

>>> def filter_scrapy(x): 
   return None if x == 'scrapy' else x  

>>> from scrapy.loader.processors import MapCompose 
>>> proc = MapCompose(filter_scrapy, unicode.upper) 
>>> proc([u'hi', u'everyone', u'im', u'pythonscrapy']) 
[u'HI, u'IM', u'PYTHONSCRAPY']

класс scrapy.loader.processors.SelectJmes (json_path)

Этот класс запрашивает значение, используя предоставленный путь json, и возвращает результат.

Например -

>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
>>> proc = SelectJmes("hello")
>>> proc({'hello': 'scrapy'})
'scrapy'
>>> proc({'hello': {'scrapy': 'world'}})
{'scrapy': 'world'}

Ниже приведен код, который запрашивает значение путем импорта json:

>>> import json
>>> proc_single_json_str = Compose(json.loads, SelectJmes("hello"))
>>> proc_single_json_str('{"hello": "scrapy"}')
u'scrapy'
>>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('hello')))
>>> proc_json_list('[{"hello":"scrapy"}, {"world":"env"}]')
[u'scrapy']