1
votes

un disjoncteur de format sur le site Web arrête mon araignée Scrapy

mon Scrapy Spider cesse de fonctionner lorsqu'il rencontre une valeur aberrante de format de site Web. Voici l'élément du site Web qui ne va pas (la partie en surbrillance): entrez la description de l'image ici

La bonne a une attribution 'a'. il ressemble à ci-dessous ((la partie en surbrillance)): entrez la description de l'image ici

Et voici mon Spider:

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
  name = "name"
  allowed_domains = ["website domain"]
  start_urls = ['Mywebsite link']

  def parse(self, response):
    self.log('I just visited: ' + response.url)

    for i in response.css('tr.odd'):
        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            'ABN': i.css('td > a::text')[1].extract(),
            'status': i.css('td::text')[2].extract(),
            'size': i.css('td::text')[3].extract(),
            'suburb/town': i.css('td::text')[4].extract(),
            'state': i.css('td::text')[5].extract(),
        }
        yield item

    for i in response.css('tr.even'):
        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            **'ABN': i.css('td > a::text')[1].extract()**,     # this part stops working
            'status': i.css('td::text')[2].extract(),
            'size': i.css('td::text')[3].extract(),
            'suburb/town': i.css('td::text')[4].extract(),
            'state': i.css('td::text')[5].extract(),
        }
        yield item

    # follow pagination link
    next_page_url = response.css('li.next > a::attr(href)').extract_first()
    if next_page_url:
        next_page_url = response.urljoin(next_page_url)
        yield scrapy.Request(url=next_page_url, callback=self.parse)

Sur le site, cela ressemble à ceci: entrez la description de l'image ici La partie «informations non disponibles» dans cette rangée arrête mon araignée. Veuillez me montrer ce que je dois faire. Merci!


6 commentaires

Votre code attend 6 liens dans un td . Le code HTML d'entrée que vous ne devriez avoir que 1 (et ce n'est pas le nom de l'entreprise). Pensez à réécrire votre extraction de ligne à partir de zéro.


Merci pour la réponse mais je ne comprends pas ce que vous essayez de dire.


Avez-vous écrit le code que vous essayez de corriger? Comprenez-vous ce que fait i.css ('td> a :: text') [n] .extract () , étant donné le code HTML d'entrée que vos captures d'écran montrent? (ps: les captures d'écran du code sont déconseillées)


url: acnc.gov.au/...


Le code du haut est le code réel du site Web, j'avais l'impression que ma boucle saisirait le texte de la classe td et me donnerait les informations telles que le nom légal et ABN


@AkshatZala, merci, c'est fait.


3 Réponses :


0
votes

Concentrons-nous sur un problème à la fois:

Au lieu de diriger la sortie de la valeur, utilisez une variable temporaire.

    for i in response.css('tr.even'):
        abn = i.css('td > a::text')[1].extract()
        if not abn:
            abn = 'Unavailable' # Alternatively, you can use a fallback selector

        item = {
            'company_name': i.css('td > a::text')[0].extract(),
            'ABN': abn,
            #...
        }
        yield item

Vous pouvez également vérifier l'utilisation de extract () et extract_first () . La documentation recommande en fait l'utilisation de get () et getall () car c'est moins déroutant.

Les documents d'utilisation de Scrapy sont maintenant écrits en utilisant les méthodes .get () et .getall (). Nous pensons que ces nouvelles méthodes se traduisent par un résultat plus concis et lisible code.


3 commentaires

Vous reproduisez cependant le problème principal avec le code d'origine, qui est l'utilisation abusive de [n] .


Donc, à la place, je devrais essayer d'utiliser la classe tr comme un n, puis extraire les informations plutôt que de parcourir chacune individuellement.


@Upendra Merci pour votre réponse, mais la condition sinon provoque toujours une erreur.



0
votes

Le principal problème de votre implémentation est que votre programme peut appeler la méthode extract sur un élément qui n’existe pas.

for row in response.css('table.views-table tbody tr'):
    i = {}
    # field specific selectors
    i['company_name'], i['ABN'], i['status'], i['size'], i['suburb/town'], i['state'] = row.css('td')
    for key in i.keys():
        i[key] = i[key].css("*::text").get(default="") 
    yield i

J'ai utilisé la décompression de liste pour remplir l'élément champs ( partiellement basés sur cette réponse précédente )
car chaque ligne du tableau contient strictement 6 colonnes
selon docs - méthode get return résultat de la première correspondance
cela signifie qu'avec cette méthode, vous n'avez pas besoin d'utiliser explicitement une balise à l'intérieur du sélecteur de cellules du tableau.


1 commentaires

Merci pour votre réponse, votre code m'a montré une manière élégante d'utiliser Scrapy. Cependant, le résultat ne contient ni nom_entreprise ni ABN.



0
votes

J'ai résolu ce problème en réécrivant mes codes. Merci à tous les contributeurs de réponses. Un merci spécial à @Gallaecio. Voici ma solution:

import scrapy
from scrapy.crawler import CrawlerProcess

class AcncSpider(scrapy.Spider):
  name = "spider_name"
  allowed_domains = ["url"]
  start_urls = ['url']

  def parse(self, response):
    self.log('I just visited: ' + response.url)

    for i in response.css('div.view-content > div > table > tbody > tr.odd'):

        item = {
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first()),
                   
        }
        yield item
    
    for i in response.css('div.view-content > div > table > tbody > tr.even'):

        item = { 
            'company_name': i.css('td.views-field.views-field-acnc-search-api-title-sort > a::text').extract(),
             
            'status': i.css('td.views-field.views-field-acnc-search-api-status-normalised::text').extract(),
            
            'size': i.css('td.views-field.views-field-field-charity-size.views-align-center::text').extract(),
             
            'suburb/town': i.css('td.views-field.views-field-acnc-search-api-address-locality::text').extract(),
            
            'state': i.css('td.views-field.views-field-acnc-search-api-address-administrative-area::text').extract(),
             
            'ABN': i.css('td.views-field.views-field-acnc-search-api-abn-sort > a::text').extract(),

            'URL': response.urljoin(i.css('td.views-field.views-field-acnc-search-api-title-sort > a::attr(href)').extract_first())
        }
        yield item
    
    # follow pagination link
    next_page_url = response.css('li.next > a::attr(href)').extract_first()
    if next_page_url:
        next_page_url = response.urljoin(next_page_url)
        yield scrapy.Request(url=next_page_url, callback=self.parse)


0 commentaires