🎸

Beautiful Soupを使って「ヨルシカの歌詞」をWebスクレイピング

2024/06/26に公開

最近ヨルシカばかり聴いている僕。
そして機械学習のためのスクレイピングに興味を持ち始めている。

せっかくなら自分の好きなもののデータをスクレイピングしたいな~と思い、ヨルシカさんの歌詞情報をスクレイピングしました。

■参考記事
こちらの記事を参考にしました。
https://zenn.dev/robes/articles/00e86185677fb5

Webスクレイピングとは?

Webスクレイピングとは、Webページからデータを抽出する技術です。HTMLの要素などから条件を指定して、必要な情報を抽出します。
スクレイピングは以下のような場面で使われます。

  • 商品価格の追跡
  • ニュース記事の収集
  • リサーチデータの収集 などなど

スクレイピングの流れ

歌詞をスクレイピングするにあたって、
ヨルシカの公式ホームページの構成を紐解きます。

歌詞ページの大元ページ(ページAとします)はこちらです。リリースしたシングルやアルバムが列挙されています。

最新のシングル「ルバート」をクリックすると、こちらのページ(ページBとします)が表示されます。

さらに曲名部分をクリックすると、こちらのページ(ページCとします)が表示されて歌詞を見ることができました!

曲名と歌詞を一覧で取得するには、ページCのURLをすべて取得して、それぞれページCから曲名と歌詞を抜き取ってくる必要がありそうです!

つまり流れとしてはこうなります。

  1. ページAのURLを元に、ページAのHTMLを取得する
  2. ページAのHTMLをスクレイピングして、ページBのURLをすべて取得する(aタグからhrefを取得する)
  3. ②で取得したページBのURLを元に、ページBのHTMLを取得する
  4. ページBのHTMLをスクレイピングして、ページCのURLをすべて取得する(aタグからhrefを取得する)
  5. ④で取得したページCのURLを元に、ページCのHTMLを取得する
  6. ページCのHTMLをスクレイピングして、曲名と歌詞を取得し、データフレームに格納する

スクレイピング実施

今回は「Google Colaboratory」上で実装しました。
ローカル環境で実装する場合は、ライブラリのインストールが必要なため、適宜pip installをお願いします。

ライブラリをインポート

必要なライブラリをインポートします。

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time

曲名・歌詞を格納するデータフレームを用意

「曲名」「歌詞」をカラムに持つデータフレームを事前に用意して、こちらにスクレイピングしたデータを追加していきます。

list_df = pd.DataFrame(columns=['曲名','歌詞'])

URLの定義

スクレイピングで取得しないURLを変数に格納します。

# ヨルシカの公式ホームページurlをyorushika_base_urlに格納します
yorushika_base_url = 'https://yorushika.com'
# lyric_urlに歌詞一覧ページ(ページA)のURLを格納します
# 歌詞一覧ページが2ページに分かれていたため、リストにしています
lyric_urls = ['https://yorushika.com/discography/artist/2/', 'https://yorushika.com/discography/artist/2/?page=2']

ページからhrefを取得するための関数を定義

以下の処理を実行する関数を定義します。
■処理
引数urlからHTML取得
⇒HTMLから指定のCSSのクラス(引数class_name)を持つ指定のタグ(引数tag)を取得
⇒取得したタグの子要素であるaタグからhrefの値を取得
⇒hrefのリストを返却

def get_href_from_url(url, tag, class_name):
  # usr_agentに前もって取得したUserAgent情報を入力します
  user_agent = '{★ユーザエージェント}'
  header = {'User-Agent': user_agent}

  # urlからhtmlを取得した後にパース
  response = requests.get(url,headers=header)
  soup = BeautifulSoup(response.text, 'lxml')
  # 指定されたタグとクラス名で必要なhtml要素を取得する
  elements = soup.find_all(tag, class_=class_name)
  
  # 返却するリストを初期化
  return_list = []
  # 取得したhtml要素を一つずつ取り出し、その子要素のaタグのhrefをreturn_listに詰めていく
  for element in elements:
    a_tags = element.select('a')
    for a_tag in a_tags:
      if(a_tag):
        return_list.append(a_tag['href'])

  # hrefのリストを返却する
  return return_list

曲名・歌詞を取得

いよいよ「曲名」「歌詞」を取得してデータフレームに格納します。

# 歌詞一覧ページ(ページA)のリストで繰り返し
for lyric_url in lyric_urls:
  # 事前に定義した関数get_href_from_urlを呼び出し、シングル・アルバムのhrefリストを取得
  album_hrefs = get_href_from_url(lyric_url, 'li', ['discoItem', 'inview'])

  for album_href in album_hrefs:
    # yorushika_base_urlとhrefを結合してURLを作成(ページB)
    album_url = yorushika_base_url + album_href

    # 事前に定義した関数get_href_from_urlを呼び出し、曲名のhrefリストを取得
    song_hrefs = get_href_from_url(album_url, 'ul', 'track--list')

    for song_href in song_hrefs:
      # yorushika_base_urlとhrefを結合してURLを作成(ページC)
      song_url = yorushika_base_url + song_href
      song_response = requests.get(song_url)
      song_soup = BeautifulSoup(song_response.text, 'lxml')
      # 曲名を取得
      song_name = song_soup.find('div', class_='detail--wrap').find('h2').text
      # 歌詞を取得
      song_lyric = song_soup.find('div', class_='lyrics--body').text

      # データフレームに取得した曲名と歌詞で行を追加する
      list_df = pd.concat([list_df, pd.DataFrame({'曲名': [song_name], '歌詞': [song_lyric]})], ignore_index=True)

      # サーバの負荷軽減のためにプログラムを1秒スリープする
      time.sleep(1)

    # サーバの負荷軽減のためにプログラムを2秒スリープする
    time.sleep(2)

以上でスクレイピングは完了です。
list_dfの中身を確認すると、改行文字が入っていますが、しっかりとデータがとれていることがわかります!!

取得したデータはcsvやexcelに出力も可能です。

list_df.to_csv('ファイル名')
list_df.to_excel('ファイル名')

スクレイピングの注意点

冒頭でも利用規約について触れていますが、
Webスクレイピングを行う際には、以下の点に注意してください。

まとめ

今回はPythonのBeautiful Soupを使ったWebスクレイピングについて紹介しました。

スクレイピングは難しいものと勝手に思っていましたが、JavaScriptでのDOM操作に似ていたためすんなり理解できました。フロントエンドエンジニアの方は容易に習得できる技術だと感じました。

最後までお読みいただきありがとうございました!

Discussion