MYmemo

思い立ってやってみるけど、長続きしない。せめて記録しておく。

Termux上でまた動かなくなったyfinanceを無理やり動かす方法

前回記事ではyfinanceのバージョンをダウングレードすることによってtermux上で動かす話について書きましたが、そのあと別のエラーで動かなくなりました。

mymemo8.hatenablog.com


1回か2回くらいは動いたんですけどね...違うエラーになってしまうんですよね。

File "/data/data/com.termux/files/usr/lib/python3.12/site-packages/yfinance/data.py", line 409, in _make_request
    raise YFRateLimitError()
yfinance.exceptions.YFRateLimitError: Too Many Requests. Rate limited. Try after a while.

んで、Try after a while しても結果は同じなんですよ。



yfinanceのAPI仕様変更が原因

色々調べてみたら本件の全容をやっと理解できました。私の理解は以下です(間違ってたらすみません)


Yahoo Financeがスクレイピング対策した

こちらはyfinanceのリリース情報です。
github.com

ver. 0.2.58 の変更内容の中に、こんな一文があります

switch to curl_cffi session to fix false rate-limit errors #2430 [reason=TLS fingerprinting]

これまでyfinanceではYahoo Finance APIからのデータ取得にrequestsライブラリを使っていたらしいのですがYahoo Financeがスクレイピング対策を強化した結果、requestsライブラリではデータ取得が難しくなったためデータ取得のためのライブラリをcurl_cffiに「switch」したらしい。curl_cffiライブラリを使えば、より実際のブラウザのような挙動を再現してアクセスすることができるらしい。


requestsライブラリなのかcurl_cffiライブラリなのか?は、バージョンが0.2.57以下か0.2.58以上か、ここが境目です。でバージョン0.2.57以下(requests)でも全く動かないってことではないが、API側のアクセス制限にすぐ引っ掛かってしまう結果、冒頭のエラーになってしまう。そういうことだと理解しました。



Termux側の問題

しかし、yfinanceをバージョン0.2.58以上にすると、前回記事で書いたように、それはそれでエラーになります。

ImportError: dlopen failed: library "libcurl-impersonate.so.4" not found: needed by /data/data/com.termux/files/usr/lib/python3.12/site-packages/curl_cffi/_wrapper.abi3.so in namespace (default)


これに対するGemini先生の見解を仰ぎますと...

このエラーは、curl_cffiというライブラリが、libcurl-impersonate.so.4という共有ライブラリを見つけられないために発生しています。yfinanceは最近、スクレイピング対策のためにcurl_cffiを内部的に利用するようになっているため、この問題が発生している可能性が高いです。Termux環境にcurl_cffiが必要とすlibcurl-impersonate.so.4というライブラリがインストールされていないか、パスが正しく通っていないことが原因です。このライブラリは、標準的なlibcurlとは異なり、より高度なウェブスクレイピング(ボット対策を回避するなど)のために使われるものです。


フムフム...


残念ながら、Termuxの公式パッケージリポジトリには、現在のところlibcurl-impersonateを直接提供するパッケージは存在しないようです。応急手段としては。curl_cffiの代わりにrequestsを使うようにyfinanceをダウングレードする (推奨される可能性が高い)方法があげられます。


いや、それはアカンねん!!

他の方法は?と、前回記事で結構検討しましたね....。





TermuxにUbuntuを入れてみた

これは前回記事を書いたときも一瞬考えましたが、スマホの要領食いそうだから後回しにしてましたが、いよいよこれしか方法が思い付かなくなってきたんで、トライすることにしました。一応Gemini先生にも意見仰ぎますと

Termux上でUbuntuを動かすことは可能です。正確には、TermuxはAndroid上で動作するLinux環境ですが、そのTermux環境内にUbuntuの最小限のファイルシステムを構築し、CLIベースでUbuntuのパッケージ管理やコマンドを利用できるようになります。TermuxでUbuntuを動かす主なメリットはTermuxのデフォルトリポジトリにはない、Ubuntuリポジトリで提供されている多くのソフトウェアやライブラリを利用できることです。また、一般的なLinux環境の再現することで、Ubuntuを前提とした多くのLinuxチュートリアルや開発環境が利用できます。


いいじゃないですか!

Termux上のUbuntu環境なら、yfinanceを動かせる可能性が高くなります。libcurl-impersonate.so.4が見つからないエラーはTermuxのデフォルト環境でライブラリが提供されていないために発生します。しかしUbuntuの標準リポジトリにはlibcurl-impersonateという名前のパッケージは直接ありませんが、curl_cffiはインストール時に必要なlibcurl-impersonateを自動的にビルドするか、互換性のある既存のライブラリを利用しようとします。curl_cffiのPyPIページによると、curl_cffiはLinux(x86_64/aarch64)向けにプリコンパイルされたバイナリホイール(*.whlファイル)を提供しており、これにはlibcurl-impersonateがバンドルされている可能性があります。 Termux上のUbuntuは一般的なLinuxのaarch64アーキテクチャとして認識されるため、このホイールが利用できる可能性が高いです。


では今回はproot-distroを使いますね。Termuxの標準ツールでUbuntuの他、DebianFedoraなどの様々なLinuxディストリビューションを簡単にインストールきます。

pkg update
pkg upgrade
pkg install proot-distro
proot-distro install ubuntu
proot-distro login ubuntu
# root@localhost:~#


Ubuntu環境に入るとプロンプトがroot@****:~に変わるはず。私は1発成功でした。Ubuntu環境から出るには exitと入力ですね。ちなみにUbuntsu環境を作ったとき、Ubuntsu側からみたフォルダ構成はこんな感じになりました。こんな感じでデータの受け渡しが可能です。

/
├─root──ubuntu環境
│
└─storage─emulated─0─termux環境



せっかくなのでUbuntu内の環境を最新にします

apt update
apt install python3-pip
pip install --upgrade pip

これでどうだ!?




で、動かしてもエラーになるんだけど?

Ubuntu環境整ったんで、早速yfinance動かしてみるとだな...

ImportError: dlopen failed: library "libcurl-impersonate.so.4" not found: needed by /data/data/com.termux/files/usr/lib/python3.12/site-packages/curl_cffi/_wrapper.abi3.so in namespace (default)

いや、エラー変わらん....

てか、なんもインストールしてないのに、そもそもなんで動くんや?!
いや、エラーよくみたらtermux側のライブラリ見に行ってるやん?!



きっちりUbuntu側の環境を使うように設定する

これは、Termux上でproot-distroを使った場合によくある状況です。proot-distroは完全に独立した仮想マシンではありません。特にTermux側のPATH環境変数や、プロセスの実行環境がUbuntu側に引き継がれてしまうことがあります。結果、Pythonを実行する際にTermux側のPythonパスが優先されてしまい、Ubuntu側にインストールしたはずのyfinanceやcurl_cffiではなく、Termux側のPythonが使われてしまうのです。


ということで、仮想環境 (venv) を使うことにします。Ubuntu環境にログインした状態で、任意のフォルダ(今回はtest_venvにします)を用意してそこに環境作ります。一連の流れは以下の通り。python3 -m venvで仮想環境venv_yfinanceができあがり、source venv_yfinance/bin/activateで仮想環境をアクティベートします。プロンプトの先頭に(venv_yfinance)のような表示が出れば、仮想環境がアクティブになっています。なお仮想環境を終了する際はdeactivateコマンドを使用します。


mkdir test_venv
cd test_venv
python3 -m venv venv_yfinance
source venv_yfinance/bin/activate
(venv_yfinance) #root@local:~/ 


フォルダ体系的には以下のようになるハズ

/
├─root(ubuntu環境)──test_venv──venv_yfinance
│
└─storage─emulated─0─termux環境


あとは必要なライブラリやなんやらをインストールしていきます。

pip install curl_cffi yfinance



ここまですれば、うごくでしょ!?



ということで、無事yfinanceを動かすことができました!

ちなみに、この状態だとpythonコマンドは明示的にUbuntu側の環境を見に行ってうごくので、termux側のディレクトリにおいてあるyfinanceも動くようになります、が、せっかく仮想環境つくったんで、ちゃんと対象ファイルを仮想環境に持っていってから動かそうかなと思います。