You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过谷歌地图链接抓取餐厅信息并构建Restaurant对象?

谷歌地图餐厅信息抓取问题及解决方案

问题描述

我正尝试在Rails控制器中编写方法,给定谷歌地图链接后抓取餐厅基础信息并构建Restaurant对象,同时用Active Storage存储抓取到的图片。需要抓取的信息包括:

  • 名称(Name)
  • 地址(Address)
  • 电话(Phone)
  • 网站(Website)
  • 菜系(Cuisine)
  • 价格区间($的数量)
  • 评分(星级数量)
  • 营业时间(Hours)

目前仅尝试获取名称但未成功,现有方法代码如下:

def scrape_google
    google_link = params[:google_link]
    page = Nokogiri::HTML(URI.open(google_link))
  
    @restaurant = Restaurant.new
    
    # Restaurant Name
    restaurant_name_element = page.at_css('h1.DUwDvf.fontHeadlineLarge')
    @restaurant.name = restaurant_name_element&.text&.strip if restaurant_name_element
    
  
    # Output scraped information to the console
    puts "Scraped Information:"
    puts "Name: #{@restaurant&.name}"
    
  
    render :scrape_google
end

问题分析与解决思路

1. 名称抓取失败的核心原因

谷歌地图页面采用动态JavaScript渲染,直接用Nokogiri抓取静态HTML只能拿到初始空页面,无法获取JS执行后生成的实际元素,因此找不到目标CSS选择器对应的内容。

2. 解决方案步骤

(1)改用动态页面抓取工具

使用ferrum(基于Chrome DevTools的轻量工具)获取渲染后的完整页面,替代静态抓取方式:

  • 先在Gemfile添加依赖:gem 'ferrum',执行bundle install
  • 修改控制器方法如下:
def scrape_google
  google_link = params[:google_link]
  browser = Ferrum::Browser.new
  browser.goto(google_link)
  # 等待目标元素加载完成,避免抓取空内容
  browser.wait_for_css('h1.DUwDvf.fontHeadlineLarge')
  page = Nokogiri::HTML(browser.body)
  
  @restaurant = Restaurant.new
  
  # 抓取名称
  restaurant_name_element = page.at_css('h1.DUwDvf.fontHeadlineLarge')
  @restaurant.name = restaurant_name_element&.text&.strip if restaurant_name_element

  # 抓取地址
  address_element = page.at_css('div.Io6YTe.fontBodyMedium')
  @restaurant.address = address_element&.text&.strip if address_element

  # 抓取电话
  phone_element = page.at_css('button.LMNPb span.fontBodyMedium')
  @restaurant.phone = phone_element&.text&.strip if phone_element

  # 抓取网站
  website_element = page.at_css('a.CsEnBe')
  @restaurant.website = website_element&.attribute('href')&.value if website_element

  # 抓取菜系
  cuisine_element = page.at_css('div.kno-rdesc span.rQMQod')
  @restaurant.cuisine = cuisine_element&.text&.strip if cuisine_element

  # 抓取价格区间(统计$的数量)
  price_element = page.at_css('span.HlvSq')
  @restaurant.price_range = price_element&.text&.count('$') if price_element

  # 抓取评分(星级对应的数值)
  rating_element = page.at_css('div.F7nice span.ceNzKf')
  @restaurant.rating = rating_element&.text&.strip if rating_element

  # 抓取营业时间
  hours_element = page.at_css('div.OqCZI')
  @restaurant.hours = hours_element&.text&.strip if hours_element

  # 抓取图片并存储到Active Storage
  image_element = page.at_css('img.THOPZb')
  if image_element
    image_url = image_element.attribute('src').value
    # 下载图片并附加到模型
    @restaurant.image.attach(io: URI.open(image_url), filename: "#{@restaurant.name.parameterize}.jpg")
  end

  puts "Scraped Information:"
  puts "Name: #{@restaurant&.name}"
  puts "Address: #{@restaurant&.address}"

  browser.quit
  render :scrape_google
end

(2)关键注意事项

  • 谷歌地图的CSS选择器可能随时变更,需定期验证更新
  • 频繁抓取可能触发反爬机制,建议添加请求间隔、使用代理IP
  • 确保Restaurant模型已配置Active Storage:has_one_attached :image
  • 优先考虑使用谷歌地图Places API获取结构化数据,合法合规且稳定性更高

内容的提问来源于stack exchange,提问作者BrownKid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:55:13