試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

Rubyを使って歌詞サイトから歌詞を取得する方法


こんにちは、風来坊です。今回は歌詞サイトからRubyスクリプトを利用して、
歌詞を取得する方法について説明したいと思います。



今回、対象となるサイトは以下の三つです。


歌詞サイトを見たことがある人ならわかると思いますが、こういったサイトにおいては著作権の関係上、
歌詞をコピー・ペーストできないようになっています。


JavaScriptで右クリックが禁止されていたり、歌詞自体がFlashで画像として表示されており、
テキストデータとしてコピーできなかったり・・・



だからといって、歌詞のテキストデータを取得する手法がないわけでは有りません。
通常のブラウザを使ってコピー・ペーストができないだけで、スクリプトを使えば
そうした制限をかいくぐって歌詞のテキストデータを取得することができます。








Rubyスクリプトを組むにあたり、string-scrubをインストールしてください。
これは文字コード変換時に生じる不正な文字を置き換える役割を果たします。
Rubyの環境がすでにインストールされているならば、

gem install string-scrub

でインストールできるはずです。






アニメソングの歌詞ならここにおまかせ?


このサイトは、対応が最も簡単です(マイナーなサイトだからだと思いますが・・・・)。
JavaScriptで右クリックが禁止されているだけと、非常にシンプルな対応しかしていません。
Rubyのopen-uriを使って歌詞ページのHTMLを取得、正規表現を使って必要部分を抜き出せば
簡単に歌詞を取得することが可能です。HTMLの文字コードがShift-JISなので、その点に気をつける必要があります。
Rubyで、このサイトの歌詞ページ中の歌詞・及び楽曲の情報を取得するような関数は以下のようになります。


#-*- coding:utf-8 -*-
require 'open-uri'

def omakase(base_url)
  
  # 正規表現パターン
  pat_text = Regexp.new('<td class=b Valign="top"><pre>(.*?)</pre></td>', Regexp::IGNORECASE | Regexp::MULTILINE)
  pat_data = Regexp.new('(.*?)\n\n作詞[::](.*?)/作曲[::](.*?)/編曲[::](.*?)/\n歌[::](.*?)\n\n(.*)', Regexp::MULTILINE)
  
  # 歌詞を取り出す
  open(base_url) do |html|
    
    # 変数
    text     = ""
    title    = ""
    lyricist = ""
    composer = ""
    arranger = ""
    singer   = ""
    
    # 歌詞と関連データを取り出す
    tmp = html.readlines.join.encode('utf-8', 'sjis')
    text = $1 if pat_text =~ tmp
    if pat_data =~ text
      title    = $1.strip
      lyricist = $2.strip
      composer = $3.strip
      arranger = $4.strip
      singer   = $5.strip
      lyric    = $6.strip
      p "曲名:" + title
      p "作詞:" + lyricist
      p "作曲:" + composer
      p "編曲:" + arranger
      p "歌手:" + singer
      p "歌詞:" + lyric
    end
  end

end





歌詞タイム


比較的大手の歌詞サイト。右クリック禁止 + 歌詞画像データ化によって、
コピーを防いでいるようです。



歌詞タイムの通常の歌詞ページは以下のようになります。

http://www.kasi-time.com/item-71736.html

f:id:incodethx3932:20140715104057p:plain



しかし、以下のページから、歌詞のテキストデータを取得することが出来るのです。

http://www.kasi-time.com/item_js.php?no=71736

f:id:incodethx3932:20140715104750p:plain




このページは、"document.write(".....歌詞テキスト.....")"という書式になっているので、
正規表現を利用して歌詞を取得します。楽曲の詳細な情報(作詞、作曲、編曲、歌手等)は
元ページに記載されていますが、これもやや手間ではありますが、正規表現を使って抜き出します。
関数は以下のようになります。


#-*- coding:utf-8 -*-
require 'open-uri'
require 'cgi'
require 'string-scrub'

def kashitime(page_url)

  # 変数
  lyric     = ""
  name      = ""
  singer    = ""
  lyricist  = ""
  composer  = ""
  arranger  = ""
  pronounce = ""
  
  # 正規表現パターン
  pat_url       = Regexp.new('www.kasi-time.com/item-(.*?).html')
  pat_lyric     = Regexp.new('document.write\(\'(.+)\'\);$', Regexp::MULTILINE)
  pat_info      = Regexp.new('<meta name=\"description\" content=\"歌手:(.*) 作詞:(.*) 作曲:(.*?) .*?>', Regexp::MULTILINE)
  pat_name      = Regexp.new('<div id=\"song_info_table\">\r\n\t\t<h1>(.*?)</h1>', Regexp::MULTILINE)
  pat_arranger  = Regexp.new('<td class=\"td1\">編曲</td><td><a href=\".*?\">(.*?)</a></td>', Regexp::MULTILINE)
  pat_pronounce = Regexp.new('<td class=\"td2\">読み</td><td>(.*?)</td>', Regexp::MULTILINE)  
    
  # 歌詞テキストデータページURL
  base = "http://www.kasi-time.com/item_js.php?no="
  lyric_url = ""
  lyric_url = base + $1 if pat_url =~ page_url
  
  # 歌詞テキストの取得
  html = open(lyric_url).readlines
  doc = html.join.force_encoding("utf-8")
  doc = CGI.unescapeHTML(doc)
  doc.gsub!('<br>', "\n")
  
  # 歌詞を取り出す
  lyric = $1 if pat_lyric =~ doc
  
  # 歌詞閲覧ページの取得
  html = open(page_url).readlines
  doc = html.join.force_encoding("utf-8")
  doc = CGI.unescapeHTML(doc)
  
  # 曲データを取り出す
  if pat_info =~ doc
    singer   = $1
    lyricist = $2
    composer = $3
  end
  name = $1.strip if pat_name =~ doc
  arranger = $1.strip if pat_arranger =~ doc
  pronounce = $1.strip if pat_pronounce =~ doc
  
  # 出力
  p "曲名: " + name
  p "読み: " + pronounce
  p "作詞: " + lyricist
  p "作曲: " + composer
  p "編曲: " + arranger
  p "歌手: " + singer    
  p "歌詞: " + lyric
    
end






うたまっぷ 歌詞を無料で検索表示

大手歌詞サイトのひとつ。右クリックこそ禁止されていないものの、
歌詞が画像データ化され、Flash上で表示されるためコピーができない。
しかし、歌詞のテキストが取得できるURLが存在するため、これを利用する。



うたまっぷの通常の歌詞ページは以下の様なページになります。

http://www.utamap.com/showkasi.php?surl=57979

f:id:incodethx3932:20140715102217p:plain




以下のページに行くと、テキストを取得出来ます。

http://www.utamap.com/phpflash/flashfalsephp.php?unum=57979

f:id:incodethx3932:20140715103312p:plain




このページは、"test=(2桁の数字)&test2=(歌詞テキスト)"という書式になっているので、
これも正規表現を利用して抜き出してやればOKです。
楽曲の詳細な情報も元ページにから同様に正規表現を利用して対応します。
元ページはEUC-JPでのエンコードなので、この点も注意が必要です。Rubyの関数を書くと以下のようになります。

# うたまっぷ用の関数
#-*- coding:utf-8 -*-
require 'open-uri'
require 'cgi'
require 'string-scrub'

def utamap(page_url)
    
  # 変数
  name     = ""
  lyric    = ""
  lyricist = ""
  composer = ""
  singer   = ""
  
  # 正規表現パターン
  pat_url      = Regexp.new('www.utamap.com/showkasi.php\?surl=(.*)')
  pat_lyric    = Regexp.new('test2=(.*)$', Regexp::MULTILINE)
  pat_name     = Regexp.new('<tr><td class="kasi1">(.*?)</td></tr>')
  pat_info     = Regexp.new('<td class="pad5x10x0x10">(.*?)</td>')
  
  # 歌詞ページURL
  base = "http://www.utamap.com/phpflash/flashfalsephp.php?unum="
  lyric_url = ""
  lyric_url = base + $1 if pat_url =~ page_url
  
  # 歌詞テキストの取得
  html = open(lyric_url).readlines
  doc = html.join.force_encoding("utf-8")
  doc = CGI.unescapeHTML(doc)
  
  # 歌詞を取り出す
  lyric = $1.strip if pat_lyric =~ doc
  
  # 歌詞閲覧ページの取得
  html = open(page_url).readlines
  doc = html.join.encode('utf-8', 'euc-jp')             # 閲覧ページはEUC-JPでエンコードされている
  doc = CGI.unescapeHTML(doc.scrub) 
  
  # 曲データを取り出す
  name     = $1.strip if pat_name =~ doc
  info_array = doc.scan(pat_info)
  lyricist = info_array[1].join.gsub(/&.*$/, '')        # 特殊文字由来のアンパサンド以下、余分な文字列を除去
  composer = info_array[3].join.gsub(/&.*$/, '')
  singer   = info_array[5].join.gsub(/<\/?[^>]*>/, '')  # strongタグを除去
  
  # 出力
  p "曲名: " + name
  p "作詞: " + lyricist
  p "作曲: " + composer
  p "歌手: " + singer
  p "歌詞: " + lyric

end




今までの関数をまとめたものが以下のようになります。
色々と改造を加えて活用できると思います。

#-*- coding:utf-8 -*-
require 'open-uri'
require 'cgi'
require 'string-scrub'


# LyricGetterクラス
class LyricGetter
  
  # 歌詞を取得する関数
  def lyricget(url)
    
    # ドメイン名の取得
    hostname = URI(url).host

    # ドメインごとに呼び出す関数を分岐する
    case hostname
      when "www.jtw.zaq.ne.jp"
        omakase(url)
      when "www.kasi-time.com"
        kashitime(url)
      when "www.utamap.com"
        utamap(url)
    end
  
  end


  # アニメソングの歌詞ならお任せ?用関数
  def omakase(base_url)

    # 正規表現パターン
    pat_text = Regexp.new('<td class=b Valign="top"><pre>(.*?)</pre></td>', Regexp::IGNORECASE | Regexp::MULTILINE)
    pat_data = Regexp.new('(.*?)\n\n作詞[::](.*?)/作曲[::](.*?)/編曲[::](.*?)/\n歌[::](.*?)\n\n(.*)', Regexp::MULTILINE)
    
    # 歌詞を取り出す
    open(base_url) do |html|
    
      # 変数
      text     = ""
      title    = ""
      lyricist = ""
      composer = ""
      arranger = ""
      singer   = ""
    
      # 歌詞と関連データを取り出す
      tmp = html.readlines.join.encode('utf-8', 'sjis')
      text = $1 if pat_text =~ tmp
      if pat_data =~ text
        title    = $1.strip
        lyricist = $2.strip
        composer = $3.strip
        arranger = $4.strip
        singer   = $5.strip
        lyric    = $6.strip
        p "曲名:" + title
        p "作詞:" + lyricist
        p "作曲:" + composer
        p "編曲:" + arranger
        p "歌手:" + singer
        p "歌詞:" + lyric
      end
    end

  end


  #歌詞タイム用の関数
  def kashitime(page_url)
    
    # 変数
    lyric     = ""
    name      = ""
    singer    = ""
    lyricist  = ""
    composer  = ""
    arranger  = ""
    pronounce = ""
    
    # 正規表現パターン
    pat_url       = Regexp.new('www.kasi-time.com/item-(.*?).html')
    pat_lyric     = Regexp.new('document.write\(\'(.+)\'\);$', Regexp::MULTILINE)
    pat_info      = Regexp.new('<meta name=\"description\" content=\"歌手:(.*) 作詞:(.*) 作曲:(.*?) .*?>', Regexp::MULTILINE)
    pat_name      = Regexp.new('<div id=\"song_info_table\">\r\n\t\t<h1>(.*?)</h1>', Regexp::MULTILINE)
    pat_arranger  = Regexp.new('<td class=\"td1\">編曲</td><td><a href=\".*?\">(.*?)</a></td>', Regexp::MULTILINE)
    pat_pronounce = Regexp.new('<td class=\"td2\">読み</td><td>(.*?)</td>', Regexp::MULTILINE)  
    
    # 歌詞テキストデータページURL
    base = "http://www.kasi-time.com/item_js.php?no="
    lyric_url = ""
    lyric_url = base + $1 if pat_url =~ page_url
    
    # 歌詞テキストの取得
    html = open(lyric_url).readlines
    doc = html.join.force_encoding("utf-8")
    doc = CGI.unescapeHTML(doc)
    doc.gsub!('<br>', "\n")
    
    # 歌詞を取り出す
    lyric = $1 if pat_lyric =~ doc
    
    # 歌詞閲覧ページの取得
    html = open(page_url).readlines
    doc = html.join.force_encoding("utf-8")
    doc = CGI.unescapeHTML(doc)
    
    # 曲データを取り出す
    if pat_info =~ doc
      singer   = $1
      lyricist = $2
      composer = $3
    end
    name = $1.strip if pat_name =~ doc
    arranger = $1.strip if pat_arranger =~ doc
    pronounce = $1.strip if pat_pronounce =~ doc
    
    # 出力
    p "曲名: " + name
    p "読み: " + pronounce
    p "作詞: " + lyricist
    p "作曲: " + composer
    p "編曲: " + arranger
    p "歌手: " + singer    
    p "歌詞: " + lyric
    
  end


  # うたまっぷ用の関数
  def utamap(page_url)
    
    # 変数
    name     = ""
    lyric    = ""
    lyricist = ""
    composer = ""
    singer   = ""
    
    # 正規表現パターン
    pat_url      = Regexp.new('www.utamap.com/showkasi.php\?surl=(.*)')
    pat_lyric    = Regexp.new('test2=(.*)$', Regexp::MULTILINE)
    pat_name     = Regexp.new('<tr><td class="kasi1">(.*?)</td></tr>')
    pat_info     = Regexp.new('<td class="pad5x10x0x10">(.*?)</td>')
    
    # 歌詞ページURL
    base = "http://www.utamap.com/phpflash/flashfalsephp.php?unum="
    lyric_url = ""
    lyric_url = base + $1 if pat_url =~ page_url
    
    # 歌詞テキストの取得
    html = open(lyric_url).readlines
    doc = html.join.force_encoding("utf-8")
    doc = CGI.unescapeHTML(doc)
    
    # 歌詞を取り出す
    lyric = $1.strip if pat_lyric =~ doc
    
    # 歌詞閲覧ページの取得
    html = open(page_url).readlines
    doc = html.join.encode('utf-8', 'euc-jp')             # 閲覧ページはEUC-JPでエンコードされている
    doc = CGI.unescapeHTML(doc.scrub) 

    # 曲データを取り出す
    name     = $1.strip if pat_name =~ doc
    info_array = doc.scan(pat_info)
    lyricist = info_array[1].join.gsub(/&.*$/, '')        # 特殊文字由来のアンパサンド以下、余分な文字列を除去
    composer = info_array[3].join.gsub(/&.*$/, '')
    singer   = info_array[5].join.gsub(/<\/?[^>]*>/, '')  # strongタグを除去
    
    # 出力
    p "曲名: " + name
    p "作詞: " + lyricist
    p "作曲: " + composer
    p "歌手: " + singer
    p "歌詞: " + lyric

  end
  
   
  # メソッドのアクセス制御
  public :lyricget
  private :omakase, :kashitime, :utamap


end




・参考URL

歌詞データはコピー不可!?歌詞サイト『うたまっぷ.com』を攻略!!コピーガードを突破せよ!!

独身の読唇による読心術 歌詞タイム テキスト コピー 歌詞 保存