ローイングファンのプログラミング日記

ボート競技やプログラミングについて書きます

クローリングで得たデータをデータベースに挿入する

今回はクローリングで得たデータをデータベースに挿入してみる。

目次


準備

PostgreSQLをインストールする

PostgreSQLのWebサイトは以下のとおり。

https://www.postgresql.org/

日本語のサイト

日本PostgreSQLユーザー会
https://www.postgresql.jp/

このブログでもインストール方法や使い方を記事にしている。

Windows10にPostgreSQLをインストールする - ローイングファンの日記

macOS10にPostgreSQLをインストールする - ローイングファンの日記

PostreSQLにデータベースとテーブルをつくる

今回はデータベース名sampledb、テーブル名sampledbsをつくっておく。
データベースとテーブルの作り方は前に書いた。

PostgreSQLのデータベースをつくる - ローイングファンの日記

PostgreSQLにテーブルをつくる - ローイングファンの日記

テーブルの内容は次のとおり。

create_sampledbs.sql

create table sampledbs(
    id serial primary key,
    column1 text,
    column2 text
);


Active Recordをインストールする

Active RecordはBundlerの--pathオプションつきでインストールした。
今回のようにPostgreSQLを操作する場合はPgのインストールも必要。

Active Recordの解説ページは以下のとおり。

Ruby on Rails ガイド
Active Record の基礎
https://railsguides.jp/active_record_basics.html

このブログでもインストールや使い方を何度か記事にしている。

Bundlerを使ってgemをインストールする - ローイングファンの日記

RubyからPostgreSQLを操作する - ローイングファンの日記

Active RecordでPostgreSQLを操作する - ローイングファンの日記

あいまい検索 Active Record where like - ローイングファンの日記

クローリングで得た情報をPostgreSQLに挿入するコード

今回はクローリングにopen-uriライブラリを使う。
コードを書く。

crawl.rb

require 'open-uri'
require 'active_record'

#PostgreSQLに接続
ActiveRecord::Base.establish_connection(
    #項目は環境に応じて書きかえる
    adapter:  "postgresql",
    host:     "",
    username: "Username",
    password: "",
    database: "sampledb"
)

class Sampledb < ActiveRecord::Base
end

#クラスを定義する
class Crawler
    def initialize
        #巡回したいURLを配列に格納する
        @urls = [
            "URL1",
            "URL2",
            "URL3",
        ]
    end

    #crawlで得た情報を配列に格納するまでのメソッドを定義する
    def collector
        collections = []
        @urls.each do |url|
            begin
                open(url,"r:utf-8") do |html|
                    readhtml = html.read
                    scandatas = []
                    s1 = readhtml.scan(/<title>(.*)<\/title>/)
                    s2 = readhtml.scan(/<h1>(.*)<\/h1>/)
                    scandatas << s1 << s2
                    collections << scandatas.flatten
                end
            rescue
                next
            end
            sleep(1)
        end
        collections
    end
end

crawler = Crawler.new
collections = crawler.collector

collections.each do |collection|
    Sampledb.create(
        column1: collection[0],
        column2: collection[1]
    )
end

records = Sampledb.all
records.each do |record|
    puts "s1 => #{record['column1']} : s2 => #{record['column2']}"
end


コードの説明

コードの説明は次のとおり。

  • open-uriとActive Recordをrequireする
  • PostgreSQLに接続する
    • host、passwordは必要に応じて記入する
  • クラスを定義する
    • 初期設定(newメソッド)をinitializeで定義する
      • 巡回したいWebページのURLを配列に格納してインスタンス変数を初期化する
    • HTMLから必要な情報を抽出して配列に格納するメソッドを定義する
      • 全てを収める配列をループの外で初期化しておく
      • URLの入った配列をループさせる
      • ファイル(URL)が開けなかったときに備えてbegin rescueで例外処理を設定する
      • open-uriライブラリのopenメソッドでHTMLを取得する
        • r:utf-8オプションをつけないとHTMLがバイト列になってしまう
      • 抽出するデータを収める配列をループ内で初期化する
      • 抽出したいデータをscanメソッドで抜き取る
      • 抽出したデータを<<メソッドで配列に格納する
      • 抽出したデータが格納された配列を全体を収める配列に格納する
      • rescue節 ファイルが開けなかったときはnextで次のeach(URL)に進む
      • 1秒間sleepしてクローリングの間隔をおく
      • 最後に全体が収まった配列を呼び出しておく
  • 定義したCrawlerクラスのインスタンスをnewメソッドでつくる
  • 定義したcollectorメソッドを実行する
  • collectorメソッドでつくられた配列からeachメソッドでデータを取りだす
    • 取りだしたデータをActive Recordのcreateメソッドでデータベースに挿入していく
  • データベースの全てのレコードをallメソッドで取りだす
  • 全てのレコードをeachメソッドでループして1行ずつputsメソッドで出力していく


補則説明

  • Pgはインストールするだけでrequireは不要
  • ループの外で初期化された配列には要素が蓄積されていき、ループ内で初期化される配列は繰り返しのつど空になる
  • 確認の意味で最後にレコードを出力している


コードの実行

Rubyコードを実行する前にPostgreSQLサーバーを起動しておく。
Active Recordをbundle install --path ...でインストールしている場合はRubyコマンドの前にbundle execコマンドをつける。

ターミナル/PowerShell

bundle exec ruby crawl.rb


ターミナル/PowerShellに出力されれば成功。
scanメソッド部分をアレンジすれば応用が可能。
scanメソッドに合わせてデータベースのテーブルを定義する。
一応うごくけれどクラス定義はうまくない。改善が必要。

今回の動作確認環境

macOS 10.13.4
Ruby 2.4.4p296
ターミナル 2.8.2

Windows10 1709
Ruby 2.5.1p57 [x64-mingw32]
Windows PowerShell 5.1

PostgreSQL 10.3
Active Record 5.2.0
Pg 1.0.0