使用Scrapy导出到JSON文件时只输出一行

3 投票
1 回答
2383 浏览
提问于 2025-04-18 05:13

好的,我刚开始学习编程,特别是用Scrapy这个工具。我写了一个爬虫程序,想从pinterest.com上获取数据。问题是,我原本可以从页面上的所有图钉获取数据,但现在只得到第一个图钉的数据。

我觉得问题可能出在数据处理的管道或者爬虫本身。自从我在爬虫里加了“strip”这个功能来去掉空格后,情况就变了。不过当我把它改回去时,输出结果还是一样,只是多了空格。这是我的爬虫代码:

from scrapy.spider import Spider
from scrapy.selector import Selector
from Pinterest.items import PinterestItem

class PinterestSpider(Spider):
    name = "pinterest"
    allowed_domains = ["pinterest.com"]
    start_urls = ["http://www.pinterest.com/llbean/pins/"]

    def parse(self, response):
        hxs = Selector(response)
        item = PinterestItem()
        items = []
        item ["pin_link"] = hxs.xpath("//div[@class='pinHolder']/a/@href").extract()[0].strip()
        item ["repin_count"] = hxs.xpath("//em[@class='socialMetaCount repinCountSmall']/text()").extract()[0].strip()
        item ["like_count"] = hxs.xpath("//em[@class='socialMetaCount likeCountSmall']/text()").extract()[0].strip()
        item ["board_name"] = hxs.xpath("//div[@class='creditTitle']/text()").extract()[0].strip()
        items.append(item)
        return items

这是我的数据处理管道:

from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
from scrapy.contrib.exporter import JsonLinesItemExporter

class JsonLinesExportPipeline(object):

    def __init__(self):
        dispatcher.connect(self.spider_opened, signals.spider_opened)
        dispatcher.connect(self.spider_closed, signals.spider_closed)
        self.files = {}

    def spider_opened(self, spider):
        file = open('%s_items.json' % spider.name, 'w+b')
        self.files[spider] = file
        self.exporter = JsonLinesItemExporter(file)
        self.exporter.start_exporting()

    def spider_closed(self, spider):
        self.exporter.finish_exporting()
        file = self.files.pop(spider)
        file.close()

    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

当我使用命令“scrapy crawl pinterest”时,得到的输出是这个JSON文件:

"pin_link": "/pin/94716398388365841/", "board_name": "Outdoor Fun", "like_count": "14", "repin_count": "94"}

这正是我想要的输出,但我只从一个图钉那里得到了数据,而不是从页面上的所有图钉。我花了很多时间在网上找类似的问题,但没有找到相同的情况。你们觉得哪里出错了呢?提前谢谢!

补充:哦,我想可能是因为在strip函数前面加了[0]?抱歉,我刚意识到这可能是问题所在……

补充:嗯,这并不是问题。我很确定这和strip函数有关,但我似乎无法正确使用它来获取多个图钉的数据。这个问题的解决方案可能和这个问题有关吗?:Scrapy:为什么提取的字符串是这个格式?我看到有些内容重叠,但我不知道该怎么用。

补充:好的,当我把爬虫修改成这样:

from scrapy.spider import Spider
from scrapy.selector import Selector
from Pinterest.items import PinterestItem

class PinterestSpider(Spider):
name = "pinterest"
allowed_domains = ["pinterest.com"]
start_urls = ["http://www.pinterest.com/llbean/pins/"]

def parse(self, response):
    hxs = Selector(response)
    sites = hxs.xpath("//div[@class='pinWrapper']")
    items = []
    for site in sites:
        item = PinterestItem()        
        item ["pin_link"] = site.select("//div[@class='pinHolder']/a/@href").extract()[0].strip()
        item ["repin_count"] = site.select("//em[@class='socialMetaCount repinCountSmall']/text()").extract()[0].strip()
        item ["like_count"] = site.select("//em[@class='socialMetaCount likeCountSmall']/text()").extract()[0].strip()
        item ["board_name"] = site.select("//div[@class='creditTitle']/text()").extract()[0].strip()
        items.append(item)
    return items

它确实给了我几行输出,但看起来都是相同的信息,所以它爬取了页面上图钉的数量,但输出的内容都是一样的:

{"pin_link": "/pin/94716398388371133/", "board_name": "Take Me Fishing", "like_count": "3", "repin_count": "21"}
{"pin_link": "/pin/94716398388371133/", "board_name": "Take Me Fishing", "like_count": "3", "repin_count": "21"}
{"pin_link": "/pin/94716398388371133/", "board_name": "Take Me Fishing", "like_count": "3", "repin_count": "21"}
{"pin_link": "/pin/94716398388371133/", "board_name": "Take Me Fishing", "like_count": "3", "repin_count": "21"}

等等。

1 个回答

3

我没有用过Scrapy,所以这只是我的猜测。

你的选择器返回了多个结果。然后你从每个列表中选择第一个值(用切片 [0]),这样就创建了一个叫 item 的单个 PinterestItem,然后把它添加到 items 列表中,最后返回这个列表。看起来并没有对选择器返回的所有可能结果进行循环处理。

所以你应该先提取出所有的结果,然后遍历这些结果来创建你的 items 列表:

def parse(self, response):
    hxs = Selector(response)
    pin_links = hxs.xpath("//div[@class='pinHolder']/a/@href").extract()
    repin_counts = hxs.xpath("//em[@class='socialMetaCount repinCountSmall']/text()").extract()
    like_counts = hxs.xpath("//em[@class='socialMetaCount likeCountSmall']/text()").extract()
    board_names = hxs.xpath("//div[@class='creditTitle']/text()").extract()

    items = []
    for pin_link, repin_count, like_count, board_name in zip(pin_links, repin_counts, like_counts, board_names):
        item = PinterestItem()
        item["pin_link"] = pin_link.strip()
        item["repin_count"] = repin_count.strip()
        item["like_count"] = like_count.strip()
        item["board_name"] = board_name.strip()
        items.append(item)
    return items

撰写回答