0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【SamuraiStats】1. 日本人メジャーリーガーの成績をスクレイピング

Last updated at Posted at 2023-05-26

初投稿です。
日本人メジャーリーガーの成績を一目で見たい、と思い 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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?