前回は公式ページのダウンロードが完了したので、今回はそれを使って解析してデータを取り出していきたいと思います。
以前、[F1公式サイトのスクレイピング](アドレス)は以下から。
以前、スクレイピングの際に調べたやつ
以前、スクレイピングで調べた際の情報です。
- 【ドライバー名】
- ファーストネーム→クラス名(hide-for-tablet)、タグ(span)
- ファミリーネーム→クラス名(hide-for-mobile)、タグ(span)
- 【国籍】
- クラス名(dark semi-bold uppercase)、タグ(td)
- 【所属チーム】
- クラス名(grey semi-bold uppercase ArchiveLink)、タグ(a)
- 【獲得ポイント】
- クラス名(dark bold)、タグ(td)
という感じでした。
ダウンロードしたファイルの読み込み
まず、前回ダウンロードしたファイルの読み込みをしてみましょう。HSPで文章などのファイルを扱う場合はnote系の命令が便利です。詳細はリファレンスを参照してもらうとして主に使うのは
- notesel (ロードしたデータを入れる入れ物をセットする)
- noteload (ファイルをロードする)
- notesave (ファイルをセーブする)
- noteunsel (セットした状態を解除する)
- notemax (入れ物に入っているファイルの行数が格納される)
- noteget (一行ずつ文章を取り出す)
簡単な説明もつけましたが、見てもらってわかるようにこれらはワンセットで使うことが多いですね。HSPでcsvやtxt、htmlファイルもこれらの命令で扱えるので本当に便利ですよ。
ということで、ざっくりとファイル読み込みのスクリプトを書いてみたいと思います。
#include "hspinet.as" notesel htmlfile noteload "drivers.html" mesbox htmlfile, 640, 400 noteunsel stop
mesboxを使って、読み込んだファイルを表示させてみたのですが。。。
改行コードがうまく反映されていないようです。ここでは手軽に進めるために、HSPモジュールのでSAKMISさんが作成されたものを使用させていただきました(今はページが存在していないようです)。以下のコードを文頭に追加しておきます。使い方はlfcc “filename”とすごく簡単で便利ですよ。
//HSPモジュール SAKMISさんのを使用しています //命令→lfcc ファイルネーム //読み込み→改行置換→保存 #module #deffunc lfcc str filename ; mref filename,32 ; mref status,64 exist filename size=strsize if size=-1 : status=-1 : return sdim ss,size+1,1 bload filename,ss,size ii=0 code=0 sdim data,size<<1,1 repeat size tt = peek (ss,cnt) if tt=10 : code=10 : break if tt=13 { code=13 tt = peek (ss,cnt+1) if tt=10 : code=0 break } loop if code=0 : status=-1 : return repeat size tt = peek (ss,cnt) if tt=code : wpoke data,ii,2573 : ii+2 : continue poke data,ii,tt : ii++ loop bsave filename,data,ii status=ii return #global
これを追加した後に
lfcc "drivers.html"
これをnotesel htmlfileの前に追加して実行してみると
無事改行が反映されました。これで読み込み完了!
hide-for-tabletを探しだしてみる
hide-for-tabletはドライバーのファーストネームを調べるのに見当を付けていたクラス名でした(この記事の冒頭参照)。これをHSPで探し出してみるスクリプトを考えます。さきほど出てきていたnote系の命令でnotegetという1行ずつ取り出す命令を使っていきましょう。で、その行の中にhide-for-tabletが含まれているかどうかをチェックして、含まれていたらダイアログで表示するようにしてみたいと思います。読み込み部分をそのまま活用して…
lfcc "drivers.html" notesel htmlfile noteload "drivers.html" // mesbox htmlfile, 640, 400 repeat notemax noteget text_line, cnt if (instr(text_line, 0, "hide-for-tablet") ! -1) : dialog text_line loop noteunsel stop
文章で説明すると「mesboxをコメントアウト、repeat~loopをnotemax(行数)繰り返す。notegetで1行ずつ取り出して”hide-for-tablet”が含まれていたら、dialogでその内容を表示」という流れ。実際に実行してみると
と該当する部分が取り出せているのがわかります。
ほしい部分だけを取り出す
では、その一文を分解して、欲しいデータだけを取り出してみましょう。取り出していた部分で共通しているのは
<span class="hide-for-tablet">driver名</span>
というspanタグの部分。これを
- 不必要な部分(タグ)を取り除く
- >や<で切り分けて取り出す
の2パターンのやり方がありそうです。すべてが綺麗に間違えなくタグが書かれているのであれば
<span class="hide-for-tablet"> </span>
のふたつをstrrep命令を使って取り除いてしまってもいいかもしれません。その場合は
strrep text_line, "<span class=\"hide-for-tablet\">", "" strrep text_line, "</span>", "" strrep text_line, " ", ""
こんな感じで書いていくといい感じになるかと思います。試しに実行してみると
という感じです。大丈夫そうですね。もうひとつの方法はsplitを使って切り分ける方法
split text_line, ">", buf split buf(1), "<", result text_line = result(0)
タグの部分で切り分けて中身を取りだす作戦。こちらも実行してみると
問題なさそうです。どちらでもいいとは思いますが、こういうアプローチもあることを覚えておくいいかもですね。
ファーストネームを格納していく
取り出せたら、前回用意した入れ物に格納していきましょう。ファーストネームは
- firstname
の入れ物でした。配列宣言してあるので「firstname(0)」など0~39番まで入れ物が用意してある状態です。なので、1個入れたら数字を増やして次の箱に入れるような流れで進めていきたいと思います。これを踏まえてコードを書くと
lfcc "drivers.html" notesel htmlfile noteload "drivers.html" fname_cnt = 0 repeat notemax noteget text_line, cnt if (instr(text_line, 0, "hide-for-tablet") ! -1) { strrep text_line, "<span class=\"hide-for-tablet\">", "" strrep text_line, "</span>", "" strrep text_line, " ", "" firstname(fname_cnt) = text_line fname_cnt++ } loop noteunsel stop
実際にちゃんと代入されているかを確認するためにチェック表示させましょう。chkという入れ物を用意して、そこに結果を入れ込みます。
chk = "" lfcc "drivers.html" notesel htmlfile noteload "drivers.html" first_cnt = 0 repeat notemax noteget text_line, cnt if (instr(text_line, 0, "hide-for-tablet") ! -1) { strrep text_line, "<span class=\"hide-for-tablet\">", "" strrep text_line, "</span>", "" strrep text_line, " ", "" firstname(first_cnt) = text_line chk += "fistname("+first_cnt+") = " + firstname(first_cnt) + "\n" first_cnt++ } loop noteunsel mesbox chk, 640, 400 stop
無事に取り出せていますね。このパターンでファミリーネームのデータも取り出してみましょう。
hide-for-mobileを探し出し、ファミリーネームを取り出す
さきほどまでのファーストネームの復習ですね。こんどは「hide-for-mobile」のクラス名を探し出して、余分なものを消してファミリーネームだけを取り出す流れです。さきほどのrepeat~loop文の中に加えて書いていきます。格納するのはfamilynameです。カウントはfamily_cntとしました。
if (instr(text_line, 0, "hide-for-mobile") ! -1) { strrep text_line, "<span class=\"hide-for-mobile\">", "" strrep text_line, "</span>", "" strrep text_line, " ", "" familyname(family_cnt) = text_line family_cnt++ continue }
また、chkについてはわかりやすい処理にするために別枠で記述するようにしました。
chk = "" repeat 40 if firstname(cnt) = "" : break chk += "fistname("+cnt+"):familyname("+cnt+") = " + firstname(cnt) + ":" + familyname(cnt) + "\n" loop
実行結果をみてみると
うーん、キミライコネンの部分だけäやö表記になってしまってますが、それ以外は大丈夫そうですね。これでドライバー名の取得は完了です。次回は引き続きデータ取り出しの処理を書いていきたいと思います。
まとめ
データの取り出しは順調に進んできましたね。これを格納しおわったら、HSPでhtmlの作成に取り掛かる予定です。こうご期待!
以下は今回の全コードになります。試してみてくださいね!(前回のプログラムでダウンロードしたdrivers.htmlが必要です)
//HSPモジュール SAKMISさんのを使用しています //命令→lfcc ファイルネーム //読み込み→改行置換→保存 #module #deffunc lfcc str filename ; mref filename,32 ; mref status,64 exist filename size=strsize if size=-1 : status=-1 : return sdim ss,size+1,1 bload filename,ss,size ii=0 code=0 sdim data,size<<1,1 repeat size tt = peek (ss,cnt) if tt=10 : code=10 : break if tt=13 { code=13 tt = peek (ss,cnt+1) if tt=10 : code=0 break } loop if code=0 : status=-1 : return repeat size tt = peek (ss,cnt) if tt=code : wpoke data,ii,2573 : ii+2 : continue poke data,ii,tt : ii++ loop bsave filename,data,ii status=ii return #global #include "hspinet.as" // ネット接続の確認 netinit if stat : dialog "ネット接続できません" : end // 初期設定 download_url = "https://www.formula1.com/en/results.html/2016/drivers.html" sdim firstname, 40, 40 sdim familyname, 40, 40 sdim country, 40, 40 sdim teamname, 40, 40 sdim getpoint, 40, 40 lfcc "drivers.html" notesel htmlfile noteload "drivers.html" first_cnt = 0 repeat notemax noteget text_line, cnt // ファーストネーム if (instr(text_line, 0, "hide-for-tablet") ! -1) { strrep text_line, "<span class=\"hide-for-tablet\">", "" strrep text_line, "</span>", "" strrep text_line, " ", "" firstname(first_cnt) = text_line first_cnt++ continue } // ファミリーネーム if (instr(text_line, 0, "hide-for-mobile") ! -1) { strrep text_line, "<span class=\"hide-for-mobile\">", "" strrep text_line, "</span>", "" strrep text_line, " ", "" familyname(family_cnt) = text_line family_cnt++ continue } loop noteunsel //debug chk = "" repeat 40 if firstname(cnt) = "" : break chk += "fistname("+cnt+"):familyname("+cnt+") = " + firstname(cnt) + ":" + familyname(cnt) + "\n" loop mesbox chk, 640, 400 stop