【问题标题】:Scrapy - Creating nested JSON ObjectScrapy - 创建嵌套的 JSON 对象
【发布时间】:2017-12-22 19:26:45
【问题描述】:

我正在学习如何使用 Scrapy,同时刷新我的 Python 知识?/从学校编码。

目前,我正在使用 imdb top 250 列表,但在处理 JSON 输出文件时遇到了困难。

我当前的代码是:

 # -*- coding: utf-8 -*-
import scrapy

from top250imdb.items import Top250ImdbItem


class ActorsSpider(scrapy.Spider):
    name = "actors"
    allowed_domains = ["imdb.com"]
    start_urls = ['http://www.imdb.com/chart/top']

    # Parsing each movie and preparing the url for the actors list
    def parse(self, response):
        for film in response.css('.titleColumn'):
            url = film.css('a::attr(href)').extract_first()
            actors_url = 'http://imdb.com' + url[:17] + 'fullcredits?ref_=tt_cl_sm#cast'
            yield scrapy.Request(actors_url, self.parse_actor)

    # Finding all actors and storing them on item
    # Refer to items.py
    def parse_actor(self, response):
        final_list = []
        item = Top250ImdbItem()
        item['poster'] = response.css('#main img::attr(src)').extract_first()
        item['title'] = response.css('h3[itemprop~=name] a::text').extract()
        item['photo'] = response.css('#fullcredits_content .loadlate::attr(loadlate)').extract()
        item['actors'] = response.css('td[itemprop~=actor] span::text').extract()

        final_list.append(item)

        updated_list = []

        for item in final_list:
            for i in range(len(item['title'])):
                sub_item = {}
                sub_item['movie'] = {}
                sub_item['movie']['poster'] = [item['poster']]
                sub_item['movie']['title'] = [item['title'][i]]
                sub_item['movie']['photo'] = [item['photo']]
                sub_item['movie']['actors'] = [item['actors']]
                updated_list.append(sub_item)
            return updated_list

我的输出文件给了我这个 JSON 组合:

[
  {
    "movie": {
      "poster": ["https://images-na.ssl-images-amazon.com/poster..."], 
      "title": ["The Shawshank Redemption"], 
      "photo": [["https://images-na.ssl-images-amazon.com/photo..."]], 
      "actors": [["Tim Robbins","Morgan Freeman",...]]}
    },{
    "movie": {
      "poster": ["https://images-na.ssl-images-amazon.com/poster..."], 
      "title": ["The Godfather"], 
      "photo": [["https://images-na.ssl-images-amazon.com/photo..."]], 
      "actors": [["Alexandre Rodrigues", "Leandro Firmino", "Phellipe Haagensen",...]]}
  }
]

但我希望实现这一目标:

{
  "movies": [{
    "poster": "https://images-na.ssl-images-amazon.com/poster...",
    "title": "The Shawshank Redemption",
    "actors": [
      {"photo": "https://images-na.ssl-images-amazon.com/photo...",
      "name": "Tim Robbins"},
      {"photo": "https://images-na.ssl-images-amazon.com/photo...",
      "name": "Morgan Freeman"},...
    ]
  },{
    "poster": "https://images-na.ssl-images-amazon.com/poster...",
    "title": "The Godfather",
    "actors": [
      {"photo": "https://images-na.ssl-images-amazon.com/photo...",
      "name": "Marlon Brando"},
      {"photo": "https://images-na.ssl-images-amazon.com/photo...",
      "name": "Al Pacino"},...
    ]
  }]
}

在我的 items.py 文件中,我有以下内容:

import scrapy


class Top250ImdbItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # Items from actors.py
    poster = scrapy.Field()
    title = scrapy.Field()
    photo = scrapy.Field()
    actors = scrapy.Field()
    movie = scrapy.Field()
    pass

我知道以下几点:

  1. 我的结果没有按顺序出现,网页列表中的第一部电影始终是我输出文件中的第一部电影,但其余的不是。我仍在努力。

  2. 我可以做同样的事情,但使用 Top250ImdbItem(),仍然浏览如何以更详细的方式完成。

  3. 这可能不是我的 JSON 的完美布局,欢迎提出建议,如果是,请告诉我,即使我知道没有完美的方法或“唯一的方法”。

  4. 有些演员没有照片,它实际上加载了不同的 CSS 选择器。目前,我想避免使用“无图片缩略图”,因此可以将这些项目留空。

示例:

{"photo": "", "name": "Al Pacino"}

【问题讨论】:

  • 不要使用(scrapy.Item) 使用dict 并以movies:[] 开头。
  • 嘿,@stovfl 你能详细说明一下吗?

标签: python arrays json nested scrapy


【解决方案1】:

问题:......在 JSON 输出文件中苦苦挣扎


注意:不能使用你的ActorsSpider,得到错误:不支持伪元素

# Define a `dict` **once**
top250ImdbItem = {'movies': []}

def parse_actor(self, response):
    poster = response.css(...
    title = response.css(...
    photos = response.css(...
    actors = response.css(...

    # Assuming List of Actors are in sync with List of Photos
    actors_list = []
    for i, actor in enumerate(actors):
        actors_list.append({"name": actor, "photo": photos[i]})

    one_movie = {"poster": poster,
                 "title": title,
                 "actors": actors_list
                }

    # Append One Movie to Top250 'movies' List
    top250ImdbItem['movies'].append(one_movie)

【讨论】:

  • 好的,我会检查一下,你不能运行它有点奇怪,我实际上仍在使用完全相同的代码,我也会检查这个问题并更新看看你是否可以运行它,我会尝试这些建议,实际上照片和演员还没有同步,仍在弄清楚如何做,但你的帮助实际上很棒。
  • 我应该在此处将修改后的工作代码作为评论发布,编辑当前代码还是保持原样?
  • Edit您的问题并仅添加更改的部分
猜你喜欢
  • 1970-01-01
  • 2017-02-14
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 2018-12-29
相关资源
最近更新 更多