14
Help us understand the problem. What are the problem?

posted at

updated at

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

スクレイピングして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)

    p @shops
  end
end

確認したい場合は、app配下直に置いて、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 = set_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], [set_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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
14
Help us understand the problem. What are the problem?