Amazon検索リンク自動生成(商品名/ASIN/URL→検索・レビュー順・価格順)

Amazon検索リンク自動生成(商品名/ASIN/URL対応)

Amazon商品URLやASIN、ASIN|商品名 から、商品ページ直リンク+検索リンク(通常/レビュー順/価格順)を自動生成するUIサンプル。 URLパラメータ由来のゴミ語(amp/rd等)混入を防止

1. スクショ

(ここに表示イメージのスクショを貼る)

2. デモ

3. 最小コード(HTML+CSS+JS)

下のコードはこのページのデモ部分と同等。記事に貼ればそのまま動く構成。

HTML(コピペ)
<div class="ppamz-card">
  <label class="ppamz-label">入力(Amazon商品URL / ASIN / ASIN|商品名)</label>
  <textarea id="ppamz_input" class="ppamz-input" rows="4"></textarea>

  <div class="ppamz-row">
    <div class="ppamz-col">
      <label class="ppamz-label">アフィタグ(任意)</label>
      <input id="ppamz_tag" class="ppamz-text" type="text">
    </div>
    <div class="ppamz-col">
      <label class="ppamz-label">ドメイン</label>
      <select id="ppamz_locale" class="ppamz-text">
        <option value="amazon.co.jp" selected>amazon.co.jp</option>
        <option value="amazon.com">amazon.com</option>
      </select>
    </div>
  </div>

  <div class="ppamz-actions">
    <button class="ppamz-btn" id="ppamz_build">リンク生成</button>
    <button class="ppamz-btn ppamz-btn-ghost" id="ppamz_reset" type="button">クリア</button>
  </div>

  <div class="ppamz-notice" id="ppamz_notice"></div>

  <div class="ppamz-out" id="ppamz_out" hidden>
    <div class="ppamz-out-head">
      <div>
        <div class="ppamz-out-title" id="ppamz_title">—</div>
        <div class="ppamz-out-sub">
          <span class="ppamz-mono">ASIN: <span id="ppamz_asin">—</span></span>
          <span class="ppamz-dot">•</span>
          <span class="ppamz-mono">Query: <span id="ppamz_query">—</span></span>
        </div>
      </div>
      <button class="ppamz-btn ppamz-btn-mini" id="ppamz_copy">リンクHTMLをコピー</button>
    </div>

    <div class="ppamz-chips" id="ppamz_links"></div>

    <details class="ppamz-details">
      <summary>生成したリンクHTML(コピペ用)</summary>
      <pre class="ppamz-pre"><code id="ppamz_html"></code></pre>
    </details>
  </div>
</div>
CSS(コピペ)
/* --- Amazon Search Link Generator UI Sample --- */
.ppamz-article{max-width:920px;margin:0 auto;line-height:1.85;font-size:16px}
.ppamz-hero{padding:18px 16px;border:1px solid rgba(0,0,0,.10);border-radius:14px;margin:0 0 18px;background:rgba(0,0,0,.02)}
.ppamz-hero h1{font-size:1.55rem;line-height:1.35;margin:0 0 10px}
.ppamz-lede{margin:0}
.ppamz-badge{display:inline-block;margin-left:8px;padding:2px 10px;border-radius:999px;border:1px solid rgba(0,0,0,.10);font-size:.85rem;background:#fff}
.ppamz-card{border:1px solid rgba(0,0,0,.10);border-radius:14px;padding:14px;margin:14px 0;background:#fff}
.ppamz-h2{font-size:1.22rem;margin:0 0 10px}
.ppamz-note{font-size:.92rem;opacity:.9;margin:0 0 10px}

.ppamz-form{display:grid;gap:10px}
.ppamz-label{display:block;font-weight:700;font-size:.95rem;margin:0 0 6px}
.ppamz-input{width:100%;min-height:86px;padding:10px 12px;border:1px solid rgba(0,0,0,.15);border-radius:12px;resize:vertical}
.ppamz-text{width:100%;padding:10px 12px;border:1px solid rgba(0,0,0,.15);border-radius:12px}
.ppamz-row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
@media (max-width:720px){.ppamz-row{grid-template-columns:1fr}}
.ppamz-actions{display:flex;gap:10px;flex-wrap:wrap}
.ppamz-btn{appearance:none;border:1px solid rgba(0,0,0,.15);background:#111;color:#fff;padding:10px 12px;border-radius:12px;cursor:pointer}
.ppamz-btn-ghost{background:#fff;color:#111}
.ppamz-btn-mini{padding:8px 10px;font-size:.9rem}
.ppamz-notice{padding:10px 12px;border-radius:12px;background:rgba(0,0,0,.04);border:1px dashed rgba(0,0,0,.18);display:none}
.ppamz-notice.is-show{display:block}
.ppamz-notice.is-warn{background:rgba(255,200,0,.12);border-style:solid}

.ppamz-out{margin-top:10px;border-top:1px dashed rgba(0,0,0,.15);padding-top:12px}
.ppamz-out-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap}
.ppamz-out-title{font-weight:800;font-size:1.1rem}
.ppamz-out-sub{font-size:.9rem;opacity:.9}
.ppamz-mono{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}
.ppamz-dot{margin:0 8px}
.ppamz-chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.ppamz-chip{display:inline-flex;align-items:center;gap:6px;padding:8px 10px;border-radius:999px;border:1px solid rgba(0,0,0,.12);background:#fff;text-decoration:none;color:inherit}
.ppamz-chip small{opacity:.75}
.ppamz-details{margin-top:10px}
.ppamz-pre{white-space:pre-wrap;word-break:break-word;background:rgba(0,0,0,.03);border:1px solid rgba(0,0,0,.10);border-radius:12px;padding:10px 12px;overflow:auto}
JS(コピペ)
(() => {
  const $ = (sel) => document.querySelector(sel);

  // ---- Utils ----
  const decode = (s) => {
    try { return decodeURIComponent(s); } catch (e) { return s; }
  };

  const normalizeSpace = (s) => String(s || '').replace(/\s+/g, ' ').trim();

  // Amazon URL から ASIN を抽出(/dp/ASIN, /gp/product/ASIN)
  const extractAsinFromUrl = (url) => {
    const m1 = url.match(/\/dp\/([A-Z0-9]{10})/i);
    if (m1) return m1[1].toUpperCase();
    const m2 = url.match(/\/gp\/product\/([A-Z0-9]{10})/i);
    if (m2) return m2[1].toUpperCase();
    return '';
  };

  // /dp/ の直前セグメント(商品名スラッグ)を取り出す
  const extractSlugNameFromUrl = (url) => {
    // ?以降は破棄(pd_rd_ / pf_rd_ / content-id 等のゴミ混入を防ぐ)
    const base = url.split('?')[0];
    const parts = base.split('/').filter(Boolean);

    // ... /{name}/dp/{asin}/...
    const dpIdx = parts.findIndex(p => p.toLowerCase() === 'dp');
    if (dpIdx > 0) {
      const nameSeg = parts[dpIdx - 1];
      return decode(nameSeg);
    }

    // ... /dp/{asin}/...(nameが無いURLは空)
    return '';
  };

  // URLスラッグ由来の「商品名っぽい文字列」を整形
  const cleanProductTitle = (raw) => {
    let s = normalizeSpace(raw);
    if (!s) return '';

    // AmazonのURLスラッグは "-" 区切りになりがち
    s = s.replace(/-/g, ' ');

    // ノイズ語(必要に応じて増やす)
    const noiseTail = ['Technology', 'Books', 'Kindle', 'Amazon', 'co', 'jp', 'com'];
    for (const n of noiseTail) {
      s = s.replace(new RegExp(`\\b${n}\\b`, 'gi'), '').trim();
    }

    // 記号整理
    s = s.replace(/[__]+/g, ' ');
    s = s.replace(/\s{2,}/g, ' ').trim();

    return s;
  };

  // 検索語を作る:商品名があるなら短めに圧縮
  const buildQuery = (productTitle) => {
    const s = normalizeSpace(productTitle);
    if (!s) return '';
    // 例:長すぎる場合、先頭の短い部分だけ(書籍タイトル等で暴走しがち)
    const maxLen = 48;
    return s.length > maxLen ? s.slice(0, maxLen).trim() : s;
  };

  // 禁止トークン(amp/rd/pf/content-id 等)混入を最終防波堤でブロック
  const scrubQuery = (q) => {
    let s = normalizeSpace(q);
    if (!s) return '';
    const banned = ['amp', 'rd', 'pf', 'content-id', 'pd_rd', 'pf_rd', 'ref', 'sym'];
    const tokens = s.split(' ').filter(t => {
      const low = t.toLowerCase();
      if (banned.includes(low)) return false;
      if (low.startsWith('pd_') || low.startsWith('pf_')) return false;
      return true;
    });
    return tokens.join(' ').trim();
  };

  // URL生成
  const buildAmazonUrls = ({ domain, asin, query, tag }) => {
    const aff = tag ? `&tag=${encodeURIComponent(tag)}` : '';
    const q = encodeURIComponent(query || '');
    const dp = asin ? `https://${domain}/dp/${asin}/` + (tag ? `?tag=${encodeURIComponent(tag)}` : '') : '';

    // 検索は補助導線(商品名検索/レビュー順/価格順)
    const searchBase = `https://${domain}/s?k=${q}`;
    const search = `${searchBase}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`;
    const review = `${searchBase}&s=review-rank${aff}`;
    const priceAsc = `${searchBase}&s=price-asc-rank${aff}`;

    return { dp, search, review, priceAsc };
  };

  // ---- UI ----
  const notice = (msg, type = 'info') => {
    const el = $('#ppamz_notice');
    el.textContent = msg || '';
    el.className = 'ppamz-notice is-show' + (type === 'warn' ? ' is-warn' : '');
    if (!msg) el.className = 'ppamz-notice';
  };

  const build = () => {
    const raw = normalizeSpace($('#ppamz_input').value);
    const tag = normalizeSpace($('#ppamz_tag').value);
    const domain = $('#ppamz_locale').value;

    if (!raw) {
      notice('入力が空です。Amazon商品URL / ASIN / ASIN|商品名 のいずれかを入れてください。', 'warn');
      return;
    }

    // 1行目だけ使う(サンプル簡略)
    const line = raw.split('\n').map(s => s.trim()).filter(Boolean)[0];

    let asin = '';
    let productTitle = '';

    // ASIN|商品名 形式
    if (line.includes('|')) {
      const [a, t] = line.split('|').map(s => normalizeSpace(s));
      asin = /^[A-Z0-9]{10}$/i.test(a) ? a.toUpperCase() : '';
      productTitle = t || '';
    } else if (/^https?:\/\//i.test(line)) {
      // URL
      asin = extractAsinFromUrl(line);
      const slugName = extractSlugNameFromUrl(line);
      productTitle = cleanProductTitle(slugName);
    } else {
      // ASIN単体
      asin = /^[A-Z0-9]{10}$/i.test(line) ? line.toUpperCase() : '';
      productTitle = '';
    }

    if (!asin) {
      notice('ASINが判定できませんでした。Amazon商品URL(/dp/ASIN)または ASIN を正しく入力してください。', 'warn');
      return;
    }

    // 商品名が空なら警告(検索語が弱い)
    if (!productTitle) {
      notice('商品名が取れませんでした。検索リンクの精度が落ちます。ASIN|商品名 形式で入力すると改善します。', 'warn');
      productTitle = `ASIN ${asin}`;
    } else {
      notice('リンクを生成しました。', 'info');
    }

    let query = buildQuery(productTitle);
    query = scrubQuery(query);

    // 最終 fallback
    if (!query) query = `ASIN ${asin}`;

    const urls = buildAmazonUrls({ domain, asin, query, tag });

    // 表示
    $('#ppamz_out').hidden = false;
    $('#ppamz_title').textContent = productTitle;
    $('#ppamz_asin').textContent = asin;
    $('#ppamz_query').textContent = query;

    const chips = [
      { href: urls.dp, label: '商品ページ', sub: 'dp/ASIN(主導線)' },
      { href: urls.search, label: 'Amazonで検索', sub: '商品名ベース' },
      { href: urls.review, label: 'レビュー順', sub: 'review-rank' },
      { href: urls.priceAsc, label: '価格が安い順', sub: 'price-asc' }
    ];

    const linksEl = $('#ppamz_links');
    linksEl.innerHTML = '';
    for (const c of chips) {
      const a = document.createElement('a');
      a.className = 'ppamz-chip';
      a.href = c.href || '#';
      a.target = '_blank';
      a.rel = 'nofollow sponsored noopener';
      a.innerHTML = `<strong>${c.label}</strong> <small>${c.sub}</small>`;
      linksEl.appendChild(a);
    }

    // コピペ用HTML
    const html = chips
      .map(c => `<a href="${c.href}" target="_blank" rel="nofollow sponsored noopener">${c.label}</a>`)
      .join(' / ');

    $('#ppamz_html').textContent = html;

    // copy
    $('#ppamz_copy').onclick = async () => {
      try {
        await navigator.clipboard.writeText(html);
        notice('リンクHTMLをコピーしました。', 'info');
      } catch (e) {
        notice('コピーに失敗しました(ブラウザの制限の可能性)。下のコードを手動でコピーしてください。', 'warn');
      }
    };
  };

  const reset = () => {
    $('#ppamz_input').value = '';
    $('#ppamz_tag').value = '';
    $('#ppamz_out').hidden = true;
    notice('');
  };

  $('#ppamz_build')?.addEventListener('click', (e) => { e.preventDefault(); build(); });
  $('#ppamz_reset')?.addEventListener('click', (e) => { e.preventDefault(); reset(); });

  // 初期ヒント
  notice('Amazon商品URL(/dp/ASIN)を貼ると、URLから商品名っぽい文字列を抽出して検索リンクを作ります。', 'info');
})();

4. ポイント

  • 主導線は dp/ASIN 直リンク(確実に買える)。検索リンクは補助。
  • 検索語は商品名から生成:URLの ?以降 は絶対に使わない。
  • URLスラッグ抽出/dp/直前)→ URLデコード → 整形で商品名っぽくできる。
  • ASIN単体は警告ASIN|商品名 入力で精度が上がる。
  • 最終防波堤amp/rd/pf/content-id 等の禁止トークンをフィルタ。
決済はStripeで安全に処理されます。
Amazonで「gt・lt」を検索
Amazonで探す

この記事の感想をこっそり教えてください(非公開)