0
1

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.

Yahoo NewsをSlackへ通知してみる ~AWS Lambda × Web scraping × Slack API~

Last updated at Posted at 2022-01-06

#はじめに
今回はAWS Lambdaを使ってSlackに通知を送るというシンプルなサーバレスアーキテクチャ作成を紹介します。
すでにLambdaとSlackについては多くの記事が出ていますがWeb scrapingを組み合わせたものはあまりないように思いました。
私がクラウド技術のすごさを思い知ったのがこのLambda×Web scrapingという組み合わせだったので初心に帰るという意味で記事にします!

#Web Scrapingとの出会いと課題
image.png

資料出所:Webスクレイピングとは?定義から活用事例までの説明

##1.Web Scraping
皆さんはWeb scrapingという技術をご存じでしょうか?
Web scrapingとはプログラムを使ってWebサイトから文字列や画像を自動で取得する技術のことです。
例えばデータ分析のためにAmazonなどの通販サイトから商品名と価格を1日1000件、1カ月間取得する必要があるとします。これを人間の手でやると何人もの社員を動員してひたすら作業を繰り返す必要がありますしミスが生じる可能性も高いです。
しかしWeb scrapingを使って行えば自動で数分で完了するので毎日実行しても負荷はほとんどなくミスも起こりません。お金・時間・労力を大幅に削減できるだけでなく品質を向上することができます
私が初めてIT技術に触れ、感動してIT業界を志すきっかけになったのがWeb scrapingです。大学の卒業論文のためにスポーツの対戦データをWeb scrapingによって1時間で5万件取得し大規模データでの分析が短時間で可能になりました。

##2.課題
Web Scrapingを一度使うだけであればPythonでプログラムを実装して実行するだけでよいですが、定期的に実行する場合はPCかサーバを用意して常時稼働状態にしてプログラムを定期実行するロジックを構築する必要があります。
以前株価や経済指標を自動取得してSlackへ送信するPythonプログラムを実装した際にはRaspberry Pi(Raspberry Pi(ラズベリーパイ)とは?IoT開発ができるラズパイの使い方)を購入して24時間起動状態にしてプログラムを定期実行していました。
しかしこの方法だと冷却用のファンが夜うるさかったり盗難・紛失などのセキュリティリスクがあったりしたのでどうにか改善が必要でした。

Ryoが構築した定期実行システムver 1.0
image.png

#AWS Lambdaという解決策
そこで着目したのがAWSが誇るサーバレスサービス「AWS Lambda」です。
サーバレスサービスとは簡単に言うと「サーバのことを気にしなくてよくなるクラウドサービス」のことです。
私が初期に構築したRaspberry Piを用いたアーキテクチャの場合、私はRaspberry Piというサーバの管理を常に行わなくてはいけません。つまり盗難防止、冷却装置、故障対策などに加えてOSの更新やセキュリティ適用などのソフト面も管理する必要があります(いわゆるサーバ運用保守作業)。
しかしLambdaを利用すれば実行するPythonプログラムを配置するだけで残りのサーバの世話はすべてAWSが責任を持って行ってくれます
。時間ごとの定期実行に加えてシステムの障害発生やアクセス増加を起点(トリガー)として全自動でプログラムを実行してくれます。サーバ費用は不要でプログラムを実行した回数に応じて課金されるので変動費のみとなりやすく済みます(実際はLambdaの無料枠があるので大量実行しない限り無料)。

Ryoが構築した定期実行システムver 2.0
image.png

#やりたいこと
実現したい定期実行システム
image.png

今回は前述のLambdaによる自動定期実行とWeb scrapingを組み合わせて1日1回YahooニュースのサイトからトップニュースのタイトルとURLを自動取得してSlackに通知するというシステムを作ります。
完成するとすべてが自動化されて達成感を得られる&WebScrapingとクラウドサービスのすごさがわかるのでぜひ挑戦してみてください。

Web scrapingは短時間にたくさん実行してしまうと先方のサーバに負荷をかけてしまい場合によっては攻撃とみなされて偽計業務妨害となってしまう可能性があります。
普通に実行していて犯罪行為となる可能性は低いですがマナーを守って高頻度の実行は控えるように、そして自己責任でお願いいたします。

参考:岡崎市立中央図書館事件

#手順
事前準備

  • Slackにアカウント登録が完了していること
  • Slack管理者として管理画面が利用できること
  • AWSのアカウント登録が完了しクレジットカード登録も完了していること
  • Python実行環境(Anaconda推奨)が構築されていること 参考:Anacondaのインストール

これらの一般的な事前準備に関してはQiitaの記事やネットの情報を参考に済ませておいてください。
さほど難しくはないと思います。

##1.Slackの設定とアプリ登録

Slackのアプリ管理画面を開き「Create an App」をクリックします
image.png


「From scratch」をクリックし、アプリ名に「daily_news」(なんでもよい)と入力してアプリを導入するworkspaceに間違いがないことを確認して「Create App」をクリックします
image.png
image.png
完了するとアプリの詳細画面が表示されます
image.png


「Incoming Webhooks」をクリックしタブをONにします
image.png


画面を下までスクロールし「Add New ... Workspace」をクリックします
image.png


権限がリクエストされるので追加する(メッセージを飛ばす先の)チャンネルを選択して「許可する」をクリックします
image.png
image.png


完了するとこのようになります
ここで発行されたWebhook URLは後程必要になりますので覚えておいてください
image.png

##2.Pythonスクリプト作成
以下4つのPythonファイル(.py)を準備します

①BeautifulSoupライブラリでYahooニュースページからニュース情報を取得するコード

get_yahoo_news.py
import requests
from bs4 import BeautifulSoup

def get_title_url(url, tag, tag_string):
    
    # スクレイピング対象の URL にリクエストを送り HTML を取得する
    res = requests.get(url)
    
    # レスポンスの HTML から BeautifulSoup オブジェクトを作る
    soup = BeautifulSoup(res.text, 'html.parser')
    
    # ページに含まれるタイトル、リンクを全て取得する
    titles = []
    for i in soup.select("[{0}='{1}']".format(tag, tag_string)):
        titles.append(i.get_text())

    urls = []
    for i in soup.select("[{0}='{1}']".format(tag, tag_string)):
        urls.append(i.get("href"))

    return titles, urls


def make_news_messgae(url, tag, tag_string):

    news_titles, news_urls = get_title_url(url, tag, tag_string)
    fixed_message = ""

    for i in range(0, len(news_titles)):
        message = []
        for j in range(0, len(news_titles)):
            message.append("*・<{}|{}>*".format(news_urls[j], news_titles[j]))
        fixed_message = fixed_message + message[i] + "\n"
    
    return fixed_message

②SlackAPIを呼び出しPOSTリクエストを送るコード

"sc-frDJqD bJCuGd"の部分はYahooニュースページのタグから取得していますが変更になる可能性がありますので取得に失敗する場合はYahooニュースページでF12ボタンを押してクラス名を確認して変更してください

image.png

send_request.py
import requests, json
import datetime
from get_yahoo_news import make_news_messgae

def dt_today():
    dt = datetime.datetime.today() + datetime.timedelta(hours=9)
    dt_today = dt.strftime("%m/%d")
    return dt_today

def send_news(url):
    #日付取得
    today = dt_today()

    #ニュースタイトル、URL取得
    news_message = make_news_messgae('https://news.yahoo.co.jp/', "class", "sc-frDJqD bJCuGd")

    #送信先SlackチャンネルのWebhookURLを指定
    WEB_HOOK_URL = url

    #POSTリクエスト送信
    requests.post(WEB_HOOK_URL, data = json.dumps({
        'text': '<!here>\n{0}の注目ニュースはこちらです!\n\n{1}'.format(today, news_message),
    }))
    return("finish_work_alert_{0}".format(today))

③SlackのWebhook URLのリスト(今回はnews_channelのURLのみ使用しますがテストのために他のチャンネルのURLを発行して記入してもよいです)

「Webhook URLをコピー」の部分は https://hooks.slack.com/services/XXXXXXX の形式で記入してください

slack_url_list.py
def slack_url_list():
    slack_url_list={
    "news_channel":"Webhook URLをコピー",
    "random":"Webhook URLをコピー" # ←無くてもよい
    }
    return slack_url_list

④Lambdaを制御するハンドラーファイルで、ここに記述されている関数が実行されます

lambda_function.py
import json
import datetime
import send_request
from slack_url_list import slack_url_list

def lambda_handler(event, context):

    dt = datetime.datetime.today() + datetime.timedelta(hours=9)
    slack_urls = slack_url_list()

    send_request.send_news(slack_urls["news_channel"])
    
    return {
        'statusCode': 200,
        'body': json.dumps('{}_finished'.format(dt.strftime("%Y%m%d_%H%M%S")))
    }

##3.ライブラリ資源の確保
requests、BeautifulSoupなどのPythonライブラリはローカルPC上では一度インストールすれば自動的に呼び出されますがLambda上では呼び出せないので必要なライブラリはコードファイルと同じディレクトリに保存しておく必要があります。
今回は事前準備でAnaconda経由でPythonが実行できる環境を整えていると仮定して進めます(独自にPythonをインストールした方はネットでpip install コマンドが使えるようにしていればOKです)。
まずは必要なライブラリをAnaconda promptからインストールします


Anaconda promptの起動
image.png


必要なライブラリのインストール
以下のような画面で
image.png
下記のコマンドを入力してください

pip install requests
pip install bs4
pip install soupsieve

インストールされたライブラリは以下のディレクトリに保存されているので探してフォルダごとコピーしてください

C:\Users\"ユーザー名"\Anaconda3\Lib\site-packages

最後に4つのPythonファイルと3つのライブラリフォルダを1つのフォルダに保存します(場所はどこでも大丈夫です)
完成形
image.png

##4.AWS Lambdaへのデプロイ

Lambdaへのデプロイのためには資源をすべて選択してZIPファイルとしてまとめておく必要があります
必要なファイル、フォルダを全選択して1つのZIPファイルとして保存してください(ZIPファイル名は「daily_news」としています)
image.png
image.png


AWSのコンソール画面から「AWS Lambda」と検索し、「関数の作成」をクリックします
作成画面で関数名「daily_news」を入力、ランタイム「Python 3.7」を選択し他はいじらずに「関数の作成」をクリック
image.png


詳細画面が表示されるので「アップロード元」をクリックして「.zipファイル」を選択
image.png


先ほど作成したZIPファイルを選択して「保存」をクリック
image.png


完成形
image.png

##5.テスト
「Test」ボタンをクリックして何も変更せずに「保存」をクリックします
その後もう一度「Test」をクリックすると関数が実行されてテストが可能となります

##6.Event BridgeによるCron日次実行
いよいよここからはPythonプログラムの定期実行をLambda上で実装していきます


関数の詳細画面から「トリガーを追加」をクリックします

トリガーとは日本語で引き金という意味で、ここではLambda関数を起動させる条件を指定することになります

image.png


トリガーで「Event Bridge」を選択し「新規ルールの作成」を選択します
ルール名は「daily_news」を選択しルールタイプは「スケジュール式」を選択します
ここでcron式という式を使っていつ関数を起動するか記述する必要があります
詳しくは公式ドキュメントを参考にしてほしいですが、今回は"平日夕方18時に実行する"を定義するために *cron(00 09 ? * MON-FRI ) と記入します

cronは世界標準時で記入する必要があるため、日本時間18時は世界標準時9時=00 09となります

image.png


最終形
image.png


これで平日18時にYahooニュースのメッセージがSlackに届くはずです!!
image.png

#おわりに
WebScrapingとLambdaを用いたニュース通知の実装、いかがだったでしょうか?
こんなことができるのを知っているだけでもITへの関心が高まると思います。もし記事で分かりにくい部分があったらご連絡いただけると嬉しいです。
今後もクラウド技術を使った小技を定期的に投稿しますのでぜひご一読ください!

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?