LoginSignup
21
18

More than 1 year has passed since last update.

Railsのnokogiriでスクレイピングしてactiverecord-importで配列をDBに保存する

Last updated at Posted at 2020-06-28

スクレイピングしてDBに保存したい人向けです

外部からデータ取ってくることに憧れてたので、初めてスクレイピングやった忘備録です。
初めてスクレイピングしたのでおてやわらかにお願いします笑

何をスクレイピングしたの?

paypayのキャンペーンwebページから店舗名を取得しました!
image.png

スクレイピング前のDB

image.png

スクレイピング後のDB

image.png

手順

  1. nokogiriでweb上のテキストを配列形式で取得する
  2. ↑の配列をactiverecord-importで一度のクエリで保存する

環境

  • sqlite3
  • ruby 2.6.3
  • Rails 6.0.2.1
Gemfile.
gem 'activerecord-import'
gem 'nokogiri'

bundle installしといてください!

まずはスクレイピングしてみる

今回はcontrollerから呼び出したかったので、moduleとして作成します。

app/controllers/concerns/paypay_scrapes_concern.rb
module PaypayScrapesConcern
  require 'open-uri'
  require 'nokogiri'

  def scrape_paypay_shops
    url = 'https://paypay.ne.jp/notice/20200604/01/'

    charset = nil
    html = open(url) do |f|
      charset = f.charset
      f.read
    end

    doc = Nokogiri::HTML.parse(html, nil, charset)

    @shops = doc.xpath('//div[@class="article__contents post"]').css('tr').map do |node|
      @shops << node.css("td[1]").text
    end.drop(1)
  end
end

結果を確認してみます。

$ ruby paypay_scrapes_concern.rb

=> ["あさひ", "味千ラーメン 掛川インター店", "遠州屋", "株式会社縁 開縁ダイニング縁や", "大石農場ハム工房", "大手門うおそう", "OZ", "KAKEGAWA 1番地", "掛川グランドホテル", "華月苑", "インド・ネパール料理レストラン GANESHA", "かねきや旅館", "カレー・ザ・ロック", "喜縁旬菜 ZIKAN", "喬菜 まさ吉", "餃子と串カツ 遠州誠家", "串&Bar FuQ(ふく)", "琴菊", "ことのや", "魚処 粋", "椎の木茶屋", "真味楼", "寿し処 八幡", "タナカ", "中国料理四川", "戸塚屋", "巴屋", "ナムズ", "にんちゃんち ", "ひいらぎや", "ファニーファーム", "Food Labo 房’s", "ふらっと", "ベル・エポック", "MAX'S DINER", "まるましらすや", "麺屋 RiQ", "八咫烏", "ラーメン 男前", "らーめん若虎", "LA MAREA 1980 DAN"]

controllerに新しくメソッド追加

shops_controller.rb
def create_paypay_shops
   @shops = scrape_paypay_shops
   shops = []
   @shops.each do |shop|
     shops << Shop.new(name: shop)
   end
   # DBアクセス一回で配列を保存できるgem activerecord-import
   Shop.import shops
 end

こんな感じで保存できると思います。

今後はDBのバリデーションとかもやりたいですね。笑

2021.03.09 追記 Activerecord-importの書き方について

Activerecord-importの公式ドキュメントによると、columns-and-arraysが一番早いそうですね。

shops_controller.rb
def paypay_save
   @shops = scrape_paypay_shops
   shops = []
   @shops.each do |shop|
     shops << Shop.new(name: shop)
   end
   # DBアクセス一回で配列を保存できるgem activerecord-import
   Shop.import shops
end

# ↑をリファクタリングしてみましょう

def paypay_save
  # eachの中でShop.newをしないことでパフォーマンス改善
  Shop.import [:name], [scrape_paypay_shops]
end

重複していたらupdateしたりignoreするコマンドもあるみたいなので試してみてください!

参考

https://morizyun.github.io/blog/ruby-nokogiri-scraping-tutorial/index.html
https://qiita.com/superman9387/items/1981a24664b260e77238
https://qiita.com/makicamel/items/b6d4f3d2661fc66103ed

21
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
18