Scrapy - Chargeurs d'articles

La description

Les chargeurs d'articles constituent un moyen pratique de remplir les articles extraits des sites Web.

Déclaration des chargeurs d'articles

La déclaration des chargeurs d'articles est semblable aux articles.

Par exemple -

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

Dans le code ci-dessus, vous pouvez voir que les processeurs d'entrée sont déclarés en utilisant _in les processeurs de suffixe et de sortie sont déclarés en utilisant _out suffixe.

le ItemLoader.default_input_processor et ItemLoader.default_output_processor Les attributs sont utilisés pour déclarer les processeurs d'entrée / sortie par défaut.

Utilisation de chargeurs d'articles pour remplir des articles

Pour utiliser le chargeur d'élément, instanciez d'abord avec un objet de type dict ou sans objet lorsque l'élément utilise la classe Item spécifiée dans ItemLoader.default_item_class attribut.

  • Vous pouvez utiliser des sélecteurs pour collecter des valeurs dans le chargeur d'articles.

  • Vous pouvez ajouter plus de valeurs dans le même champ d'élément, où le chargeur d'élément utilisera un gestionnaire approprié pour ajouter ces valeurs.

Le code suivant montre comment les éléments sont remplis à l'aide de chargeurs d'éléments -

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

Comme indiqué ci-dessus, il existe deux XPaths différents à partir desquels le title le champ est extrait en utilisant add_xpath() méthode -

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

Par la suite, une demande similaire est utilisée pour descchamp. Les données de taille sont extraites à l'aide deadd_css() méthode et last_updated est rempli avec une valeur "hier" en utilisant add_value() méthode.

Une fois toutes les données collectées, appelez ItemLoader.load_item() méthode qui renvoie les éléments remplis avec les données extraites à l'aide de add_xpath(), add_css() et add_value() méthodes.

Processeurs d'entrée et de sortie

Chaque champ d'un Item Loader contient un processeur d'entrée et un processeur de sortie.

  • Lorsque les données sont extraites, le processeur d'entrée les traite et son résultat est stocké dans ItemLoader.

  • Ensuite, après avoir collecté les données, appelez la méthode ItemLoader.load_item () pour obtenir l'objet Item rempli.

  • Enfin, vous pouvez affecter le résultat du processeur de sortie à l'élément.

Le code suivant montre comment appeler des processeurs d'entrée et de sortie pour un champ spécifique -

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 - Les données de titre sont extraites de xpath1 et transmises au processeur d'entrée et son résultat est collecté et stocké dans ItemLoader.

Line 2 - De même, le titre est extrait de xpath2 et passé par le même processeur d'entrée et son résultat est ajouté aux données collectées pour [1].

Line 3 - Le titre est extrait du sélecteur css et passé par le même processeur d'entrée et le résultat est ajouté aux données collectées pour [1] et [2].

Line 4 - Ensuite, la valeur "demo" est affectée et transmise par les processeurs d'entrée.

Line 5 - Enfin, les données sont collectées en interne à partir de tous les champs et transmises au processeur de sortie et la valeur finale est attribuée à l'élément.

Déclaration des processeurs d'entrée et de sortie

Les processeurs d'entrée et de sortie sont déclarés dans la définition ItemLoader. En dehors de cela, ils peuvent également être spécifiés dans leItem Field métadonnées.

Par exemple -

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

Il affiche une sortie comme -

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

Contexte du chargeur d'articles

Le contexte du chargeur d'élément est un dict de valeurs de clé arbitraires partagées entre les processeurs d'entrée et de sortie.

Par exemple, supposons que vous ayez une fonction 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

En recevant les arguments loader_context, il indique au chargeur d'éléments qu'il peut recevoir le contexte du chargeur d'éléments. Il existe plusieurs façons de modifier la valeur du contexte du chargeur d'élément -

  • Modifier le contexte actuel du chargeur d'élément actif -

loader = ItemLoader (product)
loader.context ["unit"] = "mm"
  • Sur l'instanciation du chargeur d'objets -

loader = ItemLoader(product, unit = "mm")
  • Sur la déclaration Item Loader pour les processeurs d'entrée / sortie qui instancie avec le contexte Item Loader -

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

Objets ItemLoader

C'est un objet qui renvoie un nouveau chargeur d'élément pour remplir l'élément donné. Il a la classe suivante -

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

Le tableau suivant montre les paramètres des objets ItemLoader -

Sr. Non Paramètre et description
1

item

C'est l'élément à remplir en appelant add_xpath (), add_css () ou add_value ().

2

selector

Il est utilisé pour extraire des données de sites Web.

3

response

Il est utilisé pour construire un sélecteur en utilisant default_selector_class.

Le tableau suivant montre les méthodes des objets ItemLoader -

Sr. Non Méthode et description Exemple
1

get_value(value, *processors, **kwargs)

Par un processeur et des arguments de mots clés donnés, la valeur est traitée par la méthode 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)

Il traite la valeur et ajoute au champ où elle est d'abord passée par get_value en donnant des processeurs et des arguments de mot-clé avant de passer par le processeur d'entrée de champ.

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)

Il remplace les données collectées par une nouvelle valeur.

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)

Il est utilisé pour extraire des chaînes unicode en donnant des processeurs et des arguments de mots clés en recevant 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)

Il reçoit XPath dans le champ qui extrait les chaînes 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)

Il remplace les données collectées à l'aide de XPath à partir de sites.

# 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 (.*)')
sept

get_css(css, *processors, **kwargs)

Il reçoit le sélecteur CSS utilisé pour extraire les chaînes 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)

Elle est similaire à la méthode add_value () à une différence près qu'elle ajoute un sélecteur CSS au champ.

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)

Il remplace les données extraites à l'aide du sélecteur CSS.

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

load_item()

Lorsque les données sont collectées, cette méthode remplit l'élément avec les données collectées et les renvoie.

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)

Il est utilisé pour créer des chargeurs imbriqués avec un sélecteur 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)

Il est utilisé pour créer des chargeurs imbriqués avec un sélecteur CSS.

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

Le tableau suivant montre les attributs des objets ItemLoader -

Sr. Non Attribut et description
1

item

C'est un objet sur lequel le chargeur d'élément effectue une analyse.

2

context

C'est le contexte actuel de Item Loader qui est actif.

3

default_item_class

Il est utilisé pour représenter les éléments, s'ils ne sont pas donnés dans le constructeur.

4

default_input_processor

Les champs qui ne spécifient pas de processeur d'entrée sont les seuls pour lesquels les processeurs default_input_processors sont utilisés.

5

default_output_processor

Les champs qui ne spécifient pas le processeur de sortie sont les seuls pour lesquels default_output_processors sont utilisés.

6

default_selector_class

C'est une classe utilisée pour construire le sélecteur, si elle n'est pas donnée dans le constructeur.

sept

selector

C'est un objet qui peut être utilisé pour extraire les données des sites.

Chargeurs imbriqués

Il est utilisé pour créer des chargeurs imbriqués tout en analysant les valeurs de la sous-section d'un document. Si vous ne créez pas de chargeurs imbriqués, vous devez spécifier XPath ou CSS complet pour chaque valeur que vous souhaitez extraire.

Par exemple, supposons que les données sont extraites d'une page d'en-tête -

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

Ensuite, vous pouvez créer un chargeur imbriqué avec sélecteur d'en-tête en ajoutant des valeurs associées à l'en-tête -

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

Réutilisation et extension des chargeurs d'articles

Les chargeurs d'objets sont conçus pour soulager la maintenance qui devient un problème fondamental lorsque votre projet acquiert plus d'araignées.

Par exemple, supposons qu'un site a son nom de produit entre trois tirets (par exemple --DVD ---). Vous pouvez supprimer ces tirets en réutilisant le chargeur d'élément de produit par défaut, si vous ne le souhaitez pas dans les noms de produit finaux, comme indiqué dans le code suivant -

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)

Processeurs intégrés disponibles

Voici quelques-uns des processeurs intégrés couramment utilisés -

classe scrapy.loader.processors.Identity

Il renvoie la valeur d'origine sans la modifier. Par exemple -

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

classe scrapy.loader.processors.TakeFirst

Il renvoie la première valeur non nulle / non vide de la liste des valeurs reçues. Par exemple -

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

classe scrapy.loader.processors.Join (separator = u '')

Il renvoie la valeur attachée au séparateur. Le séparateur par défaut est u '' et équivaut à la fonctionu' '.join. Par exemple -

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

classe scrapy.loader.processors.Compose (* fonctions, ** default_loader_context)

Il est défini par un processeur où chacune de ses valeurs d'entrée est passée à la première fonction, et le résultat de cette fonction est passé à la seconde fonction et ainsi de suite, jusqu'à ce que la fonction ast renvoie la valeur finale en sortie.

Par exemple -

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

classe scrapy.loader.processors.MapCompose (* fonctions, ** default_loader_context)

C'est un processeur où la valeur d'entrée est itérée et la première fonction est appliquée à chaque élément. Ensuite, le résultat de ces appels de fonction est concaténé pour créer un nouvel itérable qui est ensuite appliqué à la deuxième fonction et ainsi de suite, jusqu'à la dernière fonction.

Par exemple -

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

classe scrapy.loader.processors.SelectJmes (json_path)

Cette classe interroge la valeur à l'aide du chemin json fourni et renvoie la sortie.

Par exemple -

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

Voici le code, qui interroge la valeur en important 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']