【HSP】2017年版 F1ランキングページを生成してみる【その9】

Williams

前回はグランプリごとのリザルトページをデータ(CSV)化と簡易htmlページを出力まで完成しました。今回は全戦の結果をまとめたCSVの出力と、重複した場合の処理をプログラミングしていきたいと思います。

ドライバー単位でレースの結果データからポイントとなるものを全戦結果CSVに組み込んでいく予定です。前回のおさらいになりますが、拾うデータは

  • 順位
  • ポイント
  • ラップ(タイム差)

の3項目としました。さっそく全戦csvに取り掛かってまいりましょう。

スポンサーリンク

2016年の全戦をデータ化してみる(続き)

前回のプログラムを利用していきます。部分部分を取り出して書いていきますので、全コードを確認したい場合はページの一番下をみてみてくださいな(コピペ)。

全戦CSV用にセッティング

最初に入れ物を用意しておきます。

allresult_csv = ""

さらに、元々全戦CSVファイルが存在しているかの確認もしておく必要があります。これは以前のURL抽出と同じ方法が使えば解決。ただし、ファイル名を決めておく必要があります。ここでは

allresult.csv

という名前にしました。では、この名前のファイルが存在するかをチェックするコードを記述しましょう。

dirlist chk, "allresult.csv"
await 1
if (stat = 0) {
    (存在しない場合に入れ物を用意し、基本的な中身を入れておく)
} else {
    notesel allresult_csv
    noteload "allresult.csv"
    noteunsel
}

これでチェック部分はOK

基本的な中身の記述

上の部分にて「基本的な中身」を用意しなければいけません。元々あって欲しい中身は

  • 項目名(見出し部分)
  • トライバー名

なのですが、ドライバーはシーズン途中での変更やピンチヒッターなんてことも考えられます。なので、初めから用意するのではなく、結果から抽出して加えていくスタイルにしたいと思います。ということで、最初から入れる中身は

allresult_csv = "drivername"

これだけになります。

追加していくデータの成形(項目部分)

まず、項目部分にレース名とあわせて「順位」「ポイント」「ラップ」を追加してあげる必要があります。

(追加する項目の1文) += "," + gpname_now + ":pos,pts,laps"

「追加する項目の1文」という部分なのですが、プログラミングとしては、項目部分だけを取り出して、そこを書き換える形で進め行きたいと考えてます。なので、上に書いたコードは書き換える内容となるわけです。これをもともとの項目部分に上書きしてあげる形となります。そのためには

指定行の追加・変更

noteadd p1,p2,p3

p1=文字列 : 追加・変更をする文字列または変数名
p2=0~(-1) : 追加するインデックス
p3=0~1(0) : 上書きモード指定(0=追加・1=上書き)

これを使います。項目はcsvの一番最初に存在するのでp2のインデックスは「0」、上書きモードなのでp3は「1」になります。

(追加する項目の1文) += "," + gpname_now + ":pos,pts,laps"
noteadd (追加する項目の1文), 0, 1

追加していくデータの成形(新規ドライバーのデータ)

次にデータの本体をつくっていきます。まず、ドライバー名がデータに存在するのかどうかを確認して、なければドライバー名の追加という処理を考えていきましょう。存在の確認は「if instr」で行います。

drivername = firstname(cnt) + " " + familyname(cnt)
if (instr(allresult_csv, 0, drivername) = -1) : (いない場合の処理)

いない場合の処理はドライバー名から新たに追加する必要があります。また、現在が何戦目なのかによって、レース結果を追加する場所が変わって来る点も考慮しないといけません。その判定方法なのですが、

  • 項目部分の数から判断する

という方法で進めてみようと思います。場合分けで考えてみましょう。

【初戦の場合】
項目数はdrivernameのひとつのみ → 項目数 1

【2戦目の場合】
項目数はdrivernameと初戦の3つ → 項目数 1+3

【n戦目の場合】
項目数はdrivernameと{3×(n-1)} → 項目数 1+3(n-1)

項目数の関係は整理できました。実際に項目数を判定するにはsplitを使います。本来はひとつの文を切り分けるのにつかう命令ですが、実行するとstatに切り分けた数が格納されるので、これを利用します。

split (項目の1文), ",", buf
comma = stat

で、項目数の数「,」を追加してからデータを入れることで対応できるようになるはずです。

addcomma = "" : repeat comma: addcomma += "," : loop
(driver単位) = drivername + addcomma + position(cnt) + "," + getpoint(cnt) + "," + laps(cnt) +"(" + times(cnt) + ")"

追加していくデータの成形(既存ドライバーのデータ)

次にドライバーがデータに存在している場合の処理です。全戦参加している場合は都度追加していくことで問題はないのですが、怪我などで欠場があったりした場合はその部分を補完してあげないといけません。なので、こちらも項目数とドライバー単位データの数を比較しておく必要がありそうです。そして比較した数の分だけコンマを追加してあげればいいので、

split (driverの1文), ",", buf
dirver_comma = comma - stat + 1
addcomma = "" : repeat dirver_comma : addcomma += "," : loop
(driver単位) += addcomma + position(cnt) + "," + getpoint(cnt) + "," + laps(cnt) +"(" + times(cnt) + ")"

こんな感じになりました。1を追加しているのは、欠場などがない場合でもコンマをひとつ追加する必要があったのでそうしてます。

追加していくデータ3つを組み合わせる

上3つで作成したものを組み合わせてみましょう。実際にプログラミングしていく段階で少し変更をほどこしています。

  • ドライバーが存在しない場合の処理はallresult_csvの中身の最後に追加する処理に
  • ドライバーが存在するかどうかのチェック(if文)の処理を追加
  • 項目部分の一文をあらかじめ取り出して処理しておく
  • 項目部分取り出し処理の後に追加処理をする
  • repeat~loopを入れ子にするので、データをいったん格納する
  • ドライバー部分にもnoteadd処理を追加/ 項目部分取り出し・追加
/* 項目部分取り出し・追加 */
notesel allresult_csv
noteget text_line, 0
split text_line, ",", buf
comma = stat
text_line += "," + gpname_now + ":pos,pts,laps"
noteadd text_line, 0, 1

(csv作成のrepeat)

/* データの格納しなおし */
drivername = firstname(cnt) + " " + familyname(cnt)
data_box = position(cnt) + "," + getpoint(cnt) + "," + laps(cnt) +"(" + times(cnt) + ")"
/* ドライバーデータの追加 */
if (instr(allresult_csv, 0, drivername) = -1) {
    addcomma = "" : repeat comma: addcomma += "," : loop
    allresult_csv += drivername + addcomma + data_box + "\n"
} else {
    repeat notemax
        noteget text_line, cnt
        if (instr(text_line, 0, drivername) ! -1) {
            split text_line, ",", buf
            dirver_comma = comma - stat + 1
            addcomma = "" : repeat dirver_comma : addcomma += "," : loop
            text_line += addcomma + data_box
            noteadd text_line, cnt, 1
        }
    loop
}

(csv作成のloop)
noteunsel

そして、作成したcsvを保存しておきましょう。

// allresult出力
notesel allresult_csv
notesave "allresult.csv"
noteunsel
await 1

これで準備完了。いったん、前回実行したときに生成されたhtmlやcsvを削除して実行してみると


生成も無事できてますし、中身も2戦目で欠場したアロンソの部分など処理できています。大丈夫そうですね。

まとめ

今回はここまで。今のところ2016年での確認なので2017年シーズンになってあらためて実行してみないとわかりませんが、一応全戦結果のcsvファイル作成まで完了しました。次回は、フォルダに大量のファイルが生成されるようになってきてしまったので、これを整理するようにフォルダを用意してそこに保存させる仕組みを考えていきたいと思います。今回もコードを記載します。ぜひ試してみてくださいね。

//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"
    //#include "hspext.as"

    // csv_check
    dirlist chk, "Raceresulturl.csv"
    await 1
    if (stat = 0) {
        csv_text = "GP Name,URL\n"
    } else {
        notesel csv_text
        noteload "Raceresulturl.csv"
        noteunsel
    }
    dirlist chk, "allresult.csv"
    await 1
    if (stat = 0) {
        allresult_csv = "driver Name"
    } else {
        notesel allresult_csv
        noteload "allresult.csv"
        noteunsel
    }


    // ネット接続の確認
    netinit
    if stat : dialog "ネット接続できません" : end

    // 初期設定
//  download_url = "https://www.formula1.com/en/results.html/2017/drivers.html"
//  download_url = "https://www.formula1.com/en/results.html/2016/races/938/australia/race-result.html"
    sdim firstname,  40, 40
    sdim familyname, 40, 40
    sdim country,    40, 40
    sdim teamname,   40, 40
    sdim getpoint,   40, 40
    // 追加したもの
    sdim position,   40, 40
    sdim carnumber,  40, 40
    sdim laps,       40, 40
    sdim times,      40, 40
    sdim geturl,     200, 40
    sdim gpname,     200, 40

    //レースリザルト一覧ページダウンロード
    download_url = "https://www.formula1.com/en/results.html/2016/races.html"
    gosub *dl_start


    /*url抽出部分*/
    *skippoint //チェック用ラベル
    notesel htmlfile
    noteload url_pagename
    url_cnt = 0
    repeat notemax
        noteget text_line, cnt
        // RACE_URL
        if (instr(text_line, 0, "dark bold ArchiveLink") ! -1) {
            split text_line, "\"", buf
            // csv_text check
            if (instr(csv_text, 0, buf(1)) ! -1) : continue
            // geturl
            geturl(url_cnt) = buf(1)
            noteget gpname(url_cnt), cnt+1
            strrep gpname(url_cnt), " ", ""
            gpname(url_cnt) += " GP result"
            url_cnt++
        }
    loop
    noteunsel

    //make_csv
    repeat 40
        if gpname(cnt) = "" : break
        csv_text += gpname(cnt) + ",https://www.formula1.com" + geturl(cnt) + "\n"
    loop

    // csv出力
    if (gpname(0) ! "") {
        notesel csv_text
        notesave "Raceresulturl.csv"
        noteunsel
        await 1
        dialog "save new csv file"
    }




    // url→raceresultダウンロード

    notesel csv_text
    noteload "Raceresulturl.csv"
    repeat notemax
        noteget text_line, cnt
        split text_line, ",", gpname(cnt), geturl(cnt)
    loop
    noteunsel
    await 1

    repeat 40, 1
        if gpname(cnt) = "" : break //レース名が空なら終了
        //レース結果のCSVファイルが存在してるかチェック
        dirlist chk, gpname(cnt)+".csv"
        if (stat ! 0) : continue
        //存在していない場合、ダウンロードする
        download_url = geturl(cnt)
        gosub *dl_start
        //データ化処理をする
        gpname_now = gpname(cnt)
        gosub *race_csv
    loop

    end
    stop



    /* ダウンロードサブルーチン化 */
    *dl_start
    // URL分解
    if (instr(download_url, 0, ".html") ! -1) or (instr(download_url, 0, ".php") ! -1) { //.html .phpが含まれているなら
        split download_url, "/", result
        url_pagename = result(stat-1)
        url_address  = download_url
        strrep url_address, url_pagename, ""
    } else { // 含まれていない場合はindex.htmlにする
        url_address  = download_url
        url_pagename = "index.html"
    }

    neturl url_address
    netrequest url_pagename

    *main
    //取得待ち確認
    netexec res
    if res > 0 : goto *comp
    if res < 0 : goto *bad
    await 50
    goto *main

    *bad
    //エラー
    neterror estr
    dialog "ERROR "+estr
    end
    stop

    *comp
    mes "DOWNLOAD 完了"
    lfcc url_pagename

    return


    /* レース結果処理サブルーチン化 */
    *race_csv
    notesel htmlfile
    noteload url_pagename
    first_cnt = 0 : family_cnt = 0 : country_cnt = 0 : teamname_cnt = 0
    position_cnt = 0 : carnumber_cnt = 0 : laps_cnt = 0 : times_cnt = 0
    repeat notemax
        noteget text_line, cnt
        // 着順
        if (instr(text_line, 0, "<td class=\"dark\">") ! -1) {
            strrep text_line, "<td class=\"dark\">", ""
            strrep text_line, "</td>", ""
            strrep text_line, " ", ""
            position(position_cnt) = text_line
            position_cnt++
            continue
        }
        // カーナンバー
        if (instr(text_line, 0, "<td class=\"dark hide-for-mobile\">") ! -1) {
            strrep text_line, "<td class=\"dark hide-for-mobile\">", ""
            strrep text_line, "</td>", ""
            strrep text_line, " ", ""
            carnumber(carnumber_cnt) = text_line
            carnumber_cnt++
            continue
        }
        // ファーストネーム
        if (instr(text_line, 0, "<span class=\"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, "<span class=\"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
        }
        // 所属チーム
        if (instr(text_line, 0, "semi-bold uppercase hide-for-tablet") ! -1) {
            split text_line, ">", buf
            split buf(1), "<", result
            teamname(teamname_cnt) = result(0)
            teamname_cnt++
            continue
        }
        // ラップ
        if (instr(text_line, 0, "<td class=\"bold hide-for-mobile\">") ! -1) {
            strrep text_line, "<td class=\"bold hide-for-mobile\">", ""
            strrep text_line, "</td>", ""
            strrep text_line, " ", ""
            laps(laps_cnt) = text_line
            laps_cnt++
            continue
        }
        // タイム
        if (instr(text_line, 0, "<td class=\"dark bold\">") ! -1) and (instr(text_line, 0, "</td>") ! -1) {
            split text_line, ">", buf
            split buf(1), "<", result
            times(times_cnt) = result(0)
            times_cnt++
            continue
        }
        // 獲得ポイント
        if (instr(text_line, 0, "<td class=\"bold\">") ! -1) {
            strrep text_line, "<td class=\"bold\">", ""
            strrep text_line, "</td>", ""
            strrep text_line, " ", ""
            getpoint(point_cnt) = text_line
            point_cnt++
            continue
        }

    loop
    noteunsel

    //make_area
    html_text = "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta http-equiv=\"content-language\" content=\"ja\">\n<title>2017レースリザルト</title>\n<style>\nbody {\ncounter-reset: drivername;\n}\nli {\ndisplay: flex;\n}\ndiv {\nmargin-right: 1rem;\n}\n.drivername, .team {\nwidth: 12rem;\n}\n.country {\nwidth: 6rem;\n}\n.drivername:before {\ncounter-increment:drivername;\ncontent:counter(drivername) \"位 \";\ndisplay: inline-flex;\nwidth: 3rem;\n}\n</style>\n</head>\n<body>\n<h1>2017レースリザルト</h1>\n<ul>"
    csv_text = "position,firstname,familyname,carnumber,teamname,point,laps,times\n"
    /* 項目部分取り出し・追加 */
    notesel allresult_csv
    noteget text_line, 0
    split text_line, ",", buf
    comma = stat
    text_line += "," + gpname_now + ":pos,pts,laps"
    noteadd text_line, 0, 1

    repeat 40
        if firstname(cnt) = "" : break
        html_text += "<li>\n<div class=\"position\">[" + position(cnt) + "]</div>\n<div class=\"drivername\">" + firstname(cnt) + " " + familyname(cnt) + "</div>\n<div class=\"country\">" + carnumber(cnt) + "</div>\n<div class=\"team\">" + teamname(cnt) + "</div>\n<div class=\"point\">" + getpoint(cnt) + "pt</div>\n<div class=\"times\">" + laps(cnt) + "(" + times(cnt) + ")</div>\n</li>\n"
        csv_text += position(cnt) + "," + firstname(cnt) + "," + familyname(cnt) + "," + carnumber(cnt) + "," + teamname(cnt) + "," + getpoint(cnt) + "," + laps(cnt) + "," + times(cnt) + "\n"

        /* データの格納しなおし */
        drivername = firstname(cnt) + " " + familyname(cnt) : title gpname_now + ":" + drivername
        data_box = position(cnt) + "," + getpoint(cnt) + "," + laps(cnt) +"(" + times(cnt) + ")"
        /* ドライバーデータの追加 */
        if (instr(allresult_csv, 0, drivername) = -1) {
            addcomma = "" : repeat comma: addcomma += "," : loop
            allresult_csv += drivername + addcomma + data_box + "\n"
        } else {
            repeat notemax
                noteget text_line, cnt
                if (instr(text_line, 0, drivername) ! -1) {
                    split text_line, ",", buf
                    dirver_comma = comma - stat + 1
                    addcomma = "" : repeat dirver_comma : addcomma += "," : loop
                    text_line += addcomma + data_box
                    noteadd text_line, cnt, 1
                }
            loop
        }
    loop
    noteunsel
    html_text += "</ul>\n</body>\n</html>\n"


    nkfcnv html_text,html_text,"Sw"

    //HTML出力
    notesel html_text
    notesave gpname_now + ".html"
    noteunsel
    await 1
    // csv出力
    notesel csv_text
    notesave gpname_now + ".csv"
    noteunsel
    await 1
    // allresult出力
    notesel allresult_csv
    notesave "allresult.csv"
    noteunsel
    await 1

    mes "save html file"
    return

stop
スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする