【问题标题】:URI.open fails getting reddit JSON (error 429)URI.open 无法获取 reddit JSON(错误 429)
【发布时间】:2021-10-06 11:11:55
【问题描述】:

我正在尝试使用 Ruby 从 subreddit 中获取一些 JSON 数据;但它失败了,返回一个 429 错误。

  begin
    request = URI.open(
      'https://www.reddit.com/r/vintageobscura.json',
      {
      "User-Agent"=>"web:myapp:v1.0.0 (by /u/myusername)"
      }
    );
  rescue OpenURI::HTTPError => error
    response = error.io
    raise StandardError.new sprintf('Error while opening document: %s',response.status)
    #puts response.string
  end
end

当我在浏览器中加载 URL 时它可以工作;如您所见,我根据他们的API rules 定义了一个用户代理。

知道失败的原因吗?

非常感谢!

【问题讨论】:

  • 429 表示“请求过多”——您可能超出了他们的速率限制。监控 API 规则中提到的 X-Ratelimit HTTP 标头。
  • @Stefan 不确定这是不是问题,因为它可以在我的浏览器中运行...?
  • X-Ratelimit 标头说什么,您是否超出限制?
  • 很抱歉,我该如何检查呢?

标签: json ruby api reddit http-status-code-429


【解决方案1】:

HTTP 429 表示请求过多。 Reddit API 限制客户端、爬虫和爬虫。

您可以使用三个响应标头来检查速率限制状态。这里是the documentation

  • X-Ratelimit-Used:此期间使用的大约请求数
  • X-Ratelimit-Remaining:剩余的大约请求数
  • X-Ratelimit-Reset:到周期结束的大约秒数
require "open-uri"

URI.open(
  'https://www.reddit.com/r/vintageobscura.json',
  "User-Agent"=>"web:myapp:v1.0.0 (by /u/myusername)"
) { |f| pp f.meta }

# {
#   "x-ratelimit-remaining"=>"289",
#   "x-ratelimit-used"=>"11",
#   "x-ratelimit-reset"=>"125",
#   ...
# }

Shopify/limiter gem 可以帮助您的代码在再次请求后等待一段时间。或者您可以使用标头自行实现此等待机制。

【讨论】:

    【解决方案2】:

    对于任何感兴趣的人,我最终都使用了 oAuth 并每次都请求一个令牌。 可能会有所改进,但它可以工作:

    def get_access_token()
      puts "getting reddit access token"
      begin
        resp = RestClient::Request.execute(
          method: :post,
          url: 'https://www.reddit.com/api/v1/access_token',
          user: @client_id,
          password: @client_secret,
          payload: 'grant_type=client_credentials'
        )
        response = JSON.parse(resp.body)
        response['access_token']
      rescue StandardError => e
        raise StandardError.new 'Error getting Reddit OAuth2 token.'
      end
    end
    
    def get_json(subreddit_slug){
      
      url = sprintf('https://oauth.reddit.com/r/%s.json',subreddit_slug);
    
      token = get_access_token()
      
      options=>{
        'Authorization' => "Bearer #{token}",
        "User-Agent" => "ruby:#{APP_NAME}:v#{APP_VERSION} (by /u/#{REDDIT_USER})"
      }
      request = URI.open(url,options);
      request.read
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-22
      • 2018-02-24
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-18
      • 2013-12-03
      相关资源
      最近更新 更多