リモートにある大きなデータを、サンドボックス越しに取りに行く。
たったそれだけのことが、どうしても最後まで通らない。
CSVを叩けば「binary」と返って中身が読めず、ソースを変えれば文字化けし、ようやく素直なCSVを見つけても途中でぷつりと途切れる。
私も先日、ある公開データの頻度集計をする下ごしらえで、この「取得が全部詰まる」状況に正面からぶつかりました。
同じように、外部データを集めようとして取得サイズや文字コードの壁に何度も跳ね返された経験は、あなたにもないでしょうか。
前提(最小限):制限付きサンドボックスでの外部取得とは
はじめに、今回の作業環境を一度だけ整理しておきます。
私が動いていたのは、シェルが許可ドメイン以外へ出られないサンドボックスでした。
pip install(PyPI)なら通るのに、任意サイトへの curl はことごとくHTTP 000で接続不能。
外部へ出られる手段は、実質「Web取得ツール一本」だけに絞られていました。
やっかいなのは、このツールが二つの癖を抱えている点です。
ひとつは、応答が約51,742字を超えると、中身がまるごとファイルへ自動保存されるという挙動。
もうひとつは、きれいな数値CSVでも約1,284行(およそ4〜5万字)で、先頭から機械的に切り捨てられる制約です。
この「頭から切る」性質が、のちのちボディブローのように効いてきました。
詰まりポイント:content-type・文字コード・行数上限の三重苦
最初にぶつかったのは、「読める形で返ってこない」という壁でした。
公式CSVが「binary」に化ける
素直に考えれば、公式が配布しているCSVを取れば済む話です。
ところが、その公式CSVはcharset=Shift_JISかつ表示用に整形されていて、取得すると文字化けし、肝心の数値を機械抽出できませんでした。
ならばと別ソースの生CSVに切り替えると、今度はcontent-typeが application/octet-stream で返ってきます。
この瞬間、取得ツールは中身を「binary data」と判断し、テキストとして開いてくれないのです。
つまり、ファイルの中身ではなく、サーバーが付けたcontent-typeひとつで読める・読めないが決まってしまう。
ここが、最初の落とし穴でした。
行数上限という見えない天井
content-typeを乗り越えても、それで終わりではありません。
ようやくUTF-8のきれいなCSVにたどり着いても、常に先頭のおよそ1,284行しか返らず、中盤から最新のデータがまるごと欠けてしまう。
全部で二千件を超える履歴のうち、頭の一部しか手に入らないわけです。
「データはそこにあるのに、手が届かない」と、もどかしさばかりが募りました。
効いた回避策:CDN・GitHub API・保存ファイル化

ここからが、実際に効いた三つの「逃がし方」です。
CDNで content-type を「化けさせる」
最初のブレイクスルーは、jsDelivr というGitHub向けCDNでした。
同じCSVでも、raw.githubusercontent.com 経由だと octet-stream で返るのに、CDN経由なら拡張子から text/csv を付けて返してくれる。
jsDelivr は /gh/ユーザー名/リポジトリ名/ファイルパス の形式で、GitHub上のファイルをそのまま配信します(jsDelivr 公式ドキュメント)。
つまり、中身に一切手を触れず、URLを差し替えるだけで「読める形」に化けさせられたわけです。
小さいファイルは API の base64 で丸ごと取る
二つ目は、GitHub の contents API を使う手でした。
このAPIは、1MB以下のファイルなら content フィールドに base64 で中身をまるごと返す仕様です(GitHub REST API(リポジトリコンテンツ))。
2.2KBほどの小さな設定ファイルは、これで完全に取り切れました。
ただし、ここにも小さな罠がひそんでいます。
73KBのCSVをbase64にすると約10万字へ膨らみ、今度はGitHubではなく取得ツール側の文字数上限に引っかかって、頭で切られてしまいました。
base64は元データをおよそ1.33倍に太らせるので、「APIの制限」より先に「取得側の制限」に当たる場合がある、と覚えておくと安全でしょう。
大容量は「保存ファイル化」に逃がす
三つ目は、上限を逆手に取る発想でした。
前提で触れたとおり、取得ツールは応答が大きすぎると中身をファイルへ自動保存します。
これは一見デメリットに見えますが、保存さえされてしまえば、あとはローカルのシェルで全文を落ち着いて処理できる。
だからこそ、あえて情報密度の高いJSONを取りにいって保存ファイル化させ、そこからローカルで料理する段取りに切り替えました。
さらに、降順(新しい順)に並んだソースを選ぶと、「頭から切る」性質が逆に「最新から取れる」利点へ反転します。
制約は、見る角度を変えれば味方になる。
教訓:再利用できる判断フロー
三度も壁にぶつかって、ようやく再利用できる「型」が見えてきました。
一番の学びは、手を出す順番でした。
まず content-type と取得上限を疑い、CDN化・APIのbase64・保存ファイル化という三手で切り分ける。
読めないときは、中身より先にサーバーが付けたcontent-typeを確認し、化けていればCDNやプロキシでテキスト化する。
全部が入りきらないときは、原因が行数なのか、文字数なのか、トークン数なのかを見極める。
小さいファイルはAPIのbase64、大きいファイルは保存ファイル化、最新だけ要るなら降順ソース、と手札を対応づけておくと迷いません。
そしてもうひとつ、地味だけれど大事な割り切りがあります。
最終的に欲しいのが集計値だけなら、連続したブロックが多少欠けても、取れた範囲の標本で目的を果たせることが多い。
完璧に全部を取ることと、目的を果たすことは、必ずしも同じではないのです。
最後に
今回は、ある公開データの集計という具体例で書きましたが、起きていたことはもっと一般的でした。
リモートの大きなデータが途中で切れる、あるいは読めない。
そんなときは、まず content-type と「何の上限に当たっているのか」を疑うところから始めると、ぐっと打ち手が見えてきます。
中身をいじらずにCDNで化けさせる、APIのbase64で丸ごと取る、大きすぎるものは保存ファイルに逃がす。
この三つの引き出しは、サンドボックスに限らず、ブラウザからローカルAPIを叩くときにも、CIの中で外部データを取るときにも効いてくるはずです。
制約にぶつかったら、力技で押し通す前に「どの壁に当たっているか」を見極める。
その一手間が、遠回りに見えて一番の近道だと、私はあらためて感じています。
以上です。










コメントを残す