Python抓取从几个页面收集数据到一个项目(字典)



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

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

蜘蛛收集下一页(2nd),但它将它们连接到任何故事的第一页。例如,可以将第 1 个故事的第 2 页添加到第 4 个故事中。第 5 个故事的第 2 页添加到第 1 个故事中。等等。

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

谢谢。

非技术上讲: -

1)刮擦故事第一页 2)检查它是否有更多页面 3)如果没有,只需yield项目 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

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

item = SxtlItem()

此 Item 声明应从解析函数移动到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()"移动到正确的位置后,一切正常。

相关内容

最新更新