прерыватель формата на веб-сайте останавливает мой паук Scrapy - PullRequest
1 голос
/ 18 июня 2020

мой Scrapy Spider перестает работать, когда встречается с нестандартным форматом веб-сайта. Вот элемент веб-сайта, который go НЕПРАВИЛЬНО (выделенная часть): enter image description here

Правильный элемент имеет атрибуцию «а». он выглядит так ((выделенная часть)): enter image description here

А вот мой Паук:

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)

На сайте это выглядит так: enter image description here Часть «информация недоступна» в этой строке останавливает моего паука. Покажи, пожалуйста, что мне делать. Спасибо!

Ответы [ 3 ]

0 голосов
/ 18 июня 2020

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

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

Я использовал распаковку списка для заполнения полей элемента ( частично основано на этот более ранний ответ )
, поскольку каждая строка таблицы имеет строго 6 столбцов
согласно docs - метод get возвращает результат первого совпадения
это означает, что с этим вам не нужно явно использовать тег a внутри селектора ячеек таблицы.

0 голосов
/ 25 июня 2020

Я решил эту проблему, переписав свои коды. Спасибо всем авторам ответов. Особая благодарность @Gallaecio. Вот мое решение:

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 голосов
/ 18 июня 2020

Давайте сосредоточимся на одной проблеме за раз:

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

    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

Вы также можете проверить использование extract() и extract_first(). Документация на самом деле рекомендует использовать новые get() и getall(), поскольку это менее запутанно.

Документация по использованию Scrapy теперь написана с использованием .get () и .getall ( ) методы. Мы считаем, что эти новые методы позволяют получить более лаконичный и читаемый код.

...