Ruby 调用谷歌搜索 API:net/http 与 json 标准库实战

Ruby 做脚本和小工具依然顺手,而且这篇的客户端只用标准库——net/http 加 json,连 gem 都不用装,ruby serp_client.rb 直接跑。适合给运维脚本、Sidekiq 任务或任意老项目里加一个搜索数据源。

客户端代码

# serp_client.rb
require 'net/http'
require 'json'
require 'uri'

class SerpClient
  API_URL = URI('https://api.serpbase.dev/google/search')

  def initialize(api_key)
    @api_key = api_key
  end

  # 信封:status 为 0 表示成功;失败时 error 带原因、credits_charged 为 0(不扣费)
  def search(q, hl: 'en', gl: 'us', page: 1)
    body = { q: q, hl: hl, gl: gl, page: page }.to_json

    http = Net::HTTP.new(API_URL.host, API_URL.port)
    http.use_ssl = true
    http.open_timeout = 10
    http.read_timeout = 30

    resp = http.post(API_URL.path, body,
      'X-API-Key'    => @api_key,
      'Content-Type' => 'application/json')

    data = JSON.parse(resp.body)
    if data['status'] != 0
      raise SerpApiError.new(data['status'], data['error'])
    end
    data
  end

  class SerpApiError < StandardError
    attr_reader :code
    def initialize(code, message)
      @code = code
      super("SERP API error #{code}: #{message}")
    end
  end
end

# 用法
client = SerpClient.new(ENV['SERPBASE_API_KEY'])
data = client.search('mechanical keyboard review')

data['organic'].each do |r|
  puts format('%3d  %s', r['rank'], r['title'])
  puts "     #{r['link']}"
end

信封结构、参数表(q/hl/gl/page/device)与 organic 字段定义以 SerpBase 官方文档 为准;rank 是本页内的 1 起算位次,titlelink 是每条必有字段,snippetdisplay_url 等为可选——取值前用 r['snippet'] 拿到的是 nil 也别当异常处理。

错误分诊表

信号含义动作
SerpApiError 1001key 缺失/无效不重试,查配置
SerpApiError 1020余额不足告警,人工充值
SerpApiError 1029触发限流指数退避重试,最多 3 次
Net::OpenTimeout / Net::ReadTimeout连接/读取超时重试一次,再失败记日志
JSON::ParserError响应非 JSON记录原始响应前 200 字符

计费口径:search 端点每次成功请求 1 credit;100 次免费试用够在开发环境把这个类调稳,标准包 $0.50/1k 起。

三个 Ruby 特有的坑

  1. Net::HTTPuse_ssl = true:https 地址忘了这行会直接报 use_ssl 错误;URI.parse 不会自动开。把 open/read 超时显式设置,默认值在网络抖动时偏长。
  2. data['status'] 的类型:JSON 里数字就是 Integer,直接 != 0 判断即可;但如果哪天信封升级成字符串,'0' != 0 会误报——防御性写法是 data['status'].to_i != 0
  3. 别忘了键是字符串:JSON.parse 默认返回字符串键的 Hash,data[:organic] 永远是 nil,要写 data['organic'];装 symbolize_names: true 参数也行,但团队统一一种风格更重要。

FAQ

为什么不装 httparty 或 faraday? 一个 POST 接口用不上它们;标准库版零依赖,扔进任何项目都不会引起 gem 冲突。等第二个接口出现再抽公共模块不迟。

怎么翻页? search(q, page: 2),page 从 1 起;organic 为空或与上页重复就停。

PAA、相关搜索怎么拿? 返回里是可选模块:data['people_also_ask']data['related_searches'],用 data.fetch('related_searches', []) 兜底遍历;字段结构以实际返回和文档为准,先原样存 JSON 再建模。

serp_client.rb 放进 lib/,配一行环境变量,Rake 任务和 cron 脚本里就都能拿结构化搜索结果了。

数据说明:源数据来自王晓磊博士提供的全国空气质量监测数据。经过数据清洗,制作成分城市、分站点、按指标存储的小时浓度监测数据,如果需要其他城市、站点、指标数据可以站内消息联系本人。 内容概要:本文档记录了北京市2015年部分日期每小时的PM2.5浓度监测数据,时间跨度从1月到12月的部分时段,数据以“年月日 时 PM2.5值”的格式呈现,数值单位为微克/立方米(μg/m³),部分时间段存在缺失值(用NaN表示)。数据反映了北京在不同季节、不同时段的空气质量变化情况,包括污染高峰期(如冬季)和较为清洁时段(如夏季),部分数据显示PM2.5浓度严重超标,达到300以上,属于重度或严重污染级别。; 适合人群:环境科学研究人员、空气质量数据分析人员、气象学爱好者、公共卫生政策制定者以及关注城市空气污染问题的社会公众。; 使用场景及目标:①用于分析北京2015年PM2.5浓度的时间变化趋势周期性特征;②支持空气质量建模、污染源追踪及健康风险评估研究;③作为教学案例帮助学生理解大气污染物的时间序列特性;④辅助政府机构制定雾霾治理措施并评估其效果。; 阅读建议:此数据为原始时间序列记录,使用前应进行数据清洗(处理NaN值)、时间对齐和统计分析,建议结合气象数据(如风速、湿度)和地理信息综合解读,以便更准确地识别污染成因传播规律。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值