初投稿です。
日本人メジャーリーガーの成績を一目で見たい、と思い JavsScript でコーディングしました。
とりあえずスクレイピングの基礎は完成したよ、という記事です。
きっかけ
プロ野球(NPB)観戦が趣味なのですが、最近は日本人メジャーリーガーの活躍が目覚ましく、ヌートバーの活躍も嬉しいということで、彼らの成績チェックも日課になっています。
メジャーの試合時間は、日本時間だとだいたい深夜~昼前くらいです。
おかげで、朝はメジャー、夜はプロ野球と野球に囲まれて楽しい日々です。
ちなみにロッテファンです。
成績のチェックは スポナビ さんにお世話になっています。
ただ、成績を確認するには各選手のページか、所属チームの試合ページを開く必要があり、一括で見れないのが手間でした。
そこで、今回のコーディングに至りました。
ChatGPTの協力のおかげで思ったよりスムーズに書けました。
コード
さっそくですが、現状のコードです。コード全体は Github にあるので、重要な部分だけ貼り付けようと思います。 →Twitter API周りの情報もあるので一旦非公開。この記事にあるコードで十分なはず。
レポジトリ名は scrapingTest となっていますが、SamuraiStats に変える予定です。
インポート
import axios from "axios";
import cheerio from "cheerio";
const url = "URL"
axios.get(url).then((response) => {
const html = response.data
const $ = cheerio.load(html)
//ここから先は下記
})
めっちゃ雑談:axiosとcheerioをインポートして使用しています。ChatGPTにおすすめされました。
一応、「PuppeteerとCheerioどっちにする?」と聞かれたので、比較して選択しましたが、再現性が低いな~知識つけなきゃな~と思ったり。とりあえず今回はコーディング優先。
パーツとなる関数
①CSSセレクタを使って要素を指定し、取ってきて、returnする。
"fetchToArray"となっているが、array以外でも使うことになるので名前変更しなきゃいけない。
const fetchToArray = (cssSelector) => {
let returnArray = [];
const elements = $(cssSelector);
//セレクタに一致する要素がない時、エラーを吐く
if (elements.length === 0) {
throw new Error(`No elements found for selector: ${cssSelector}`);
}
elements.each((i, e) => {
returnArray.push($(e).text().trim());
});
return returnArray;
};
②取ってきた要素の配列2つをつなげる。
Tableからヘッダ(th)とデータ(td)を別々で取ってくるため。
const mergeTableArrays = (headArray, dataArray) => {
let returnArray = [];
if (headArray.length === dataArray.length) {
for (let i = 0; i < headArray.length; i++) {
returnArray.push(headArray[i] + ":" + dataArray[i]);
}
return returnArray;
} else {
console.error("dataLength don't match");
console.error(`array1.length: ${headArray.length}`);
console.error(`array2.length: ${dataArray.length}`);
}
};
使用例
//名前の表示
const name = fetchToArray("#contentMain > div.bb-centerColumn > div > div.bb-modCommon01 > div > div > div.bb-profile__data > ruby > h1");
console.log(name);
//最新試合成績の表示
const recentStatsHeader = fetchToArray("#game_b > thead > tr > th");
const recentStatsData = fetchToArray("#game_b > tbody > tr:nth-child(1) > td");
const recentStats = mergeTableArrays(recentStatsHeader, recentStatsData);
console.log(recentStats);
以下が出力したログです。
(1) ['吉田 正尚']
(11) ['日付:5月25日', '対戦チーム:エンゼルス', '打数:4', '安打:1', '本塁打:0', '打点:0', '得点:1', '三振:0', '四球:0', '死球:0', '打席結果:一併打、中2、二ゴロ、一ゴロ']
こんな感じでスクレイピングできました。
「名前の表示」において、「fetchToArrayがarrayを返していない、nameという名称もよくない」という問題があり、そのほかにも
- データベース構築:おそらくLocalStorageを使用
- 指定日時に更新を確認し、更新があれば成績を取得しなおす
- できればツイートする
- 各選手にまつわる絵文字をつける。成績に応じて増減する
- 非同期処理まわりの理解
……等々、タスクが残りまくっていますが、とりあえずスクレイピングの基礎は完成。
月2本程度で記事を書いていければと思うので、次回のネタになると思います。
ほな、また。
記録:初挑戦:import/export