テレビ番組表をexcelに入れる

サイトから番組表をダウンロードし、必要な部分(局名、番組開始時刻、番組名、番組内容)を取り出す

(get_tvprog.rb)

#!/usr/bin/env ruby

require 'nokogiri'
require 'open-uri'

doc = Nokogiri::HTML(STDIN)

#局名を保存する
line = []
ch_area = doc.css('#ch_area')
ch_area.css('ul').each do |ul|
  ul.css('li').each do |li|
    li.css('p').each do |p|
      #puts "#{p}\n"
      line.push(p.text)
    end
  end
end

#puts line

program = doc.css('#program_area')

idx = 0
program.css('ul').each do |ul|
  puts "<line id=\"#{line[idx]}\">"
  ul.css('li').each do |li|
    if( li[:s].to_s.size == 12 ) #番組開始時刻?
      puts "  <time s=\"#{li[:s]}\">"
      li.css('div.program_text').each do |div| #番組名?番組内容?
        div.css('p').each do |p|
          puts "    #{p}\n"
        end
      end
      puts "  </time>\n"
    end
  end
  puts "</line>\n"
  idx += 1
end

実行してみる

番組のサイトから、2024年11月3日の神奈川の地デジ番組表をダウンロードし、必要な部分を取り出す

$ curl "https://bangumi.org/epg/td?broad_cast_date=20241103&ggm_group_id=45" | ./get_tvprog.rb
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  478k  100  478k    0     0   429k      0  0:00:01  0:00:01 --:--:--  430k
<line id="1 NHK総合1..">
  <time s="202411030500">
    <p class="program_title">ニュース・気象情報</p>
    <p class="program_detail"></p>
  </time>
  <time s="202411030510">
    <p class="program_title">大河ドラマ「光る君へ」2分ダイジェスト(41)揺らぎ🈑</p>
    <p class="program_detail">三条天皇(木村達成)から悩ましい願いを託される道長(柄本佑)。一方、まひろ(吉高由里子)は、彰子(見上愛)の意向で和歌の会を催すことに。すると招かれざる客が…</p>
  </time>
  <time s="202411030512">
    <p class="program_title">ドラマ10「宙わたる教室」PR🈑</p>
    <p class="program_detail">実話に着想を得た感動小説を窪田正孝を主演に迎えてドラマ化した「宙わたる教室」。第4話の振り返りダイジェストと第5話のみどころを2分で紹介。</p>
  </time>
  <time s="202411030514">
    <p class="program_title">SDGsのうた アオ・キイ版 目標17 パートナーシップで目標を達成しよう</p>
    <p class="program_detail">「ひろがれ!いろとりどり」は#SDGsを楽しく学んでいく番組シリーズ。「SDGsのうた」ではSDGsの目標を1つずつ、アオとキイの歌とアニメで紹介していくよ!</p>
  </time>
...

上記の出力を、excelファイルにワークシートとして追加する

(add_tvprog2xlsx.rb)

#!/usr/bin/env ruby

require 'kconv'
require 'nokogiri'
require 'open-uri'
require 'rubyXL'
require 'rubyXL/convenience_methods'

#48時間制
#24時は翌日の0時、25時は翌日の1時
cnt = Array.new(48) #各時間帯(0時、1時..)ごとの番組数
max = Array.new(48) #各時間ごとの番組数の最大値(セルの位置調整に使用する。NHKEテレが多い。)
idx = Array.new(48) #各時間帯の番組名、番組内容の表示位置(セル)

adate = ARGV.shift

#1日1ファイルとし、番組表はワークシート単位で追加する
file = adate.to_s + ".xlsx"
if File.exist?(file)
  workbook = RubyXL::Parser.parse(file)
else
  workbook = RubyXL::Workbook.new
  workbook.worksheets.delete_at(0)
end

ARGV.each do |arg|

  #番組表ファイルを開く
  f = File.open(arg,"r")
  doc = Nokogiri::HTML(f, nil, 'utf-8')

  max.each_index do |i|
    max[i] = 0
  end

  idx.each_index do |i|
    idx[i] = 0
  end

  #番組表の読込み
  doc.css('line').each do |line|

    print "#{line[:id]}\n"

    cnt.each_index do |i|
      cnt[i] = 0
    end

    line.css('time').each do |time|
      date = time[:s][0,8].to_s
      hour = time[:s][8,2].to_s
      puts "date:#{date}\thour:#{hour}\n"
      if date == adate # x月y日の番組表作成時に、番組開始日がx月y日である
        cnt[ hour.to_i ] += 1
      else # x月y日ではない→翌日と判断する
        cnt[ hour.to_i + 24 ] += 1
      end
    end

    cnt.each_index do |i|
      print "#{i}: #{cnt[i]}\n"
    end

    cnt.each_index do |i|
      if cnt[i] > max[i]
        max[i] = cnt[i]
      end
    end

  end

  print "max\n"
    max.each_index do |i|
    print "#{i}: #{max[i]}\n"
  end

  for i in 1..48 do
    idx[i] = idx[i-1] + max[i-1]
  end

  print "index\n"
  idx.each_index do |i|
    print "#{i}: #{idx[i]}\n"
  end

  #ワークシートの作成
  if workbook["#{arg}"] #ワークシート名が重複する場合は、プログラムを終了する
    abort "worksheet #{arg} is duplicated!!"
  else
    worksheet = workbook.add_worksheet("#{arg}")
  end

  view = RubyXL::WorksheetView.new
  view.pane = RubyXL::Pane.new(
    top_left_cell: RubyXL::Reference.new(1, 1),
    y_split: 1,
    x_split: 1,
    state: 'frozenSplit',
    activePane: 'bottomRight'
  )
  views = RubyXL::WorksheetViews.new
  views << view
  worksheet.sheet_views = views

  #一番左のセルに時間(hh00)を書く
  idx.each_index do |i|

    worksheet.change_column_vertical_alignment(0, 'top')
    worksheet.change_column_width(0, 3)

    worksheet.add_cell(idx[i]+1, 0, i.to_s + "00")
    worksheet[idx[i]+1][0].change_text_wrap(true)
    worksheet[idx[i]+1][0].change_font_size(6)

  end

  linecnt = 0

  doc.css('line').each do |line|

    pgcnt = 0
    print "#{line[:id]}\n"

    worksheet.change_column_vertical_alignment(linecnt+1, 'top')
    worksheet.change_column_width(linecnt+1, 12)

    #局名を書く
    worksheet.add_cell(0, linecnt+1, line[:id])
    worksheet[0][linecnt+1].change_text_wrap(true)
    worksheet[0][linecnt+1].change_font_size(6)

    prev_hour = 0 #初期値を仮に0にする

    line.css('time').each do |time|

      date = time[:s][0,8]
      hhmm = time[:s][8,4].to_s
      hour = hhmm[0,2].to_i

      if date != adate
        hour += 24
      end

      if prev_hour != hour
        pgcnt = idx[hour]
      end

      prev_hour = hour

      program = hhmm + " "

      time.css('p').each do |p|
        #puts p.text
        program += p.text
      end

      worksheet.add_cell(pgcnt+1, linecnt+1, program)
      worksheet[pgcnt+1][linecnt+1].change_text_wrap(true)
      worksheet[pgcnt+1][linecnt+1].change_font_size(6)

      #次の番組
      pgcnt += 1

    end

    #次の局
    linecnt += 1

  end
end

workbook.write(file)

実行してみる

$ ./add_tvprog2xlsx.rb 20241103 20241103.45.temp

1つ目の引数は、日付(yyyymmdd)。番組表のexcelファイル名は、yyyymmdd.xlsxとなる。
2つ目の引数は、yyyymmdd.xlsxに追加する番組表のファイルで、番組表をワークシートで追加する。

実行してみる その2

地上デジ(神奈川)とBSの番組をダウンロードし、20241110.xlsxに追加する。

$ curl "https://bangumi.org/epg/td?broad_cast_date=20241110&ggm_group_id=45" | ./get_tvprog.rb > 20241110.45.temp
$ curl "https://bangumi.org/epg/bs?broad_cast_date=20241110" | ./get_tvprog.rb > 20241110.b.temp
$ ./add_tvprog2xlsx.rb 20241110 20241110.45.temp 20241110.b.temp



RubyXLで詰まった部分の解消方法と基本動作について

https://qiita.com/arukuishi/items/70014c8040f0409cb35a

ver3.4.0からリソースの無駄を抑えられるように用途に応じたメソッドが呼び出せるようになりました
どちらかと言えば、呼び出さないと使えなくなったのでundefined method Errorが出る場合は確認してください
...