Извлечение таблицы свойств из продукта dt dd с помощью scrapy - получение списка индексов вне диапазона - PullRequest
0 голосов
/ 03 мая 2019

Вот страницу, которую я пытаюсь почистить https://www.termex.ru/catalog/protochnye_vodonagrevateli/18445/ У меня проблемы с извлечением свойств продукта.

<dl class="product-item-detail-properties">
<dt>Артикул</dt>
<dd>TIP 500 (combi)</dd>
<dt>Производитель</dt>
<dd>THERMEX</dd>
<dt>Гарантия</dt>
<dd>12 месяцев</dd>
</dl>

Я тестировал текущий код, используя Scapy Shell и его работу.

item['properties'] = list()
        for prop in response.xpath('//dl[@class="product-item-detail-properties"]'):
            item['properties'].append(
                {
                    'name': prop.xpath('normalize-space(./dt)').getall()[1],
                    'value': prop.xpath('normalize-space(./dd)').getall()[1],
                }
            )
        yield item

Первое значение для dt / dd пустое, поэтому я вынужден использовать второе значение - getall()[1].

>>> prop.xpath('normalize-space(./dt)').getall()
['', 'Артикул']

По некоторым причинам, когда я запускаю полный паук, я получаю ошибку list index out of range. Вот мой журнал:

2019-05-03 14:11:03 [scrapy.core.engine] INFO: Spider opened
2019-05-03 14:11:03 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2019-05-03 14:11:03 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6024
2019-05-03 14:11:03 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.termex.ru/robots.txt> (referer: None)
2019-05-03 14:11:04 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/> (referer: None)
2019-05-03 14:11:04 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/19637/> (referer: https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/)
2019-05-03 14:11:04 [scrapy.core.scraper] ERROR: Spider error processing <GET https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/19637/> (referer: https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/)
Traceback (most recent call last):
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/utils/defer.py", line 102, in iter_errback
    yield next(it)
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/offsite.py", line 30, in process_spider_output
    for x in result:
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/referer.py", line 339, in <genexpr>
    return (_set_referer(r) for r in result or ())
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/urllength.py", line 37, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/depth.py", line 58, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/home/roman/scrapy/globaldriveru/globaldriveru/spiders/termex_ru.py", line 28, in parse_products
    'name': prop.xpath('normalize-space(./dt)').getall()[1],
IndexError: list index out of range
2019-05-03 14:11:04 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/9292/> (referer: https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/)
2019-05-03 14:11:05 [scrapy.core.scraper] ERROR: Spider error processing <GET https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/9292/> (referer: https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/)
Traceback (most recent call last):
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/utils/defer.py", line 102, in iter_errback
    yield next(it)
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/offsite.py", line 30, in process_spider_output
    for x in result:
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/referer.py", line 339, in <genexpr>
    return (_set_referer(r) for r in result or ())
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/urllength.py", line 37, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/home/roman/miniconda/envs/scrapy/lib/python3.7/site-packages/scrapy/spidermiddlewares/depth.py", line 58, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "/home/roman/scrapy/globaldriveru/globaldriveru/spiders/termex_ru.py", line 28, in parse_products
    'name': prop.xpath('normalize-space(./dt)').getall()[1],
IndexError: list index out of range

Вот мой полный паук:

import scrapy


class TermexRuSpider(scrapy.Spider):
    name = 'termex_ru'
    allowed_domains = ['termex.ru']
    start_urls = ['https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/',
     #             'https://www.termex.ru/catalog/nakopitelnye_vodonagrevateli/?PAGEN_1=2',
     #             'https://www.termex.ru/catalog/protochnye_vodonagrevateli/',
                  ]

    def parse(self, response):
        links = response.xpath('//a[@class="product-item-image-wrapper"]/@href').extract()
        for link in links:
            yield scrapy.Request(response.urljoin(link), callback=self.parse_products, dont_filter=True)

    def parse_products(self, response):
        item = dict()
        item['title'] = response.xpath('//meta[@itemprop="name"]/@content').getall()
        item['department'] = response.xpath('//span[@itemprop="name"]')[2]
        item['price'] = response.xpath('//meta[@itemprop="price"]/@content').get()
        item['image'] = response.xpath('//div[@class="product-item-detail-slider-image active"]/img/@src').get()
        item['properties'] = list()
        for prop in response.xpath('//dl[@class="product-item-detail-properties"]'):
            item['properties'].append(
                {
                    'name': prop.xpath('normalize-space(./dt)').getall()[1],
                    'value': prop.xpath('normalize-space(./dd)').getall()[1],
                }
            )
        yield item

1 Ответ

2 голосов
/ 03 мая 2019

У вас есть два элемента //dl[@class="product-item-detail-properties"] на странице. Одна пуста, а вторая содержит список dt / dd. И теперь вы повторяете не по парам, как вы хотели, а по этому родительскому списку.

Я бы предложил вам это решение для dt / dd:

    for prop in response.xpath('//dl[@class="product-item-detail-properties"]/dt'):
        item['properties'].append(
            {
                'name': prop.xpath('normalize-space(./text())').get(),
                'value': prop.xpath('normalize-space(./following-sibling::dd/text())').get(),
            }
        )
  1. повторяется по всем dt в вашем списке;
  2. получить его текст как name и получить первого следующего брата dd как value.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...