pythonのwebスクレイピングで得た値をLINEに通知する方法

Python プログラミング

こんにちは、はるです。

はてな顔

困った人: pythonでwebスクレイピングをしてみたい。webスクレイピングした情報をLINEに送ってみたい。

こんな悩みを解決していきます。

私自身pythonを勉強中ですが、「楽天ハンドの入荷情報をスクレイピングして、入荷したらLINEに通知を送る」という処理を作りました。

楽天モバイルの公式サイトの利用規約を見る感じスクレイピングは禁止されていなかったので、「まだスクレイピングやったことがないよ」という方は本記事を参考にぜひチャレンジしてみてください!

クローリングできるページ一覧は、robots.txtで見ることができます。(Disallow は禁止ページ)
楽天サイトのrobots.txt

本記事では楽天ハンドを例に、pythonでスクレイピングする方法と、webスクレイピングした値をLineに通知させる方法を解説していきます。

実行環境

  • Windows10
  • Anaconda3

記事の内容

  • はじめに、ソースコード公開
  • pythonでwebスクレイピングする方法
  • webスクレイピングした値をLineに通知させる方法

追記

楽天ハンドのクラス名が変わっています。
本記事で紹介したクラス名は、product-detail-Layout_Btn-modalですが、2021/3/15現在では、c-Btn_Primary-autoproduct-Rakuten-hand_Nav-btnになっています。

記事の内容

はじめに、ソースコード公開

今回解説するソースコードを載せておきます。

from bs4 import BeautifulSoup
import requests

r = requests.get("https://network.mobile.rakuten.co.jp/product/smartphone/rakuten-hand/")
print(r)
c = r.content
# print(c)

soup = BeautifulSoup(c, "html.parser")

# print(soup)
category = soup.find_all('div',{'class': 'product-detail-Layout_Btn-modal'})
print(category.text)

stock = category.text

def main():
    send_line_notify(stock)

def send_line_notify(notification_message):
    line_notify_token = 'LINEのトークン'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    headers = {'Authorization': f'Bearer {line_notify_token}'}
    data = {'message': f'message: {notification_message}'}
    requests.post(line_notify_api, headers = headers, data = data)

if ("現在入荷待ち" != stock):
    print("入荷したみたい")
    if __name__ == "__main__":
        main()
else:
    print("入荷待ち")

pythonでwebスクレイピングする方法

pythonでwebスクレイピングする方法
以下の順番で、webスクレイピングをすることができます。

  1. BeautifulSoupとrequestsのインポート
  2. サイトを読み込む
  3. 値をとってくる

BeautifulSoupとrequestsのインポート

まずは、BeautifulSoupとrequestsをインストールします。
Anacondaを使っている人はconda、使っていない人はpipです。

私はAnaconda環境なので、公式サイトのとおりにcondaでインストールしました。

  • conda install -c anaconda beautifulsoup4
  • conda install -c anaconda requests

参考:Anaconda公式サイト
beautifulsoup4
requests

pipの方

  • pip install beautifulsoup4
  • pip install requests

参考:pipy公式サイト
beautifulsoup4
requests

インストールが終わったら、インポートしていきます。
以下のような感じです。

from bs4 import BeautifulSoup
import requests

サイトを読み込む

requestsを使って、スクレイピングしたいサイトを読み込みます。

r = requests.get("https://network.mobile.rakuten.co.jp/product/smartphone/rakuten-hand/")
# print(r)
c = r.content
# print(c)

requests.getでサイトのURLをとってきます。
このrに入った値は、「Response[200]」といったHTTPステータスコードです。

カンタンに説明すると、「URLちょうだいー」「OK、取得に成功したよ」というやり取りをしていて、「Response[200]」が成功を表しています。

r.contentとすることで、htmlソースコードを抜き出すことができます。
ですが、改行が¥nとなっていたり、日本語が英数字になっていたりして見にくい。

そこで、BeautifulSoupを使ってキレイにしていきます。

soup = BeautifulSoup(c, "html.parser")
# print(soup)

第一引数(,の前)にとってきたhtmlを入れ、第二引数(,から後ろ)にはhtml.parserを指定します。

html.parserの代わりにlxmlでも大丈夫みたいですが、lxmlをインポートする必要があったので使いませんでした。

値をとってくる

次にスクレイピングで値をとっていきましょう。

楽天ハンドが入荷したら、「現在入荷待ち」という表記が変わります。
なので、「現在入荷待ち」のテキストデータが欲しいです。

そこで、「現在入荷待ち」と書かれているボタンのproduct-detail-Layout_Btn-modalというクラス名を取得していきます。

実際のhtmlは以下の感じでした。

<div class="product-detail-Layout_Btn-modal" aria-disabled="true"><a>現在入荷待ち</a></div>

追記

楽天ハンドのクラス名が変わっています。
本記事で紹介したクラス名は、product-detail-Layout_Btn-modalですが、2021/3/15現在では、c-Btn_Primary-autoproduct-Rakuten-hand_Nav-btnになっています。

category = soup.find_all('div',{'class': 'product-detail-Layout_Btn-modal'})
print(category.text)

stock = category.text

soup.findで指定した値(今回はclass)のついたhtmlを取得します。
そのまま出力すると、文字を含んだhtmlが表示されますが、現在入荷待ちという文字だけを取り出したいので、categoryの後ろに.textをつけました。

ちなみにsoup.find_allにすると、複数取り出すことができます。
今回の例でいうと、product-detail-Layout_Btn-modalのクラス名がついたすべてのhtmlが対象です。

webスクレイピングした値をLineに通知させる方法

webスクレイピングした値をLineに通知させる方法
続いて、スクレイピングした値をLineに通知させる方法は以下の手順です。

  1. トークンを取得する
  2. 通知を送る
  3. 条件分岐

トークンを取得する

まずはLINE Notifyにログインします。
LINENotify1
LINEアカウントのメールアドレスとパスワードを入力しましょう。
LINENotify2
次にマイページを開いて、トークンを発行します。
LINENotify4
マイページの下の方にトークンを発行する場所があります。
LINENotity5
トークン名を入力し、通知を受け取るライングループを選びます。
自分宛てにする場合は、一番上の1:1を選びましょう。
LINENotity6
トークンを発行して画面を閉じたら見れなくなるので、コピーを忘れずに。
LINENotity7

通知を送る

send_line_notifyには、LINEで送られてくるメッセージを入れることができます。
今回はstockを入れて「現在入荷待ち」か「購入する」のどちらかスクレイピングしたものが入るようにしました。

def main():
    send_line_notify(stock)

def send_line_notify(notification_message):
    line_notify_token = 'LINEのトークン'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    headers = {'Authorization': f'Bearer {line_notify_token}'}
    data = {'message': f'message: {notification_message}'}
    requests.post(line_notify_api, headers = headers, data = data)

条件分岐

スクレイピングで得た値が「現在入荷待ち」でなければ、main()処理を呼び出します。

if ("現在入荷待ち" != stock):
    print("入荷したみたい")
    if __name__ == "__main__":
        main()
else:
    print("入荷待ち")

if __name__ == "__main__":は、他のファイルにインポートするときにプログラムが勝手に動かないようにするものなので、付けても付けなくても動きます。

さいごに

さいごに
お疲れさまです。
最後までご覧いただきありがとうございました。

追加で「10分おきに処理を行うループ処理を加えて、在庫が入ったら自動でLINEに通知するプログラム」も作れたので、下記に載せておきます。

※10分おきに処理をするというプログラムを使いたかったので、scheduleとtimeも追加でインポートしています。

今回の参考記事一覧(下にスクロールします)

import schedule
import time
from bs4 import BeautifulSoup
import requests

def loop():
    r = requests.get("https://network.mobile.rakuten.co.jp/product/smartphone/rakuten-hand/")
    c = r.content

    soup = BeautifulSoup(c, "html.parser")

    # print(soup)
    category = soup.find_all('div',{'class': 'product-detail-Layout_Btn-modal'})
    print(category.text)

    stock = category.text

    def main():
        send_line_notify(stock)

    def send_line_notify(notification_message):
        line_notify_token = 'LINEのトークン'
        line_notify_api = 'https://notify-api.line.me/api/notify'
        headers = {'Authorization': f'Bearer {line_notify_token}'}
        data = {'message': f'message: {notification_message}'}
        requests.post(line_notify_api, headers = headers, data = data)

    if ("現在入荷待ち" != stock):
        print("入荷したみたい")
        if __name__ == "__main__":
            main()
    else:
        print("入荷待ち")

schedule.every(10).minutes.do(loop)

while True:
    schedule.run_pending()
    time.sleep(1)

以上です。
ご覧いただきありがとうございました。

※さらにサイトの自動ログインについても知りたい方は、こちらの記事もどうぞ。

参考