出了什么问题
首先,让我们看看您的代码中发生了什么。这是你的循环:
@dl_page = []
(1..2).each do |page|
@dl_page << [ `(curl --url "https://angel.co/video?page=#{page}&sort=joined" -H "X-Requested-With: XMLHttpRequest")` ]
@result = "#{@dl_page.join}"
end
假设您的 curl 命令第一次返回一个有效的 JSON 对象,例如 {"html":"foo"},第二次返回 {"html":"bar"}。让我们展开你的循环:
@dl_page = []
# First iteration
@dl_page << [ '{"html":"foo"}' ]
# => [ [ '{"html":"foo"}' ] ]
@result = @dl_page.join
# => '{"html":"foo"}'
请注意,由于您使用 << 运算符将数组 ([ '{"html":"foo"}' ]) 附加到 @dl_page,因此 @dl_page 现在是一个具有单个元素的数组,它本身就是一个具有单个元素的数组。这可能不是你想要的。您可能想要的只是将 JSON 字符串本身附加到数组中,即@dl_page << '{"html":"foo"}'。
另请注意,我将"#{@dl_page.join}" 替换为@dl_page.join。 "#{foo}" 从来没有必要。 #{...} 用于字符串插值,这里没有插值,Array#join 返回一个字符串,所以上面完全等价于@result = @dl_page.join。
docs for Array#join 有点模糊,但事实证明[ [ '{"html":"foo"}' ] ].join 只是返回'{"html":"foo"}'。
正如您所发现的,如果您在此停止并使用JSON.load,它会起作用,因为@result 是一个有效的 JSON 对象。让我们找出为什么在第二次迭代之后不再是这种情况:
# Second iteration
@dl_page << [ '{"html":"bar"}' ]
# => [ [ '{"html":"foo"}' ], [ '{"html":"bar"}' ] ]
@result = @dl_page.join
# => '{"html":"foo"}{"html":"bar"}'
现在@dl_page 是一个包含两个元素的数组,每个元素本身就是一个包含一个元素的数组。当您调用 @dl_page.join 时,结果是两个 JSON 对象相互混合在一起。显然这是无效的,所以JSON.load 失败了。
如何解决
您有一些表面问题,例如将数组附加到 @dl_page 而不仅仅是单个元素,以及在循环内执行 @result = ... 而实际上您只需要在循环之后执行一次。这些都是值得解决的问题。
然而,这里真正的问题是你试图将两个 JSON 字符串转换为一个 JSON 字符串然后解析它,而你应该分别解析每个 JSON 字符串:
@result = []
(1..2).each do |page|
json = `curl --url "https://angel.co/video?page=#{page}&sort=joined" -H "X-Requested-With: XMLHttpRequest"`
@result << JSON.parse(json)
end
再次假设curl系统调用第一次返回{"html":"foo"},第二次返回{"html":"bar"},现在@result的值将是一个包含两个元素的数组,每个元素都是一个Ruby哈希:
p @result
# => [ { "html" => "foo" }, { "html" => "bar" } ]
如果您只想要 "html" 键的值,您可以这样做:
@result = []
(1..2).each do |page|
json = `(curl --url "https://angel.co/video?page=#{page}&sort=joined" -H "X-Requested-With: XMLHttpRequest")`
@result << JSON.parse(json)["html"]
end
现在@result 的值将是一个包含两个字符串的数组:
p @result
# => ["foo", "bar"]
不过,我们仍然可以做得更好。在 Ruby 中,通常情况下,如果您在循环外创建一个空对象,然后在循环内向该对象添加内容,您应该改用 Enumerable#map 或 Enumerable#reduce:
@result = (1..2).map do |page|
json = `curl --url "https://angel.co/video?page=#{page}&sort=joined" -H "X-Requested-With: XMLHttpRequest"`
JSON.parse(json)["html"]
end
p @result
# => ["foo", "bar"]