楽天市場、Yahooショッピング商品価格比較検索(2026年の楽天APIのポイントも解説!)

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

この記事は約20分で読めます。

楽天市場とYahooショッピング同時に検索できるアプリです。
入力項目を少なくしシンプルに検索できます。
結果表示もシンプルに価格の安い順に表示します。
普通の検索では検索結果に欲しい商品とまったく無関係の商品が出てくることがあります。
その対策として商品名に必ず含まれるキーワードを指定できるようにしています。
こちらがアプリになります。↓↓↓↓
楽天、Yahoo商品価格比較検索イチゲアプリ(2026/2/13楽天API新規対応済み)
楽天、Yahoo商品価格比較検索イチゲアプリ(こちらはRender無料ブランでつかってるので、表示するまで数分かかります。毎月20日以降停止。楽天API新規対応済み)

この記事はバックエンドのはなしですが、こちら↓↓は、フロントエンドのはなしです。

【楽天API】Rakuten Ichiba Item Search API(2022-06-01)をWeb applicationで使う方法
広告
MINISFORUM日本公式ストア

楽天API対応(追記2026/2/13)

古いAPIが使えなくなるようなので新しくしました。https://rakuten-webservice.tumblr.com/post/808042087369097216/announcement-0209-legacy-version-of-ichiba-api
使っていたのはIchibaItem/Search/20170706
Rakuten Ichiba Item Search API (version:2022-06-01)に変更。
アプリが削除できないので、残したまま、新規で同じものを登録した。
使わない既存のものをEditで上書きすれば変更できた。activeは5個まで。
上が新しい。下が古い。(古いのを消したいが削除する手段が見つからないので、そのまま。)

2026/2/14うまくいったと思ったらエラー出てた。 “errors”: { “errorCode”: 400, “errorMessage”: “accessKey must be present as a query parameter or in the header” } 
→解決(詳細は次章)

勘違いしたままやってたこと

paramsのほうにも追加’accessKey’: ACCESS_KEY,
結果:
“statusCode”: 429, “message”: “Rate limit is exceeded. Try again in 1 seconds.”
今度はレート制限に引っかかった。

time.sleep(1)入れました。
結果:”errors”: { “errorCode”: 403, “errorMessage”: “REQUEST_CONTEXT_BODY_HTTP_REFERRER_MISSING”

ヘッダー’Referer’: ‘https://django6.kikuichige.com’ ‘Referer’: ‘https://django6.kikuichige.com’ 追加
結果:
“errors”: { “errorCode”: 403, “errorMessage”: “REQUEST_CONTEXT_BODY_HTTP_REFERRER_MISSING”
「HTTP Referer が無い」ではなく「楽天が期待する Referer と一致しない」(copilot談)
copilotは、登録はドメインだけでいいというので新しくApplication URLhttps://django6.kikuichige.comにしたが、状況変わらず。
楽天ウェブサービス → Your Applications → 新アプリ → アプリ情報の編集でサービス利用ドメインを入力しろとcopilotはいうが、そんな欄はない。

こちらを参考にした。https://zenn.dev/milky/scraps/252296c031eb4b
Referer→Originに変更。
結果:
私の場合、解決してないが一歩前進。”errors”: { “errorCode”: 403, “errorMessage”: “HTTP_REFERRER_NOT_ALLOWED” } 

原因判明

私の場合、Webアプリとはいえ楽天APIをたたいている部分は、Backend serviceからだったので、そこで話がおかしくなってた。Application typeの選択が、ただのアンケート的に考えていたが、超重要項目だった。
アプリを登録する際、Application typeをWeb applicationにしていたものを、
API/Backend serviceにしたらうまくいった。
そもそも、API/Backend serviceを選択すると、Allowed IP Addressが聞かれるので、そこでサーバーのIPを入力すればいい。

そのIPからのアクセスは許可してくれる。Backend serviceからアクセスする場合、ブラウザからのアクセスとは違ってRefererやOriginは関係なかった。うまくいってもよさそうだが、多分、私の構成Nginxコンテナ+Djangoアプリコンテナでは、DjangoでRefererやOriginを付けてリクエストしても、リクエストを最終的に出すNginx設定で消されていたのかもしれない。(サーバーからのリクエストがどんなものが出てたか未確認)
また、Application typeをWebアプリにしてパソコンでrequest.get(python)を使ってOriginを書き換えてやってみてもダメだった。
Webアプリとして使う場合は、どこかのサーバー上に「JavaScript で楽天APIへアクセスするWebアプリ」を置く必要がありそうです。
その際、アクセスキーなどの情報はフロント(ブラウザ側)にも送られるため、取り扱いには注意したほうがいいです。
ただし、アクセスキーが第三者に知られたとしても、Origin が異なれば今回のようにエラーになるように設計されているのだと思います。

ポイント

  • アプリを+New Appで新規作成。アプリ名は日本語はエラーになった。
  • Application typeは、楽天APIにアクセスするのが
    フロント(ブラウザ)の場合→Webアプリ。
    サーバーからアクセスする場合→API/Backend serviceを選択
  • Application IDは変わっている。
  • application_secretがAccess_Keyに代わった。
  • アプリのプログラムはAI(copilotなど)で修正。
  • パラメータ仕様、レスポンス仕様が違う
  • レート制限が厳しくなってるのでtime.sleep(1)入れました。
主な変更
            # request_url = 'https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706'
            request_url = 'https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20220601'
            # 30件30ページに制限
            for page in range(1, 4):
                # headers = { 'Authorization': f'Bearer {ACCESS_KEY}','Origin': 'https://kikuichige.com' }←フロントからリクエストと勘違いして追加してたが不要だった。
                params = {
                    'keyword': keyword,
                    'sort': '-reviewAverage',
                    'page': page,
                    'minPrice': minPrice,
                    'maxPrice': maxPrice,
                    'applicationId': APP_ID,
                    'accessKey': ACCESS_KEY, # 新API必須
                    'affiliateId': '**'
                }
                res = requests.get(request_url, params)
                # res = requests.get(request_url, params=params, headers=headers)←フロントからリクエストと勘違いして追加してたが不要だった。
                time.sleep(1)
                result = res.json()

このほかresを展開する部分はレスポンス仕様が違うのでcopilotに任せて修正したが、うまくいかず、Claude、Geminiと渡り歩き、最終的にChatGptが今回の件は頼りになった。

サーバーのIPがRenderのようにOutboundが動的に割り当てられる場合は

まだよく調べていないが、Render無料プランのアプリのサーバーIP調べようとして、ChatGptに聞いたら、動的割り当てされてるとか答えてきた。確かにRenderの設定画面をパッと見る限りない。
動的IPの割り当てをもう少し掘り下げてChatGptに聞いてみた。疑問に思ったのはDNSサーバーにドメインとIPの紐づけ設定をすると浸透するまで数時間かかっているので、DNSを書き換えてドメインとIPを動的に割り振るのは不可能ではないかと思ったから。
ChatGptの答え

DNS(your-app.onrender.comと固定IPの紐づけ)
your-app.onrender.com
        ↓
[Render LBロードバランサー(アクセス負荷を分散する役目) : 固定IP(後述)]
        ↓
[App Container(アプリが実際に動くコンテナ) : 動的IP]
        ↓
[NAT Gateway (出口): 動的IP]
        ↓動的IPでアクセスしてしまうので、楽天APIのアプリ登録時にIPが固定で設定できない。
[外部API](楽天API)
注意:固定IPと書いてあるが、実際には、複数(後述)

さらに聞いた。

結論からいきますね。

はい、入口(クライアント → Render)と出口(Render → クライアント)で
App Container の IP は一切見えません。

クライアントから見ると、**入口も出口も同じ「Render の入口 IP」**です。

順に分解します。


① クライアントが見ている通信の正体

ブラウザがアクセスしているのは:

your-app.onrender.com

DNS を引くと、返ってくるのは

👉 Render のロードバランサ(LB)の IP

です。

TCP / HTTP レベルで見ると

クライアント
  ↔(TCP接続)
Render のロードバランサ(固定管理IP)

ここで TCP セッションが完結しています。


② App Container はどう関与しているか

ロードバランサの裏側では:

[Render LB]
    ↓(内部ネットワーク)
[App Container]
  • App Container は 内部IP
  • その IP は 外部には絶対に出ない
  • クライアントと直接 TCP 接続しない

③ HTML を返すとき「出口IP」はどう見える?

重要ポイント👇

レスポンスの送信元 IP は App Container ではなく、LB の IP

流れを正確に書くと:

1. クライアント → LB(SYN)
2. LB → App Container(内部)
3. App Container → LB(HTML)
4. LB → クライアント(HTML)

つまり:

  • クライアントが見る 送信元IP
    👉 常に「Render の入口 IP」
  • App Container の IP
    👉 一度も表に出ない

④ 「入口と出口でIPが違うのでは?」への答え

❌ 違いません。

HTTP 的にも TCP 的にも:

  • 接続先 IP:LB
  • レスポンス元 IP:LB

同一の TCP セッションです。


⑤ 外部 API のときだけ何が違うのか

比較すると分かりやすいです。

HTML を返すとき(今回の質問)

Client ←→ Render LB ←→ App Container
  • クライアント視点:LB しか見えない
  • IP は安定

外部 API を呼ぶとき

App Container → NAT Gateway → 外部API
  • 外部API視点:NAT の出口IPが見える
  • これが動的に変わる

👉 ここが「Render の IP は動的」と言われる理由


⑥ 直感的なたとえ

  • Render LB:受付カウンター
  • App Container:バックヤードの作業員

お客さんは:

  • 受付の人とだけ話す
  • 作業員の顔も名前も知らない

⑦ まとめ(ここ重要)

  • クライアントが HTML を受け取る通信では
    入口IP ≠ App Container IP
  • 入口も出口も
    Render のロードバランサの IP
  • App Container の IP は
    完全に内部用

なので、

「HTML を返すときに入口と出口で IP が違うのでは?」

という心配は 不要です。

本当にそうか確認するため、Renderにデプロイした同じアプリで確認してみた。
まず、開発者ツールのネットワークで得た固定IPをRemoteAddressで楽天APIのアプリ新規登録いたが、やはり403。

実験していて、ブラウザの開発者ツールのネットワークタブで見るとRemote Addressが 216.24.57.7:443のときと216.24.57.251:443のときがあったので質問した。


何が起きているか(結論)

Render の入口(ロードバランサ)が複数台あり、
そのうちのどれかに毎回つながっている

なので、

  • 216.24.57.7:443
  • 216.24.57.251:443

どちらも
👉 Render のフロントエンド LB の IP
で、あなたの App Container の IP ではありません。


なぜ IP が複数あるのか

Render 側は、ざっくりこういう構成です:

your-app.onrender.com
        ↓ DNS
  複数の LB IP を返す
   - 216.24.57.7
   - 216.24.57.251
        ↓
  その時選ばれた LB に接続

ポイント

  • DNS は 1 IP だけとは限らない
  • 複数 A レコードを返す(ラウンドロビン)←ここは、ChatGptに改めて聞いた。
  • ブラウザはその中のどれかを選ぶ

開発者ツールで見えている「Remote Address」の正体

Chrome / Edge の Network タブで見る:

Remote Address: 216.24.57.xxx:443

これは:

👉 TCP 接続の相手先 IP
👉 TLS が張られている相手

Render の入口 LB

です。


重要:IP が切り替わるタイミング

以下のどれでも変わります:

  • ページをリロード
  • 新しい TCP 接続が張られる
  • HTTP/2 / HTTP/3 の接続再確立
  • DNS キャッシュの更新

でも:

❌ リダイレクトされている
❌ App Container が直接応答している

わけではありません。


「じゃあ同じセッションはどうなる?」

1 回の接続中は:

Client ↔ LB(216.24.57.7)

で固定です。

次の接続で:

Client ↔ LB(216.24.57.251)

に変わるだけ。

👉 途中で切り替わることはない(TCP 的に無理)


よくある誤解を整理

誤解実際
App の IP が変わっている
DNS が毎回書き換わっている
リダイレクトしている
LB が複数ある
接続ごとに別 LB に当たる

これが意味すること(実務的に大事)

  • クライアント視点の IP は安定しているとは限らない
  • IP 制限で 216.24.57.7 だけ許可 → ❌ すぐ壊れる
  • Render の特定 IP を allowlist する設計は危険

👉 ドメインベース or プロキシ前提が正解


まとめ(核心)

  • 216.24.57.7216.24.57.251Render の入口
  • 複数あるのは 高可用性・負荷分散のため
  • App Container の IP は 一度も外に出ていない

この際、いい機会なので、今まで疑問に思っていたことも質問したら、結構、今回の件でイメージしやすくなった。

「複数 A レコード(ラウンドロビン)」を DNS → ブラウザ → TCP の流れで解説します。


① A レコードって何か(前提を1行で)

A レコード

「このドメイン名は、この IPv4 アドレスですよ」という DNS の答え

普通はこう思いますよね:

example.com → 93.184.216.34

でも、1対1である必要はないんです。


② 複数 A レコードとは

DNS では 同じ名前に複数の A レコード を持てます。

your-app.onrender.com
  A 216.24.57.7
  A 216.24.57.251

これが 複数 A レコード


③ 「ラウンドロビン」って何をしている?

DNS サーバは、問い合わせが来るたびに:

  • A レコードを 順番に並べ替えて返す
  • もしくは ランダム順で返す

例:

1回目の DNS 応答

216.24.57.7
216.24.57.251

2回目の DNS 応答

216.24.57.251
216.24.57.7

これを DNS ラウンドロビン と呼びます。

⚠️「DNSがどれを使うか決める」わけではない
順番を返すだけ


④ どの IP に実際につながるの?

👉 決めるのはクライアント(OS / ブラウザ)

一般的な挙動:

  1. DNS から A レコード一覧を受け取る
  2. 先頭の IP に接続を試みる
  3. 失敗したら次へ

だから:

  • DNS の順序が変わる
  • → 接続される IP が変わる
  • → 開発者ツールで Remote Address が変わる

⑤ なぜこんな仕組みが必要?

理由① 負荷分散(ロードバランシング)

IP1 が忙しい
IP2 は空いている
→ 自然に分散

理由② 高可用性(冗長化)

216.24.57.7 が死んだ
→ 216.24.57.251 に接続される

DNS レベルで 単一障害点を消せる


⑥ Render の場合に当てはめると

your-app.onrender.com
        ↓ DNS
  [216.24.57.7]  [216.24.57.251]
        ↓
Render の複数ロードバランサ
        ↓
App Container
  • App Container は1つでもOK
  • 入口だけ複数用意している
  • IP が違って見えるのはここ

⑦ TTL と「浸透時間」はどうなる?

TTL(Time To Live)

A レコードの有効期限

例:

TTL = 60秒
  • 60秒間は DNS キャッシュを使う
  • 期限切れで再問い合わせ
  • その時、順序が変わる可能性

👉 DNSを書き換えているわけではない
👉 同じ情報を、違う順で返しているだけ


⑧ よくある誤解を一気に潰す

誤解実際
DNSがIPを切り替えている
リダイレクトしている
途中でIPが変わる
DNSは複数IPを返しているだけ
接続先はクライアントが選ぶ

⑨ 「ロードバランサと何が違う?」

DNSラウンドロビンL7/L4ロードバランサ
超シンプル高機能
ヘルスチェック弱い強い
TCP接続は見ない見る
DNSレベル通信レベル

Render は:

  • DNSラウンドロビン + 内部LB
  • という 二段構え

⑩ まとめ(ここが本質)

  • 複数 A レコードは 仕様
  • ラウンドロビンは 並び順を変えるだけ
  • 実際にどれに接続するかは クライアント次第
  • Remote Address が変わるのは 入口が複数ある証拠

答えは 半分だけ YES、半分は NO です。


結論を一文で

ロードバランサーは「アプリを実行するコンテナ」ではない。
アプリの前に立って、通信だけをさばく専用の仕組み。

「負荷分散しているからそう呼んでいるだけ」ではありません。


① ロードバランサー(LB)とは何者か

ロードバランサーは:

クライアントからの通信を受け取り、
どのアプリ実体に渡すかを決める門番

です。

実体としては:

  • 専用ソフトウェア(例:Envoy / HAProxy / Nginx)
  • 専用のマネージドサービス

👉 あなたのアプリコードは一切動いていない


② App Container との決定的な違い

ロードバランサーApp Container
役割通信の制御ビジネスロジック
実行するものネットワーク処理あなたのコード
HTML生成
DBアクセス
スケール常時複数必要に応じて
落ちたら?別LBへ再起動

③ Render での構成を正確に書くと

Render の場合:

Client
  ↓
[LB コンテナ群]   ← ここは複数・常駐
  ↓
[App Container]   ← ここで Django / Node が動く

重要

  • LB は 常に起動
  • App Container は スケール・再起動される
  • 両者は 完全に別プロセス / 別責務

④ 「同じアプリを実行してるだけ?」という疑問への答え

❌ 違います。

ロードバランサーは:

  • HTTPリクエストを理解する
  • TLS を終端する
  • ヘッダを書き換える
  • 接続を再利用する
  • 障害ノードを避ける

でも:

  • あなたの views.py
  • あなたの index.html
  • あなたの DB クエリ

は一切知りません。


⑤ じゃあ負荷分散って何を分けてる?

分散しているのは

👉 「処理」ではなく「接続」

1000人アクセス
  ↓
LB が 1000 接続を受ける
  ↓
App1 に 300
App2 に 400
App3 に 300

App Container は 同じアプリを複数起動しているだけ。


⑥ 「LB もコンテナなの?」という疑問

実装としては:

  • LB もコンテナであることは多い
  • でも ユーザーが管理できない
  • 中身は完全に別物

たとえるなら:

  • App Container:あなたの店員
  • LB:ビルの受付とエレベーター制御

⑦ なぜ App Container 自身が分散しないのか

もし LB がなかったら:

  • クライアントが直接 App に接続
  • App が落ちたら即死
  • TLS / 再送 / keep-alive が地獄

👉 アプリにネットワークをやらせないために LB がいる。


⑧ まとめ(核心)

  • ロードバランサー ≠ アプリコンテナ
  • 責務が完全に違う
  • 「負荷分散」は 結果であって本質ではない
  • 本質は
    👉 通信をアプリから切り離すこと

Renderの場合はOutbound IP Addressesを設定すればOK

イチゲをOFUSEで応援する(御質問でもOKです)Vプリカでのお支払いがおすすめです

続いて、以下でうまくいった。やはり楽天APIにアクセスするときは、別の動的IPからアクセスしてるみたいです。とはいえ範囲が書いてあるので設定できました。

RenderのDashboadの右上のConnectに以下があった。これを設定したら、うまくいった。

Outbound
Outbound IP Addresses
Network requests from your service to the public internet will come from one of the following IP addresses or ranges.
These IPs are not unique to your service or workspace. They are shared by other Render services in the same region.
この下にIPアドレスが出てた。

そのアドレスをAllowed IP addressesに貼り付ければうまくいきました。
ただ、Webアプリにアクセスしたときの固定IPも書かないと、登録できなかった。(関係なかった。新規でなく既存のものをEditで編集できたので。)
固定IPはWebアプリをブラウザで開き、開発者ツールのネットワークで1番上の通信をクリックして見れば、Remote Addressに書いてあります。(毎回、違うことがあるが上記参照。表示されたもの1個だけ書いたらOKだった。しかし、たまたま固定IPを書いたらOKになっただけで動作が不安定だっただけと思われる。なので、本来、この固定IPは不要だと思う。)

楽天、Yahoo商品価格比較検索イチゲアプリ(こちらはRender無料ブランでつかってるので、表示するまで数分かかります。毎月20日以降停止。楽天API新規対応済み)

Renderを久しぶりに使ったら、GitHubとの連携が切れていたが、再連携の仕方が分かったので、記事更新しました。↓↓


どうしてもダメな場合はWebアプリ(フロントから楽天APIにリクエストするタイプ)に作り替えるしかないかもしれません。こちら↓を参考にしてください。

【楽天API】Rakuten Ichiba Item Search API(2022-06-01)をWeb applicationで使う方法

アプリ操作方法

キーワード:検索するキーワード
絶対キーワード:キーワード検索結果のうち商品名に、ここで指定したキーワードが入っている商品を結果表示します。全角スペースで複数キーワード指定できます。
完全一致なので大文字、小文字、全角、半角も区別します。
何も検索結果が出ないときの原因は下の検索のコツに書いてあります。
最低価格:検索対象の商品価格下限です。デフォルト0円
最低価格:検索対象の商品価格上限です。デフォルト1000000円

検索結果
価格の安い順に表示します。
店:Y=Yahooショッピング、楽=楽天市場
画像:商品画像
価格:設定されてる価格。(送料、税、その他、この価格が意味する内容は異なりますので詳細はリンク先でご確認ください。
商品名:商品名、売り場のリンクがついてます。
楽天最大90件+Yahoo最大90件=合計最大180件
検索ボタンをクリックすると検索します。

検索のコツ

絶対キーワードを入力したとき検索結果に絶対キーワードが入っている商品名がない場合は何も表示されません。
価格設定を変えて再度検索してください。
このアプリのアルゴリズムはキーワード、最低価格、最高価格、安い順を設定し楽天、YahooショッピングAPIで検索結果をもらいます。
その検索結果から商品名に「絶対キーワード」で指定したキーワードが入っていないものは対象から外します。
安い順に表示します。
このアプリはDjango(Python)で作っています。

今後の予定

随時機能アップをはかりたいと思います。
AmazonのAPI(PA-API)を使うために必要なアマゾンアソシエイトにも申し込みましたが
一定以上の売上実績を重ねることが使用開始条件となります。
使用できるようになったらアマゾンも追加する予定でしたが全然売れないので諦めました。

このブログを書いてるイチゲをOFUSEで応援する

MENTAやってます(ichige)

コメント

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