Подтвердить что ты не робот

Почему я получаю "неявное преобразование String в Integer (TypeError)"?

У меня есть код, который я запускаю в очень похожих обстоятельствах. Это первое обстоятельство, когда у меня есть imdb_id фильма, который я хочу получить:

url = "http://mymovieapi.com/?id=#{self.imdb_id}&type=json&plot=none&episode=0&lang=en-US&aka=simple&release=simple&business=0&tech=0"
doc = Hpricot(open(url)).to_s
json = JSON.parse(doc)

puts json
puts json["imdb_id"]

И это дает следующий результат:

{"rating_count"=>493949,
"genres"=>["Drama", "Romance"],
"rated"=>"PG-13",
"language"=>["English", "French", "German", "Swedish", "Italian", "Russian"],
"rating"=>7.6,
"country"=>["USA"],
"release_date"=>19980403,
"title"=>"Titanic",
"year"=>1997,
"filming_locations"=>"Santa Clarita, California, USA",
"imdb_id"=>"tt0120338",
"directors"=>["James Cameron"],
"writers"=>["James Cameron"],
"actors"=>["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher", "Gloria Stuart", "Bill Paxton", "Bernard Hill", "David Warner", "Victor Garber", "Jonathan Hyde", "Suzy Amis", "Lewis Abernathy", "Nicholas Cascone", "Anatoly M. Sagalevitch"],
"also_known_as"=>["Tai tan ni ke hao"],
"poster"=>{"imdb"=>"http://ia.media-imdb.com/images/M/[email protected]@._V1_SY317_CR0,0,214,317_.jpg", "cover"=>"http://imdb-poster.b0.upaiyun.com/000/120/338.jpg!cover?_upt=66ac07591382594194"},
"runtime"=>["194 min"],
"type"=>"M",
"imdb_url"=>"http://www.imdb.com/title/tt0120338/"}

tt0120338

Это так, как ожидалось. Во втором случае у меня есть title и year той же пленки:

url = "http://mymovieapi.com/?title=#{self.title}&type=json&plot=simple&episode=0&limit=1&year=#{self.year}&yg=1&mt=none&lang=en-US&offset=&aka=simple&release=simple&business=0&tech=0"
doc = Hpricot(open(url)).to_s
json = JSON.parse(doc)

puts json
puts json["imdb_id"]

Из этого я получаю точно такой же вывод JSON:

{"rating_count"=>493949,
"genres"=>["Drama", "Romance"],
"rated"=>"PG-13", "language"=>["English", "French", "German", "Swedish", "Italian", "Russian"],
"rating"=>7.6,
"country"=>["USA"],
"release_date"=>19980403,
"title"=>"Titanic",
"year"=>1997,
"filming_locations"=>"Santa Clarita, California, USA",
"imdb_id"=>"tt0120338",
"directors"=>["James Cameron"],
"writers"=>["James Cameron"],
"actors"=>["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher", "Gloria Stuart", "Bill Paxton", "Bernard Hill", "David Warner", "Victor Garber", "Jonathan Hyde", "Suzy Amis", "Lewis Abernathy", "Nicholas Cascone", "Anatoly M. Sagalevitch"],
"also_known_as"=>["Tai tan ni ke hao"],
"poster"=>{"imdb"=>"http://ia.media-imdb.com/images/M/[email protected]@._V1_SY317_CR0,0,214,317_.jpg",
"cover"=>"http://imdb-poster.b0.upaiyun.com/000/120/338.jpg!cover?_upt=ec8bdec31382594417"},
"runtime"=>["194 min"],
"type"=>"M",
"imdb_url"=>"http://www.imdb.com/title/tt0120338/"}

Но когда я пытаюсь вызвать puts json["imdb_id"], я получаю эту ошибку:

no implicit conversion of String into Integer (TypeError)

Это всегда происходит при извлечении с помощью title и year, но все же кажется необъяснимым, поскольку вывод JSON точно такой же.

4b9b3361

Ответ 1

Из-за исключения, кажется, что json во втором ответе есть массив с только одним элементом, поэтому вывод puts json одинаков (скобки не выводятся с помощью puts), но json["string"] не работает, потому что [] ожидает, что Integer будет использоваться как индекс.

Отметьте p json или json.is_a?(Array), и если это действительно массив, попробуйте json.first['imdb_id'].

Ответ 2

Вот что не так и как его исправить:

  • Вы не получаете HTML обратно, поэтому вам НЕ нужно разбирать HTML. Посмотрите содержимое doc в приведенных ниже примерах. Обратите внимание, что разбор HTML не происходит, и нет необходимости в нем, потому что вы специально запрашиваете ответ JSON: type=json.
  • Первый запрос возвращает один ответ, потому что вы запрашиваете конкретный imdb_id. Вы можете получить только один ответ, так что вы получите только один объект/хэш.
  • Второй запрос возвращает массив ответов, потому что может быть несколько элементов с теми же title и year, хотя это кажется маловероятным. В результате вы должны захватить определенный элемент из возвращаемого массива после разбора JSON. Я использовал first, но ваш пробег может измениться, так как вы можете получить несколько предметов; Вам нужно будет выяснить, какой из них подходит, если вы получаете больше одного.

Вот код:

require 'json'
require 'open-uri'

imdb_id = 'tt0120338'
url = "http://mymovieapi.com/?id=#{ imdb_id }&type=json&plot=none&episode=0&lang=en-US&aka=simple&release=simple&business=0&tech=0"
doc = open(url).read
doc[0..5] # => "{\"rati"
json = JSON.parse(doc) # => {"rating_count"=>493949, "genres"=>["Drama", "Romance"], "rated"=>"PG-13", "language"=>["English", "French", "German", "Swedish", "Italian", "Russian"], "rating"=>7.6, "country"=>["USA"], "release_date"=>19980403, "title"=>"Titanic", "year"=>1997, "filming_locations"=>"Santa Clarita, California, USA", "imdb_id"=>"tt0120338", "directors"=>["James Cameron"], "writers"=>["James Cameron"], "actors"=>["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher", "Gloria Stuart", "Bill Paxton", "Bernard Hill", "David Warner", "Victor Garber", "Jonathan Hyde", "Suzy Amis", "Lewis Abernathy", "Nicholas Cascone", "Anatoly M. Sagalevitch"], "also_known_as"=>["Tai tan ni ke hao"], "poster"=>{"imdb"=>"http://ia.media-imdb.com/images/M/[email protected]@._V1_SY317_CR0,0,214,317_.jpg", "cover"=>"http://imdb-poster.b0.upaiyun.com/000/120/338.jpg!cover?_upt=7dedce781382606097"}, "runtime"=>["194 min"], "type"=>"M", "imdb_url"=>"http://www.imdb.com/title/tt0120338/"}
json["imdb_id"] # => "tt0120338"

Это возвращает один элемент как ответ JSON. Вы можете видеть это, посмотрев на переменную doc и увидите, что это JSON, а не HTML. Разбор с использованием анализатора JSON возвратил хэш.

url = "http://mymovieapi.com/?title=#{ json['title'] }&type=json&plot=simple&episode=0&limit=1&year=#{ json['year'] }&yg=1&mt=none&lang=en-US&offset=&aka=simple&release=simple&business=0&tech=0"
doc = open(url).read
doc[0..5] # => "[{\"rat"
json = JSON.parse(doc).first # => {"rating_count"=>493949, "genres"=>["Drama", "Romance"], "rated"=>"PG-13", "language"=>["English", "French", "German", "Swedish", "Italian", "Russian"], "rating"=>7.6, "country"=>["USA"], "release_date"=>19980403, "title"=>"Titanic", "year"=>1997, "filming_locations"=>"Santa Clarita, California, USA", "imdb_id"=>"tt0120338", "directors"=>["James Cameron"], "writers"=>["James Cameron"], "actors"=>["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher", "Gloria Stuart", "Bill Paxton", "Bernard Hill", "David Warner", "Victor Garber", "Jonathan Hyde", "Suzy Amis", "Lewis Abernathy", "Nicholas Cascone", "Anatoly M. Sagalevitch"], "plot_simple"=>"A seventeen-year-old aristocrat, expecting to be married to a rich claimant by her mother, falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.", "poster"=>{"imdb"=>"http://ia.media-imdb.com/images/M/[email protected]@._V1_SY317_CR0,0,214,317_.jpg", "cover"=>"http://imdb-poster.b0.upaiyun.com/000/120/338.jpg!cover?_upt=7dedce781382606097"}, "runtime"=>["194 min"], "type"=>"M", "imdb_url"=>"http://www.imdb.com/title/tt0120338/", "also_known_as"=>["Tai tan ni ke hao"]}
json["imdb_id"] # => "tt0120338"

Этот запрос возвратил массив хешей, что разумно. Строка JSON представляет собой массив, который отображается в переменной doc. Разбираем его, а захват только первого элемента позволяет прочитать значение imdb_id.

Опять же, обратите внимание, что нет парсера HTML, и он не нужен. Вы должны посмотреть на данные, о которых вы возвращаетесь, не просто предположить.

Ответ 3

Ошибка должна быть где-то в вашем коде из того, что я могу сказать.

Я установил JSON, который вы дали в качестве вывода для переменной a в IRB: (JSON из вашего второго примера)

1.9.3p194 :043 > a
 => {"rating_count"=>493949, "genres"=>["Drama", "Romance"], "rated"=>"PG-13", "language"=>["English", "French", "German", "Swedish", "Italian", "Russian"], "rating"=>7.6, "country"=>["USA"], "release_date"=>19980403, "title"=>"Titanic", "year"=>1997, "filming_locations"=>"Santa Clarita, California, USA", "imdb_id"=>"tt0120338", "directors"=>["James Cameron"], "writers"=>["James Cameron"], "actors"=>["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher", "Gloria Stuart", "Bill Paxton", "Bernard Hill", "David Warner", "Victor Garber", "Jonathan Hyde", "Suzy Amis", "Lewis Abernathy", "Nicholas Cascone", "Anatoly M. Sagalevitch"], "also_known_as"=>["Tai tan ni ke hao"], "poster"=>{"imdb"=>"http://ia.media-imdb.com/images/M/[email protected]@._V1_SY317_CR0,0,214,317_.jpg", "cover"=>"http://imdb-poster.b0.upaiyun.com/000/120/338.jpg!cover?_upt=ec8bdec31382594417"}, "runtime"=>["194 min"], "type"=>"M", "imdb_url"=>"http://www.imdb.com/title/tt0120338/"} 

Затем я позвонил:

1.9.3p194 :046 > puts a["imdb_id"]
tt0120338
 => nil 

Это дало мне правильный результат.