1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code で YouTube Shorts Chrome 拡張を 1 セッションで作り切った — DOM 探索 10 回失敗と突破パターン

1
Last updated at Posted at 2026-05-20

結論

YouTube Shorts の説明文を 2 タップから 1 クリックに変える Chrome 拡張を、Claude Code との対話 1 セッション(約 2.5 時間)で完成させた。

DOM セレクタが 10 回以上 null を返し続けたが、5 つの落とし穴を特定して突破した。Manifest V3 + Shadow DOM + MutationObserver の組み合わせが解答だった。


なぜ Shorts の DOM は難しいのか

通常の YouTube は ytp-button クラスで操作できるが、Shorts は独自の "spec button" 仕様(ytSpecButtonShapeNextHost)で構築されており、セレクタが全く異なる。

// ❌ 通常 YouTube では動く — Shorts では null
document.querySelector('.ytp-button')
document.querySelector('[aria-label="詳細"]')

10 回失敗した 5 つの落とし穴

1. Shadow DOM の壁

Shorts のボタンは Shadow DOM 内に配置。通常の querySelector は貫通できない。

// ❌ Shadow DOM には届かない
document.querySelector('ytd-shorts button')

// ✅ shadowRoot 経由でアクセス
const host = document.querySelector('ytSpecButtonShapeNextHost')
if (host?.shadowRoot) {
  host.shadowRoot.querySelector('button')?.click()
}

DevTools の Elements タブで #shadow-root (open) が表示されていたらこれが原因。

2. 非同期レンダリング

Shorts は SPA。DOMContentLoaded を待っても目的の要素は存在しない。MutationObserver で待ち構える必要がある。

// ❌ DOMContentLoaded では間に合わない
document.addEventListener('DOMContentLoaded', () => {
  document.querySelector('ytd-shorts #expand-button')  // null
})

// ✅ MutationObserver で DOM 変化を監視
const observer = new MutationObserver(() => {
  const target = document.querySelector('ytd-shorts #expand-button button')
  if (target) {
    target.click()
    observer.disconnect()
  }
})
observer.observe(document.body, { childList: true, subtree: true })
setTimeout(() => observer.disconnect(), 5000)

3. Manifest V3 の host_permissions 設定ミス

content_scriptsmatches だけでは不足。host_permissions も必要。

{
  "manifest_version": 3,
  "content_scripts": [{
    "matches": ["*://www.youtube.com/shorts/*"],
    "js": ["content.js"]
  }],
  "host_permissions": ["*://www.youtube.com/*"]
}

4. 拡張のキャッシュ

コードを変更しても chrome://extensions/ から「再読み込み」しないと古いコードが動き続ける。「直したはずなのに変わらない」を 3 回やってから気づいた。

5. スワイプ時の URL 変化

2 本目の動画からボタンが機能しなくなる。Shorts をスワイプするたびに URL が変わるため、URL 変化を監視して再初期化が必要。

let lastUrl = location.href
new MutationObserver(() => {
  if (lastUrl !== location.href) {
    lastUrl = location.href
    setTimeout(initExpandButton, 500)
  }
}).observe(document, { subtree: true, childList: true })

完成した最小構成

manifest.json:

{
  "manifest_version": 3,
  "name": "Shorts 説明を 1 クリックで開く",
  "version": "1.0",
  "content_scripts": [{
    "matches": ["*://www.youtube.com/shorts/*"],
    "js": ["content.js"]
  }],
  "host_permissions": ["*://www.youtube.com/*"]
}

content.js:

function tryExpand() {
  const btn = document.querySelector('ytd-shorts #expand-button button')
  if (btn) { btn.click(); return true }
  return false
}

function initExpandButton() {
  if (tryExpand()) return
  const observer = new MutationObserver(() => {
    if (tryExpand()) observer.disconnect()
  })
  observer.observe(document.body, { childList: true, subtree: true })
  setTimeout(() => observer.disconnect(), 5000)
}

let lastUrl = location.href
initExpandButton()
new MutationObserver(() => {
  if (lastUrl !== location.href) {
    lastUrl = location.href
    setTimeout(initExpandButton, 500)
  }
}).observe(document, { subtree: true, childList: true })

Claude Code との対話で突破した方法

詰まりを突破したのは、DevTools で確認した DOM 構造を Claude Code に貼り付けて「なぜ null になるか」を聞いたことだった。

#shadow-root (open) という表示があります」と伝えると、Shadow DOM の存在とアクセス方法を即座に返してくれた。一人でデバッグしていたらさらに 1〜2 時間かかっていたと思う。

効果的だった使い方:

  1. DevTools で実際の DOM をコピーして貼り付ける
  2. 「このセレクタが null を返す原因を推測してください」と聞く
  3. 返ってきた 3〜5 候補を上から試す

まとめ

Shorts の Chrome 拡張で詰まるポイントは決まっている:

問題 原因 解決策
querySelector が null Shadow DOM shadowRoot 経由でアクセス
DOMContentLoaded で null 非同期レンダリング MutationObserver を使う
拡張が動かない host_permissions 欠落 manifest.json に追記
コード変更が反映しない キャッシュ chrome://extensions/ で再読み込み
2 本目から動かない URL 変化未検知 URL 変化監視の MutationObserver を追加

詳細な実録・「で、どう稼ぐ?」の観点はこちら: masatoman.net 元記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?