【Python開発奮闘記】APIの壁と戦い、Webスクレイピングで金属価格を取得するまで

ALL

こんにちは、Tech Samuraiです!
今回は、金属・商品価格表示スクリプトを開発する過程で、私が直面したAPIの厳しい現実と、**Webスクレイピングの数々の罠**、そして最終的にどうやってそれを乗り越えたのか、その全記録を共有します。

当初の計画は「APIを使ってスマートに」でしたが、現実はそんなに甘くありませんでした。これは、理想と現実のギャップと戦い、試行錯誤の末にゴールにたどり着いた、一人の開発者の物語です。


第1章:APIの夢と、高すぎた壁

最初の計画は、公開されているAPIを利用して、スマートに価格データを取得することでした。Commodities-APIFinancial Modeling Prep (FMP)といったサービスに目をつけ、APIキーを手にし、Pythonの`requests`ライブラリでデータを取得。ターミナルに価格が表示された時、私は「計画通りだ」と確信していました。

しかし、その喜びは長くは続きませんでした。

  • プランの変更: Commodities-APIは、かつての無料プランが「7日間の無料トライアル」に変わっており、継続的な利用は不可能でした。
  • 機能制限の壁: FMP`に切り替えたものの、今度はエラーとの長い戦いが始まりました。APIキーのコピペミスはすぐに解決できましたが、無料アカウントではアクセスできないURL (`403 Forbidden`) や、金・銀以外の価格を取得しようとすると表示される「有料プラン限定」の壁 (`402 Payment Required`) に阻まれ、計画は頓挫しました。

【教訓】
APIは非常に便利ですが、無料プランでできることには限りがある。特に、取得できるデータの種類や量には厳しい制限があることを痛感しました。


第2章:Webスクレイピングへの転換と、新たなる苦難

APIに見切りをつけた私は、ウェブサイトから直接情報を抜き出す「Webスクレイピング」へ方針を転換。ターゲットは金属価格情報が豊富なKitcoのサイトです。

Pythonの`BeautifulSoup`ライブラリを使い、価格が載っているHTML要素を特定してデータを抜き出す。ロジックはシンプルに見えましたが、ここでも様々なエラーが私を襲います。

  1. `FeatureNotFound: lxml`: HTML解析ライブラリ`lxml`が環境になく、rye add lxmlで解決。
  2. `SSLError: CERTIFICATE_VERIFY_FAILED`: サイトのSSL証明書の問題で接続が拒否される。最終的には証明書の検証を無効にする「禁じ手」で突破。
  3. データ取得失敗: エラーは出ないものの、価格が取得できない。サイトのHTML構造が更新されており、スクリプトの目印が古くなっていたのが原因でした。

【教訓】
Webスクレイピングは強力ですが、ターゲットサイトの構造変更に非常に弱い、脆い技術です。一つのサイトに固執せず、構造がよりシンプルなサイトを探す判断も重要だと学びました。


第3章:Bloombergでの最終決戦と、灯台下暗し

そして、最終的にたどり着いたのが`Bloomberg`のサイトでした。ここのHTML構造は比較的きれいで、スクレイピングの最後の望みを託しました。

幸い、「始値」というラベルの隣にその価格が、「出来高」の隣にその数値が記載されている、という一貫したレイアウトになっていました。そこで、「まずラベルの文字を探し、その隣の要素を取得する」という、より人間の視点に近いロジックを実装し、主要な価格データは安定して取得できるようになりました。

しかし、最後の壁が立ちはだかります。なぜか「銘柄名」だけが取得できないのです。ブラウザの検証ツールで見ると、銘柄名は単純な

`タグで囲まれているはずなのに…。

ブレークスルー

複雑なクラス名を正規表現で探そうとして失敗を繰り返した後、私は原点に立ち返り、もう一度ブラウザの検証ツールでHTMLを丹念に確認しました。そこにあったのは、

<h1 class="name"> 金先物  TCM </h1>

という、これ以上ないほどシンプルな構造でした。私の思い込みと、以前の複雑な試みが、この最も簡単な正解を見えなくしていたのです。「灯台下暗し」とは、まさにこのことでした。

スクリプトの銘柄名を探す部分を、soup.find('h1', class_='name')`というシンプルな一行に書き換えたことで、ついに全てのデータを完璧に取得するスクリプトが完成しました。


完成したスクリプトとリポジトリ

この長い戦いを経て完成したスクリプトは、以下のGitHubリポジトリで公開しています。

# 最終的に完成したBloombergスクレイピングのコアロジック (metal_bloomberg.py)
import requests
from bs4 import BeautifulSoup
import re

def scrape_bloomberg_quote(url):
    """
    指定されたBloombergのURLから価格データをスクレイピングする。
    """
    try:
        headers = { 'User-Agent': '...' }
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        soup = BeautifulSoup(response.content, 'lxml')

        def find_value_by_label(label_text):
            # ... (ラベルを元に値を探すヘルパー関数) ...
            pass

        # ▼▼▼ ブレークスルーとなった箇所 ▼▼▼
        name_element = soup.find('h1', class_='name')
        quote_name = name_element.get_text(strip=True) if name_element else "銘柄名N/A"
        # ▲▲▲ ここが最終的な答えだった ▲▲▲

        # ... (各項目を取得して表示する処理) ...

    except Exception as e:
        print(f"❌ エラーが発生しました: {e}")

# ... (メイン処理) ...

最終的な教訓

この開発奮闘記から得られた最大の教訓は、**エラー解決の鍵は、ツールの出力や自分の思い込みだけでなく、一次情報(今回の場合は実際のHTML)を直接、注意深く観察することにある**、という点です。複雑な解決策を試す前に、最もシンプルな方法が使えないか検討することが、遠回りに見えて実は一番の近道でした。

コメント

タイトルとURLをコピーしました