Qiita
Python
Selenium
AWS
スクレイピング

Qiitaでいいねが付くとLINE通知してくれる優しい世界を構築した


はじめに

Qiitaにはメール通知機能がありますが、「いいね」された時にメール通知してくれる機能がありません。

これはQiita中毒者としては、なかなか厳しい仕様です:mask:

ということで今回は、負荷が掛からない程度にスクレイピングを行い、LINE通知をするプログラムを作成したいと思います。


構成図

draw.io3分クッキング

Untitled Diagram.png


手順


  1. Lambdaの環境構築

  2. headless chromeでログイン後画面を開く

  3. 通知数と最新の通知メッセージを取得する

  4. 取得データをDynamoDBに保存

  5. IFTTTのWebhooksにリクエスト送信

  6. LINE通知

  7. 定期実行の設定


1. Lambdaの環境構築

Qiitaの通知数はReactで動的に生成しているようで、ソースコードをそのまま取得しても通知数が空の状態でした。そのためSeleniumを使ってブラウザからアクセスを行い、最終的に生成されるhtmlを取得したいと思います。

ただし、Lambda上でheadless chromeを動かすことはなかなかに大変です。

chrome,chrome driver,seleniumの3点セットを用意し、動作に問題ないバージョンの組み合わせにした上で、zipで固めてlambdaにアップする必要があります。

私は以下の記事を参考にセットアップを行って、なんとか動く状態まで持っていきました。

AWS Lambda上のheadless chromeをPythonで動かす


2. headless chromeでQiitaのログイン後画面を開く

Qiitaのログイン画面から、メールアドレス/パスワードのテキストボックスの要素を取得し、自身の認証情報を入力した上でログインボタンをクリックする処理を書いていきます。

スクリーンショット 2018-09-14 21.16.53.png

driver.get('https://qiita.com/login')

user_id = driver.find_element_by_id('identity')
user_id.send_keys('*****@****')
password = driver.find_element_by_id('password')
password.send_keys('********')
time.sleep(2)

# ログインボタンをクリック
login_button = driver.find_element_by_name('commit')
login_button.click()
time.sleep(2)

なおメールアドレスとパスワードは、Lambdaの環境変数に持たせると良いと思います。

またページの読み込みを待つため、time.sleep()を適宜入れています。


3. 通知数と最新の通知メッセージを取得する

スクリーンショット 2018-09-14 22.09.06.png

通知があるかを判定するため、通知数を取得します。

また新しい通知がある時のみにLINE通知を行いたいため、最新の通知メッセージも取得しておきます。

html_source = driver.page_source

bs_obj = BeautifulSoup(html_source,'html.parser')

notice_count = bs_obj.select('.st-Header_notifications')[0].text

# 通知0件なら処理終了
if int(notice_count) == 0:
return

# 通知一覧からメッセージを取得
driver.get('https://qiita.com/notifications')
time.sleep(2)

html_source = driver.page_source
bs_obj = BeautifulSoup(html_source,'html.parser')
recent_message = bs_obj.select('.notification_actionWrapper')[0].text

driver.quit()


4. 取得データをDynamoDBに保存

DynamoDBに保存されている通知メッセージを取得し、最新の通知メッセージと比較します。

メッセージが異なる場合は最新の値に更新した上で、IFTTTにリクエストを行います。

# DynamoDBへのアクセス

DYNAMO_DB = boto3.resource('dynamodb')
DB_TABLE = DYNAMO_DB.Table('QiitaNotice')
try:
response = DB_TABLE.get_item(
Key={
'id':0
}
)
except ClientError as e:
print(e.response['Error']['Message'])
return

# アイテムの取り出し
if response['Item']['message'] != recent_message:
response = DB_TABLE.update_item(
Key={
'id': 0
},
UpdateExpression='set message = :m',
ExpressionAttributeValues={
':m': recent_message
},
ReturnValues='UPDATED_NEW'
)
post_ifttt(notice_count,recent_message)


5. IFTTTのWebhooksにリクエスト送信

IFTTTでWebhooksサービスとして提供されているURLに、POSTリクエストを送信します。

URLの中にイベント名と認証キーを含め、データ部にjson形式で通知数と通知メッセージを持たせます。

リクエスト用のURLは、IFTTTのWebhooks>Documentationページにて、簡単に生成する事ができます。またリクエストのテストも簡単に実行できます。

スクリーンショット 2018-09-15 13.21.37.png

def post_ifttt(notice_count,recent_message):

IFTTT_KEY = '******'
url = 'https://maker.ifttt.com/trigger/notice_qiita_fav/with/key/' + IFTTT_KEY
header = {'Content-Type':'application/json'}
params = {'value1':notice_count,'value2':recent_message}
request = urllib.request.Request(url=url, headers=header, data=json.dumps(params).encode('utf-8'))
urllib.request.urlopen(request)


6. LINE通知

IFTTTの設定画面で、トリガーにWebhooksを設定し、データをLINE通知するように設定します。

「this」にWebhooksを、「that」にLINEを設定します。

スクリーンショット 2018-09-15 13.37.05.png

作成したアプレットの設定は以下の通りです。

「Value1」「Value2」がPOSTリクエストで送信されたデータを表示する変数になります。

Screenshot_2018-09-16 IFTTT.png

新しい通知があると、こんな感じでLINE通知が来ます。

(テストなので通知0件になっています。)

IMG_3574.jpg


7. 定期実行の設定

Lambda関数のトリガーにCloudWatch Eventsを追加し、15分ごとにキックするように設定します。

スクリーンショット 2018-09-15 13.49.50.png


おわりに

これで快適なQiitaライフが送れます。やったぜ!

複雑な処理はしていないので、簡単に出来ると思ってたんですが、環境構築に意外と苦戦しました:sweat_smile:

この記事が少しでも参考になりましたら、「いいね!」ボタンをクリックしていただけると幸いです:bow_tone1: