12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GeekSalonAdvent Calendar 2022

Day 19

【Rails】Mechanizeを利用して、サイトの情報を取得して表示する方法【スクレイピング】

Last updated at Posted at 2022-12-20

1:概要

railsでスクレイピングでhtml情報を取得し、欲しい要素を抽出して自サイトに表示させる方法を紹介していきたいと思います。

スクレイピングとはWebやデータベースを広く探って「データを抽出する手法」のことです。
Mechanizeというgemを使った方法を紹介していきたいと思います。

今回は2種類ご紹介したいと思います
①Qiitaのトレンド記事の見出しを取得し、リンク付きで表示する方法
https://craftgawker.com/(手作り作品投稿サイト)から写真を取得し表示させる方法

完成図イメージ


image.png


image (2).png

前提

コントローラー名はtweets,アクション名はhomeで記述しています。

開発環境
ruby 2.7.3
rails 6.1.6

2:実装

2-1 一般的な実装方法

1 gem「mechanize」をインストールする

まずはスクレイピングを簡単にしてくれるGem、mechanizeをインストールしていきます。

Gemfile
gem 'mechanize'
ターミナル
bundle install

公式はこちら

2 Mechanizeクラスのインスタンスを生成し、ページから情報を取得してインスタンス変数に代入する
tweets_controller.rb
    def home
        agent = Mechanize.new
        page = agent.get("URL名")
        @elements = page.search('要素名')
    end

agent = Mechanize.new
ここでまずMechanizeクラスをインスタンス化しています。
インスタンス化とは、Classの定義を元に新たな変数を作成することです。Mechanizeを使えるように定義し直した、と思ってもらえたら大丈夫です。
page = agent.get("URL名")
Mechanizeクラスのgetメソッドを使ってHTML情報を取得しています。
@elements = page.search('要素名')
上で取得したHTML情報から、searchメソッドを使って要素を取得し、インスタンス変数に代入しています。
要素名の部分には、クラス名やID名などが入ります。CSSのセレクターの取得と同じです。

3 Viewページで表示する
home.html.erb
<% @elements.each do |ele| %>
  <%= ele %>
<% end %>

@elementsには戻り値が配列として入っているため、eachメソッドを使用して表示します。
inner_textメソッドや、get_attributeメソッドを利用することで、表示方法を選ぶことが出来ます。(後述)

2-2 Qiitaのトレンド記事の見出しを取得し、リンク付きで表示する

ここからは実際のWebページを取得していこうと思います。まずはQiitaのトレンド記事から。
gem「mechanize」は導入済みとします。

コントローラー記入

tweets_controller.rb
    def home
        agent = Mechanize.new
        page_qiita = agent.get("https://qiita.com/")
        @qiita = page_qiita.search('.css-skov52 a')
    end

取得したい要素のセレクタ名を探すには、検証ツールを利用します。

image.png

タイトル部分をみると、css-skov52というクラス名の中のaタグだとわかるので、このように記入できます。

viewページ記入

home.html.erb
<% @qiita.each do |qiita| %>
      <p><%=link_to(qiita.inner_text,qiita[:href])%></p>
<% end %>

これで表示することが出来ます。

解説

each doの中にそのまま以下のように書くと

<%= qiita %>

以下のように表示されてしまいます。

<a href="https://qiita.com/ken1041/items/49417edd50536a397318" class="css-11rvgoz">ワンランク上のSQLを書くためのポイント3つ</a>

ここからテキスト情報、hrefの中のリンクを取得していきます。

inner_textメソッド

タグ内のテキストを取得することが出来ます。

home.html.erb
<% @qiita.each do |qiita| %>
      <p><%= qiita.inner_text %></p>
<% end %>

表示↓

ワンランク上のSQLを書くためのポイント3つ

get_attributeメソッド

タグの持つ属性値を取得する際に使用します。つまり、href属性の値を取得できます。

正式に書くとqiita.get_attribute('href')ですが、
省略してqiita[:href]と書くことが出来ます。

home.html.erb
<% @qiita.each do |qiita| %>
      <p><%= qiita[:href] %></p>
<% end %>

表示↓

https://qiita.com/ken1041/items/49417edd50536a397318

この2つのメソッドを利用して、link_toに代入すれば、タイトルとリンク付きで表示することが出来ます。

2-3 手作り作品投稿サイトから写真を取得し表示させる方法

次に、たくさんの写真が並んでいる以下のサイトから、写真情報を取得して、同じように写真で表示させる方法を紹介していきます。

コントローラー記入

tweets_controller.rb
    def home
        agent = Mechanize.new
        page_craft = agent.get("https://craftgawker.com/")
        @img = page_craft.search('img')
    end

画像要素をもってくるため、要素名にはimgと記入します。

viewページ記入

home.html.erb
<% @img.each do |i| %>
      <%= image_tag i[:src] ,size: '275x275'%>
<% end %>

そのままだと<img src="//photo2.craftgawker.com/wp-content/uploads/craft/2022/12/480365.jpg" width="275" height="275" alt="Christmasとなるため、get_attributeメソッドを利用してsrc属性の値を取得し、image_tagに代入し、サイズを調整するときれいに表示されます。

ちなみにrailsのためimage_tagを利用しておりますが、

<img src="<%= i[:src]%>" width="275" height="275">

と書いても同じように表示できます。

3:おわりに

これを利用すれば色んなサイトから情報をとってきて表示することができます!ワクワクしますね😊
著作権などもあるので、そこには気をつけてください!

ちなみにコントローラーの記述において、searchメソッドでは該当要素すべてを取得しますが、atメソッドを利用すると該当1件のみを取得することができます。

参考記事

Railsでスクレイピング Mechanizeの基礎
【Rails】mechanizeを使えばrailsスクレイピングが余裕な件
【rails】スクレイピングの実装方法

12
4
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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?