すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

【ハンズオンワーク】スクレイピングとSlack通知機能を学習しよう!

この記事で出来るようになること

スクレイピング

スクレイピングは、Webサイトに記載されている情報をプログラミングを使って取得する技術のことです。
このカリキュラムでは、Railsの mechanize というgemを活用してスクレイピングの使い方を学習します。

このスクレイピングの章は、以下の手順で進めます。

  1. Railsアプリケーションの作成とGemの導入
  2. スクレイピングを使ってWebページのデータを取得しよう
  3. スクレイピングで取得したデータをDBに挿入しよう

Railsアプリケーションの作成とGemの導入

それでは、このカリキュラムで利用するRailsアプリケーションを作成しましょう。
以下のコマンドを実行して下さい。

ターミナル
1
rails new mechanize_slack_app

次に mechanize という gem をインストールしましょう。

Gemfile に以下を追記して下さい。

Gemfile | mechanizeの導入
1
gem 'mechanize'

Gemfileの追記が終われば、 bundle install を実行し gem を取り入れましょう。

スクレイピングの基本的な使い方

この章では、スクレイピングの基本的な使い方を学びます。

スクレイピングの基本的な使い方は、【Rails】 Mechanizeを使ってスクレイピングをしよう のページを参考にしましょう。

Webページのタイトルの取得

スクレイピングを実装するためのクラスを作成しましょう。

先ほど作成した mechanize_slack_app に移動して、以下のコマンドを打ち込んで下さい。

1
touch lib/web_scraper.rb

作成した web_scraper.rb に以下の内容を入力して下さい。

1
2
3
4
5
6
7
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end
end

まず rails c のコマンドを使い、rails consoleを立ち上げましょう。

1
rails c

コンソールに以下を入力して、Pikawakaサイトのサイトタイトルを取得できれば完了です。

1
2
irb(main):001> WebScraper.get_title('https://pikawaka.com')
=> "Pikawaka - ピカ1わかりやすいプログラミング用語サイト"
指定したWebページのタイトルを取得しよう

それでは get_title メソッドを使用して、任意のWebサイトを三つ選び、タイトルを取得しましょう。

タイトルの取得方法は Webページのタイトルの取得方法の参考ページ を参考にして下さい。

Webページに記載されている指定した要素のテキストを取得

次にWebページに記載されている指定した要素のテキストを取得します。要素 を指定するには searchメソッド を使い、要素のテキストを取得するには inner_textメソッド を使用します。

指定した要素のテキストの取得方法の例として、h1要素のテキストを取得するメソッドを作ってみましょう。

web_scraper.rb | 指定した要素のテキストの取得方法の例
1
2
3
4
5
6
7
8
9
10
11
12
13
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end

def self.get_h1_text(url)
agent = Mechanize.new
page = agent.get(url)
page.search('h1').inner_text
end
end
指定したWebページのh1のテキストを取得しよう

get_h1_text を活用し、任意のWebサイトを三つ選び、それぞれのサイトのh1のテキストを取得しましょう。

※ h1を設定していないサイトに関しては、空文字が取得されます。

「任意の要素をテキスト」を取得するメソッドを作成しよう

次に特定のページの「任意の要素をテキスト」を取得するメソッドを作成しましょう。

例えば、以下の画像を見るとPikawakaトップページのサイドバーにあるカテゴリーは c-sidebar__article-title クラスの要素の中の a 要素で取得できることが分かります。

特定のページの任意の要素をテキスト

「Pikawaka」という特定のページのサイドバーにあるカテゴリーの全てをテキストを取得するには、以下のようなメソッドを作成する必要があります。以下のメソッドを web_scraper.rb に追記して下さい。

web_scraper.rb | 指定した要素のテキストの取得方法の例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end

  def self.get_h1_text(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.search('h1').inner_text
  end

def self.get_pikawaka_sidebar_category_texts
agent = Mechanize.new
page = agent.get('https://pikawaka.com')
texts = []
page.search('.c-sidebar__article-title', 'a').each do |element|
texts << element.inner_text
end
puts texts
end
end

メソッドを実行し、以下のように表示されていることを確認して下さい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
irb(main):026> WebScraper.get_pikawaka_sidebar_category_texts

変換系メソッド

繰り返し処理

初学者向けのRuby入門

初級者向け用語・メソッド一覧

便利な組み込みクラスのメソッド

中級者になる為の用語・メソッド一覧

図解で理解するRuby用語一覧

知っておきたいヘルパーメソッド
...
特定のWebページの任意のテキストを取得しよう

get_pikawaka_sidebar_category_texts のように特定のWebページの任意のテキストを取得するメソッドを作成しましょう。

get_サイト名_コンテンツ名_texts の命名規則に従ってメソッドを作成して下さい。コンソールでメソッドを実行し、テキストを取得できているか確認して下さい。

指定した属性値を取得

次は属性値を取得する方法を学びます。まず a タグの href という属性値を取得する方法について学習します。

属性値の取得に関しては、こちらのサイトを参考にして下さい。

a タグの href という属性に https://pikawaka.com を入れた場合、以下のような表記になります。

<a href="https://pikawaka.com" target="_blank">https://pikawaka.com</a>

この要素の href 属性の値を取得するには、以下のように記述します。

1
2
a要素.get_attribute('href')
=> https://pikawaka.com

このようにaタグであれば href 属性を指定することで、aタグに設定されているリンクを取得できます。
imgタグであれば、 src 属性を指定することで、画像urlを取得できます。

それでは、以下のように「特定のページのサイドバーにあるカテゴリーのリンク」を全て取得するメソッドを追記しましょう。

web_scraper.rb | 指定した要素のテキストの取得方法の例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end

  def self.get_h1_text(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.search('h1').inner_text
  end

  def self.get_pikawaka_sidebar_category_texts
    agent = Mechanize.new
    page = agent.get('https://pikawaka.com')
    texts = []
    page.search('.c-sidebar__article-title', 'a').each do |element|
      texts << element.inner_text
    end

    puts texts
  end

def self.get_pikawaka_sidebar_category_links
url = 'https://pikawaka.com'
agent = Mechanize.new
page = agent.get(url)
links = []
page.search('.c-sidebar__article-title', 'a').each do |element|
link = element.get_attribute('href')
links << url + link if link.present?
end
puts links
end
end

メソッドを実行し、以下のように表示されていることを確認して下さい。

1
2
3
4
5
6
7
8
9
10
11
irb(main):026> WebScraper.get_pikawaka_sidebar_category_links

https://pikawaka.com/
https://pikawaka.com/ruby
https://pikawaka.com/rails
https://pikawaka.com/html-css
https://pikawaka.com/javascript
https://pikawaka.com/word
https://pikawaka.com/tips
https://pikawaka.com/it-industry
...
特定のWebページの属性値を取得しよう

get_pikawaka_sidebar_category_links のように、特定のWebページの任意の属性値を取得するメソッドを作成しましょう。

Slack通知機能

Slack通知機能は特定のアクションを実行した際にSlackへ通知する機能のことを指します。

Slack通知機能の導入

Slack通知チャンネルを作成しよう!

ここではテスト用として、卒業生コミュニティチームで自身に通知するSlackチャンネルをまず作成しましょう。

slack_notification_宮嶋勇弥 のように slack_notification_自身のフルネーム でチャンネルを作成して下さい。
作成後にそのチャンネルに宮嶋を招待して下さい。

Slack通知

Webhook urlを作成しよう

以下のサイトを参考に、slack_notification_自身のフルネーム を指定して Slack通知を受け取るためのWebhook urlしましょう。

https://pikawaka.com/rails/slack-api#incoming-webhookを追加しよう

Webhook urlを取得できれば、以下の画像のように Webhook url を送信して下さい。

画像

Slack通知のGemを導入しよう

Slack通知のGemを導入しよう。

Gemfile
1
2
gem "slack-notifier"
gem "dotenv-rails"
環境変数を定義しよう

以下のサイトを参考に環境変数を定義して下さい。

https://pikawaka.com/rails/slack-api#環境変数を定義しよう

Slack通知機能の実装

準備は整いました。ここからSlack通知機能の実装を行っていきましょう。

rails c を実行し、コンソールを立ち上げて下さい。

コンソールを立ち上げたら、以下の内容を打ち込んで下さい。

1
2
3
4
5
6
        notifier = Slack::Notifier.new ENV['WEBHOOK_URL'] do
          defaults channel: "#workshop", #チャンネル名
                   username: "通知BOT" #Slackに表示するユーザー名
        end

        notifier.ping 'Hello workshop' # Slackに通知するメッセージ

すると #workshop'Hello workshop' という内容の通知が届きましたね。

上記のように設定することで、指定したチャンネルに指定した内容が届くようになります。

scraping機能とslack通知機能を掛け合わせてみよう

scraping機能とslack通知機能のそれぞれの実装方法について学びました。
ここからはScraping機能とSlack機能を掛け合わせた機能を作成してみましょう。

例としてPikawaka サイトに新規で作成された記事を取得し通知する方法を見てみます。

以下の画像を参考にすると新着記事は、p-article__thumb--primary クラスの中の p-article__thumb__inner クラスの中の c-article__title--thumb クラスの中の h4 要素であることが分かります。

新着記事の画像

以下のようにメソッドを追記して、新着記事を取得するメソッドを作成して下さい。

web_scraper.rb | 指定した要素のテキストの取得方法の例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end

  def self.get_h1_text(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.search('h1').inner_text
  end

  def self.get_pikawaka_sidebar_category_texts
    agent = Mechanize.new
    page = agent.get('https://pikawaka.com')
    texts = []
    page.search('.c-sidebar__article-title', 'a').each do |element|
      texts << element.inner_text
    end

    puts texts
  end

  def self.get_pikawaka_sidebar_category_links
    url = 'https://pikawaka.com'
    agent = Mechanize.new
    page = agent.get(url)
    links = []
    page.search('.c-sidebar__article-title', 'a').each do |element|
      link = element.get_attribute('href')
      links << url + link if link.present?
    end

    puts links
  end

def self.get_pikawaka_newest_article_links
agent = Mechanize.new
page = agent.get('https://pikawaka.com')
texts = []
page.search('p-article__thumb--primary', 'p-article__thumb__inner', 'c-article__title--thumb', 'h4').each do |element|
text = element.inner_text
texts << text
end
puts texts.first(4)
end
end

メソッドを実行すると、新着記事のタイトル一覧を取得できました。次にタイトル一覧をスラックチャンネルに通知するように修正します。

以下のようにメソッドを修正して、実行して下さい。

web_scraper.rb | 指定した要素のテキストの取得方法の例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class WebScraper
  def self.get_title(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.title
  end

  def self.get_h1_text(url)
    agent = Mechanize.new
    page = agent.get(url)
    page.search('h1').inner_text
  end

  def self.get_pikawaka_sidebar_category_texts
    agent = Mechanize.new
    page = agent.get('https://pikawaka.com')
    texts = []
    page.search('.c-sidebar__article-title', 'a').each do |element|
      texts << element.inner_text
    end

    puts texts
  end

  def self.get_pikawaka_sidebar_category_links
    url = 'https://pikawaka.com'
    agent = Mechanize.new
    page = agent.get(url)
    links = []
    page.search('.c-sidebar__article-title', 'a').each do |element|
      link = element.get_attribute('href')
      links << url + link if link.present?
    end

    puts links
  end

  def self.get_pikawaka_newest_article_texts
    agent = Mechanize.new
    page = agent.get('https://pikawaka.com')
    texts = []
    page.search('p-article__thumb--primary', 'p-article__thumb__inner', 'c-article__title--thumb', 'h4').each do |element|
      text = element.inner_text
      texts << text
    end

texts.unshift("【Pikawakaの新規記事一覧のタイトルを取得しました。】\n") # 配列の先頭に要素を追加
notifier = Slack::Notifier.new ENV['WEBHOOK_URL'] do
defaults channel: "#slack_notification_宮嶋勇弥", username: "通知BOT"
end
notifier.ping texts.first(4).join("\n") # Slackに通知するメッセージ
end
end

このようにスクレイピングで取得した情報をスラックに通知することで、スクレイピングとスラックを掛け合わせた機能を作成できました。

スラックに通知してみよう

「任意のテキストを取得しよう」で作ったメソッドを修正して、スクレイピングで取得したテキストをスラックに投稿できるように修正してみましょう!