【问题标题】:python scrapy collecting data from several pages into one item(dictionary)python scrapy将多个页面中的数据收集到一个项目中(字典)
【发布时间】:2017-04-16 11:48:13
【问题描述】:

我有一个网站要抓取。在主页上它有故事预告 - 所以,这个页面将是我们的开始解析页面。我的蜘蛛会从它那里收集有关每个故事的数据——作者、评级、出版日期等。这些都是由蜘蛛正确完成的。

import scrapy
from scrapy.spiders import Spider
from sxtl.items import SxtlItem
from scrapy.http.request import Request


class SxtlSpider(Spider):
    name = "sxtl"

    start_urls = ['some_site']


    def parse(self, response):

        list_of_stories = response.xpath('//div[@id and @class="storyBox"]')

        item = SxtlItem()

        for i in list_of_stories:

            pre_rating = i.xpath('div[@class="storyDetail"]/div[@class="stor\
                yDetailWrapper"]/div[@class="block rating_positive"]/span/\
                text()').extract()
            rating = float(("".join(pre_rating)).replace("+", ""))

            link = "".join(i.xpath('div[@class="wrapSLT"]/div[@class="title\
                Story"]/a/@href').extract())

            if rating > 6:
                yield Request("".join(link), meta={'item':item}, callback=\
                                                            self.parse_story)
            else:
                break

    def parse_story(self, response):

        item = response.meta['item']

        number_of_pages = response.xpath('//div[@class="pNavig"]/a[@href]\
                                        [last()-1]/text()').extract()

        if number_of_pages:
            item['number_of_pages'] = int("".join(number_of_pages))
        else:
            item['number_of_pages'] = 1

        item['date'] = "".join(response.xpath('//span[@class="date"]\
                                                /text()').extract()).strip()
        item['author'] = "".join(response.xpath('//a[@class="author"]\
                                                /text()').extract()).strip()
        item['text'] = response.xpath('//div[@id="storyText"]/div\
                [@itemprop="description"]/text() | //div[@id="storyText"]\
                        /div[@itemprop="description"]/p/text()').extract()
        item['list_of_links'] = response.xpath('//div[@class="pNavig"]\
                                            /a[@href]/@href').extract()

        yield item

因此,数据收集正确,但我们只有每个故事的第一页。但是每个 sory 都有几页(并且有指向第 2、3、4 页的链接,有时是 15 页)。这就是问题出现的地方。我用这个替换产量项目:(获取每个故事的第二页)

yield Request("".join(item['list_of_links'][0]), meta={'item':item}, \
                                                callback=self.get_text)


def get_text(self, response):

    item = response.meta['item']

    item['text'].extend(response.xpath('//div[@id="storyText"]/div\
        [@itemprop="description"]/text() | //div[@id="storyText"]\
                /div[@itemprop="description"]/p/text()').extract())

    yield item

Spider 收集下一页(第 2 页),但它会将它们连接到任何故事的第一页。例如,第 1 层的第 2 页可以添加到第 4 层。第 5 故事的第 2 页被添加到第 1 故事。以此类推。

请帮忙,如果要抓取的数据分布在多个网页上,如何将数据收集到一个项目(一个字典)中? (在这种情况下 - 如何不让来自不同项目的数据相互混合?)

谢谢。

【问题讨论】:

标签: python web-scraping scrapy


【解决方案1】:

从技术上讲:-

1) 刮故事第一页 2)检查它是否有更多页面 3)如果没有,只需yield item 4)如果它有下一页按钮/链接,则抓取该链接并将整个数据字典传递给下一个回调方法。

def parse_story(self, response):

    item = response.meta['item']

    number_of_pages = response.xpath('//div[@class="pNavig"]/a[@href]\
                                    [last()-1]/text()').extract()

    if number_of_pages:
        item['number_of_pages'] = int("".join(number_of_pages))
    else:
        item['number_of_pages'] = 1

    item['date'] = "".join(response.xpath('//span[@class="date"]\
                                            /text()').extract()).strip()
    item['author'] = "".join(response.xpath('//a[@class="author"]\
                                            /text()').extract()).strip()
    item['text'] = response.xpath('//div[@id="storyText"]/div\
            [@itemprop="description"]/text() | //div[@id="storyText"]\
                    /div[@itemprop="description"]/p/text()').extract()
    item['list_of_links'] = response.xpath('//div[@class="pNavig"]\
                                        /a[@href]/@href').extract()

    # if it has NEXT PAGE button
    if nextPageURL > 0:
        yield Request(url= nextPageURL , callback=self.get_text, meta={'item':item})
    else:
        # it has no more pages, so just yield data.
        yield item





def get_text(self, response):

    item = response.meta['item']


    # merge text here
    item['text'] = item['text'] + response.xpath('//div[@id="storyText"]/div\
        [@itemprop="description"]/text() | //div[@id="storyText"]\
                /div[@itemprop="description"]/p/text()').extract()


    # Now again check here if it has NEXT PAGE button call same function again.
    if nextPageURL > 0:
        yield Request(url= nextPageURL , callback=self.get_text, meta={'item':item})
    else:
        # no more pages, now finally yield the ITEM
        yield item

【讨论】:

  • 谢谢,但这正是我想要做的。 "1) 刮故事第一页 2) 检查它是否有更多页面 3) 如果没有,只产生项目 4) 如果它有下一页按钮/链接,则刮掉该链接并将整个数据字典传递给下一个回调方法。”失败后,我试着从网站上抓取 1 或 2 页。无论如何,我已经解决了这个问题,我会在答案中展示它。
  • 但无论如何,我感谢您的时间和关注。谢谢。
【解决方案2】:

经过多次尝试和阅读一大堆文档后,我找到了解决方案:

item = SxtlItem()

这个 Item 声明应该从 parse 函数移动到 parse_story 函数的开头。并且应该删除 parse_story 中的“item = response.meta['item']”行。当然,

yield Request("".join(link), meta={'item':item}, callback=self.parse_story)

在“解析”中应该改为

yield Request("".join(link), callback=self.parse_story)

为什么?因为 Item 只声明了一次,并且它的所有字段都在不断地被重写。虽然文档中只有一页 - 看起来一切正常,好像我们有一个“新”项目。但是当一个故事有几页时,这个项目会以一些混乱的方式被覆盖,我们会收到混乱的结果。很快:应该创建尽可能多的新项目,就像我们要保存的项目对象一样多。

将“item = SxtlItem()”移动到正确的位置后,一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多