Скрапинг с помощью scrapy

Я пытаюсь копнуть немного глубже с помощью scrapy, но могу получить только название того, что я очищаю, а не какие-либо детали. Вот код, который у меня есть до сих пор:

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from tcgplayer1.items import Tcgplayer1Item

class MySpider(BaseSpider):
    name = "tcg"
    allowed_domains = ["http://www.tcgplayer.com/"]
    start_urls = ["http://store.tcgplayer.com/magic/journey-into-nyx?PageNumber=1"]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)
        titles = hxs.select("//div[@class='magicCard']")
        vendor = hxs.select("//tr[@class='vendor']")
        items = []

        for titles in titles:
            item = Tcgplayer1Item()
            item ["cardname"] = titles.select("//li[@class='cardName']/a/text()").extract()
            item ["price"] = vendor.select("//td[@class='price']/br/text()").extract()
            item ["quantity"] = vendor.select("//td[@class='quantity']/td/text()").extract()
            items.append(item)
        return items

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


person six7zero9    schedule 27.05.2014    source источник


Ответы (2)


Прежде всего, вот исправленная версия кода:

from scrapy.spider import BaseSpider
from scrapy.selector import Selector
from tcgplayer1.items import Tcgplayer1Item


class MySpider(BaseSpider):
    name = "tcg"
    allowed_domains = ["http://www.tcgplayer.com/"]
    start_urls = ["http://store.tcgplayer.com/magic/journey-into-nyx?PageNumber=1"]

    def parse(self, response):
        hxs = Selector(response)
        titles = hxs.xpath("//div[@class='magicCard']")
        for title in titles:
            item = Tcgplayer1Item()
            item["cardname"] = title.xpath(".//li[@class='cardName']/a/text()").extract()[0]

            vendor = title.xpath(".//tr[@class='vendor ']")
            item["price"] = vendor.xpath("normalize-space(.//td[@class='price']/text())").extract()
            item["quantity"] = vendor.xpath("normalize-space(.//td[@class='quantity']/text())").extract()
            yield item

Было несколько проблем с кодом:

  • имя класса vendor должно содержать пробел в конце: "поставщик" - было сложно найти
  • для каждого товара есть несколько поставщиков - вам нужно определить vendor внутри цикла
  • вы переопределяете переменную titles в цикле
  • выражения xpath в цикле должны быть относительными .//
  • используйте Selector вместо устаревшего HtmlXPathSelector
  • используйте xpath() вместо устаревшего select()
  • используйте normalize-space() для удаления новых строк и лишних пробелов в price и quantity xpaths
person alecxe    schedule 27.05.2014
comment
это действительно близко ... единственная проблема в том, что цены и количество не соответствуют картам. Он показывает один и тот же список цен для каждой карты ... а также количество. Хотя это было гораздо ближе. - person six7zero9; 27.05.2014
comment
@user3680812 user3680812 возникла небольшая проблема, я обновил код, перепроверьте, пожалуйста. - person alecxe; 27.05.2014
comment
.//tr сделал это ... ты так много. - person six7zero9; 27.05.2014
comment
@ user3680812 рад, что это помогло. Это была интересная проблема. Подумайте о том, чтобы принять ответ, если считаете, что он того заслуживает. Спасибо. - person alecxe; 27.05.2014
comment
насколько сложно заставить этот код выполняться через page1, сколько бы страниц там ни было? - person six7zero9; 27.05.2014
comment
@ user3680812 ну, это хороший кандидат на отдельный вопрос SO. Но идея в основном состоит в том, чтобы получить номер последней страницы из части страницы с разбивкой на страницы и динамически определить свой start_urls, переопределив start_requests() вашего паука. - person alecxe; 27.05.2014

Во-первых, вы можете изменить

item ["price"] = vendor.select("//td[@class='price']/br/text()").extract()
item ["quantity"] = vendor.select("//td[@class='quantity']/td/text()").extract()

To:

item ["price"] = titles.select("//td[@class='price']/br/text()").extract()
item ["quantity"] = titles.select("//td[@class='quantity']/td/text()").extract()

Это гарантирует, что вы получите только строки цены и количества для нужной карты.

Возможно, вам также придется удалить /br и /td из селекторов, чтобы ваш код выглядел так:

item ["price"] = titles.select("//td[@class='price']/text()").extract()
item ["quantity"] = titles.select("//td[@class='quantity']/text()").extract()
person Adam    schedule 27.05.2014