Scrapy: cargadores de artículos

Descripción

Los cargadores de artículos proporcionan una forma conveniente de llenar los artículos que se extraen de los sitios web.

Declarar cargadores de artículos

La declaración de cargadores de artículos es como artículos.

Por ejemplo

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

En el código anterior, puede ver que los procesadores de entrada se declaran usando _in Los procesadores de sufijo y salida se declaran usando _out sufijo.

los ItemLoader.default_input_processor y ItemLoader.default_output_processor Los atributos se utilizan para declarar procesadores de entrada / salida predeterminados.

Uso de cargadores de elementos para completar elementos

Para usar el Cargador de artículos, primero cree una instancia con un objeto similar a dict o sin uno donde el artículo use la clase de artículo especificada en ItemLoader.default_item_class atributo.

  • Puede utilizar selectores para recopilar valores en el Cargador de artículos.

  • Puede agregar más valores en el mismo campo de artículo, donde Item Loader utilizará un controlador apropiado para agregar estos valores.

El siguiente código demuestra cómo se rellenan los elementos con los cargadores de elementos:

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()

Como se muestra arriba, hay dos XPaths diferentes de los cuales el title el campo se extrae usando add_xpath() método -

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

A partir de entonces, se utiliza una solicitud similar para desccampo. Los datos de tamaño se extraen usandoadd_css() método y last_updated se rellena con un valor "ayer" utilizando add_value() método.

Una vez recopilados todos los datos, llame ItemLoader.load_item() método que devuelve los elementos llenos de datos extraídos utilizando add_xpath(), add_css() y add_value() métodos.

Procesadores de entrada y salida

Cada campo de un cargador de artículos contiene un procesador de entrada y un procesador de salida.

  • Cuando se extraen los datos, el procesador de entrada los procesa y su resultado se almacena en ItemLoader.

  • A continuación, después de recopilar los datos, llame al método ItemLoader.load_item () para obtener el objeto Item poblado.

  • Finalmente, puede asignar el resultado del procesador de salida al artículo.

El siguiente código demuestra cómo llamar a procesadores de entrada y salida para un campo específico:

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 - Los datos del título se extraen de xpath1 y se pasan a través del procesador de entrada y su resultado se recopila y almacena en ItemLoader.

Line 2 - De manera similar, el título se extrae de xpath2 y se pasa por el mismo procesador de entrada y su resultado se agrega a los datos recopilados para [1].

Line 3 - El título se extrae del selector css y se pasa por el mismo procesador de entrada y el resultado se agrega a los datos recopilados para [1] y [2].

Line 4 - A continuación, se asigna el valor "demo" y se pasa a través de los procesadores de entrada.

Line 5 - Finalmente, los datos se recopilan internamente de todos los campos y se pasan al procesador de salida y el valor final se asigna al artículo.

Declaración de procesadores de entrada y salida

Los procesadores de entrada y salida se declaran en la definición de ItemLoader. Aparte de esto, también se pueden especificar en elItem Field metadatos.

Por ejemplo

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()

Muestra una salida como:

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

Contexto del cargador de artículos

El contexto del cargador de elementos es un dictado de valores clave arbitrarios compartidos entre procesadores de entrada y salida.

Por ejemplo, suponga que tiene una función 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

Al recibir argumentos de loader_context, le dice al Cargador de artículos que puede recibir el contexto del Cargador de artículos. Hay varias formas de cambiar el valor del contexto del cargador de artículos:

  • Modificar el contexto actual del cargador de elementos activo -

loader = ItemLoader (product)
loader.context ["unit"] = "mm"
  • En la instanciación de Item Loader -

loader = ItemLoader(product, unit = "mm")
  • En la declaración de Item Loader para procesadores de entrada / salida que crea una instancia con el contexto de Item Loader -

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

Objetos ItemLoader

Es un objeto que devuelve un nuevo cargador de elementos para completar el elemento dado. Tiene la siguiente clase:

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

La siguiente tabla muestra los parámetros de los objetos ItemLoader:

No Señor Descripción de parámetros
1

item

Es el elemento que se debe completar llamando a add_xpath (), add_css () o add_value ().

2

selector

Se utiliza para extraer datos de sitios web.

3

response

Se usa para construir el selector usando default_selector_class.

La siguiente tabla muestra los métodos de los objetos ItemLoader:

No Señor Método y descripción Ejemplo
1

get_value(value, *processors, **kwargs)

Por un procesador dado y argumentos de palabra clave, el valor es procesado por el método 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)

Procesa el valor y lo agrega al campo donde primero se pasa a través de get_value dando procesadores y argumentos de palabras clave antes de pasar por el procesador de entrada de campo.

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)

Reemplaza los datos recopilados por un nuevo valor.

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)

Se utiliza para extraer cadenas Unicode dando procesadores y argumentos de palabras clave al recibir 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)

Recibe XPath en el campo que extrae cadenas 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)

Reemplaza los datos recopilados mediante XPath de los sitios.

# 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)

Recibe el selector de CSS que se utiliza para extraer las cadenas 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)

Es similar al método add_value () con la diferencia de que agrega un selector CSS al campo.

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)

Reemplaza los datos extraídos usando el selector CSS.

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

load_item()

Cuando se recopilan los datos, este método llena el artículo con los datos recopilados y lo devuelve.

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)

Se utiliza para crear cargadores anidados con un selector 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)

Se utiliza para crear cargadores anidados con un selector de CSS.

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

La siguiente tabla muestra los atributos de los objetos ItemLoader:

No Señor Atributo y descripción
1

item

Es un objeto en el que Item Loader realiza un análisis.

2

context

Es el contexto actual de Item Loader el que está activo.

3

default_item_class

Se utiliza para representar los elementos, si no se da en el constructor.

4

default_input_processor

Los campos que no especifican el procesador de entrada son los únicos para los que se utilizan default_input_processors.

5

default_output_processor

Los campos que no especifican el procesador de salida son los únicos para los que se utilizan default_output_processors.

6

default_selector_class

Es una clase que se usa para construir el selector, si no se da en el constructor.

7

selector

Es un objeto que se puede utilizar para extraer los datos de los sitios.

Cargadores anidados

Se utiliza para crear cargadores anidados mientras se analizan los valores de la subsección de un documento. Si no crea cargadores anidados, debe especificar XPath o CSS completos para cada valor que desee extraer.

Por ejemplo, suponga que los datos se extraen de una página de encabezado:

<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>

A continuación, puede crear un cargador anidado con selector de encabezado agregando valores relacionados al encabezado:

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()

Reutilización y ampliación de cargadores de artículos

Los cargadores de artículos están diseñados para aliviar el mantenimiento que se convierte en un problema fundamental cuando su proyecto adquiere más arañas.

Por ejemplo, suponga que un sitio tiene el nombre de su producto entre tres guiones (por ejemplo, --DVD ---). Puede eliminar esos guiones reutilizando el Cargador de artículos de producto predeterminado, si no lo desea en los nombres de productos finales como se muestra en el siguiente código:

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)

Procesadores integrados disponibles

A continuación se muestran algunos de los procesadores integrados de uso común:

clase scrapy.loader.processors.Identity

Devuelve el valor original sin alterarlo. Por ejemplo

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

clase scrapy.loader.processors.TakeFirst

Devuelve el primer valor que no es nulo / no está vacío de la lista de valores recibidos. Por ejemplo

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

clase scrapy.loader.processors.Join (separador = u '')

Devuelve el valor adjunto al separador. El separador predeterminado es u '' y es equivalente a la funciónu' '.join. Por ejemplo

>>> 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'

clase scrapy.loader.processors.Compose (* funciones, ** default_loader_context)

Está definido por un procesador donde cada uno de sus valores de entrada se pasa a la primera función, y el resultado de esa función se pasa a la segunda función y así sucesivamente, hasta que la función ast devuelve el valor final como salida.

Por ejemplo

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

clase scrapy.loader.processors.MapCompose (* funciones, ** default_loader_context)

Es un procesador donde se itera el valor de entrada y se aplica la primera función a cada elemento. A continuación, el resultado de estas llamadas de función se concatenan para crear un nuevo iterable que luego se aplica a la segunda función y así sucesivamente, hasta la última función.

Por ejemplo

>>> 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']

clase scrapy.loader.processors.SelectJmes (json_path)

Esta clase consulta el valor utilizando la ruta json proporcionada y devuelve el resultado.

Por ejemplo

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

A continuación se muestra el código, que consulta el valor importando 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']