Naver動画のダウンロードを自動化する:ブラウザ拡張からAPI連携まで、実用的な実装テクニックを解説
こんにちは、ウェブスクレイピングと動画処理を趣味としているエンジニアです。
先日、韓国のコンテンツを調査するプロジェクトで「Naver TV」や「V LIVE」の動画をローカルに保存する必要が出てきました。最初はyoutube-dlやyt-dlpを試してみたのですが、Naverの独自プレーヤー構造に苦戦…。結局、自分で解析ロジックを組むことになったのですが、その過程で得た知見をまとめてみようと思います。
なお、本記事で紹介する手法は個人の学習・研究目的での利用を前提としています。著作権法やNaverの利用規約は必ずご自身で確認し、適法な範囲でご活用ください。
なぜNaver動画のダウンロードは「ちょっと」難しいのか
YouTubeやTwitter(X)と違い、Naverの動画配信にはいくつかの特徴があります。
-
プレーヤーの多重ネスト
動画ページを開くと、iframeで別ドメインのプレーヤーが読み込まれ、さらにその中でJavaScriptが動画メタデータを動的に生成します。 -
m3u8 + HLS配信の採用
多くの動画がHLS(HTTP Live Streaming)形式で配信されており、.m3u8プレイリストを解析してセグメントを結合する必要があります。 -
Referer / User-Agentの検証
単純にcurlでリクエストを送っても403を返されることが多く、ブラウザと同等のヘッダーを再現する必要があります。 -
V LIVEとNaver TVで仕様が異なる
同じNaverグループでも、プラットフォームごとにAPIエンドポイントやトークン発行フローが微妙に違います。
これらの課題を「毎回手作業で」解決するのは現実的ではありません。そこで、私が実際に運用している**「軽量・保守しやすい」解析アプローチ**を紹介します。
核心部分:動画メタデータの取得ロジック(Python例)
まず、Naver TVの動画ページからm3u8URLを抽出する基本的な流れです。requestsとBeautifulSoup、そしてm3u8ライブラリを使います。
import requests
from bs4 import BeautifulSoup
import m3u8
def extract_naver_video_url(page_url: str) -> str:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://tv.naver.com/'
}
# 1. 動画ページを取得
resp = requests.get(page_url, headers=headers)
resp.raise_for_status()
# 2. iframeのsrcを抽出(プレーヤーページ)
soup = BeautifulSoup(resp.text, 'html.parser')
iframe = soup.find('iframe', {'id': 'video_iframe'})
if not iframe:
raise ValueError("iframeが見つかりません")
player_url = iframe['src']
# 3. プレーヤーページからvideo infoを取得
player_resp = requests.get(player_url, headers=headers)
player_soup = BeautifulSoup(player_resp.text, 'html.parser')
# data属性やscriptタグからm3u8 URLを抽出(実装はページ構造に依存)
# 例: <video>タグのsrc、またはwindow.videoInfo JSON
script_tags = player_soup.find_all('script', string=True)
for tag in script_tags:
if 'videoInfo' in tag.string:
# 簡易的なJSON抽出(実際は正規表現やjsonライブラリで厳密に)
start = tag.string.find('{')
end = tag.string.rfind('}') + 1
import json
video_info = json.loads(tag.string[start:end])
return video_info.get('video', {}).get('source', {}).get('mpegURL')
raise ValueError("m3u8 URLを抽出できませんでした")
💡 ポイント: Naverはページ構造を頻繁に変更するため、
iframe#video_iframeのようなセレクターは「現時点での例」として捉え、実際の運用ではDOMの変化に強いXPathやPlaywrightなどのヘッドレスブラウザ併用を検討してください。
m3u8セグメントのダウンロードと結合
m3u8URLが取得できたら、次はセグメントの取得です。m3u8ライブラリを使うと、プレイリストの解析が非常に楽になります。
def download_hls_video(m3u8_url: str, output_path: str):
headers = {'Referer': 'https://tv.naver.com/'}
playlist = m3u8.load(m3u8_url, headers=headers)
with open(output_path, 'wb') as f:
for segment in playlist.segments:
# 相対URLを絶対URLに変換
seg_url = segment.absolute_uri
seg_resp = requests.get(seg_url, headers=headers)
seg_resp.raise_for_status()
f.write(seg_resp.content)
print(f"Downloaded: {seg_url}")
※ 実際のプロダクションでは、並列ダウンロード・再開対応・進捗表示などを追加する必要があります。また、セグメントが暗号化されている場合は#EXT-X-KEYの処理も必要です(Naverの一般公開動画では稀ですが)。
「毎回コードを書くのは面倒」→ Webツール化のメリット
上記のような処理を毎回スクリプトで実行するのは、非エンジニアのチームメンバーにはハードルが高いですよね。そこで、私はこのロジックをWebインターフェースにラップし、URLを貼り付けるだけでダウンロードできるようにしました。
今回ご紹介している Naver動画ダウンローダー は、まさにそのような「技術的バックエンド + 直感的UI」を組み合わせたツールです。
技術的な特徴(裏側を少しだけ)
- フロントエンド: Vue.js + TypeScript。URL入力・解析状態・ダウンロードリンクをリアクティブに管理。
- バックエンド: Python(FastAPI) + Celery。動画解析は非同期タスクとしてキューイングし、長時間処理でもタイムアウトを回避。
- セキュリティ: ユーザー入力サニタイズ、CORS制限、レートリミットにより悪用を防止。
- プライバシー: 動画データの一時保存はメモリ内のみ。ダウンロード完了後即破棄。ログにもURLを記録しません。
特に「クライアント側で完結」と謳っている点は重要で、サーバーに動画キャッシュが残らないため、法的リスクとストレージコストの両方を抑えられます。
実際の使い流れ(技術者目線で)
-
URLの正規化処理
ユーザーがコピーしたURLにはutm_パラメータやアンカーが付いていることがあります。ツール内部ではurllib.parseでクエリを整理し、 canonical な形式に変換しています。 -
プラットフォーム自動判別
tv.naver.com、vlive.tv、blog.naver.comなど、ドメインから対象サービスを判定し、それぞれに最適化したパーサーを呼び出します。 -
フォールバック機構
1つ目の解析手法で失敗した場合、代替のAPIエンドポイントや、ヘッドレスブラウザによるレンダリングを試行します。これにより「たまに動かない」というストレスを大幅に低減。 -
解像度の選択ロジック
m3u8プレイリストには複数の解像度が含まれることがあります。ツールではBANDWIDTHタグを元に、ユーザーに選択肢を提示。モバイル利用を想定して「480p推奨」のデフォルト設定も用意しています。
開発中にハマったポイント(実体験)
① CORSとプロキシ問題
ブラウザから直接NaverのAPIを叩くとCORSエラーになります。解決策は2つ:
- サーバーサイドでプロキシを挟む(今回採用)
- ブラウザ拡張機能として実装し、
webRequestAPIでヘッダーを改変
後者も検討しましたが、Qiita読者の皆様なら「サーバーサイド制御の方が運用しやすい」と共感していただけるかと。
② 動的トークンの有効期限
V LIVEの一部エンドポイントでは、access_tokenがページ読み込み時に発行され、5分程度で失効します。対策として、トークン取得→動画情報取得→ダウンロード開始を1リクエストチェーンで完結させる設計にしました。
③ 日本語ローカライズの落とし穴
「ダウンロード」と「保存」、「解像度」と「画質」など、技術用語の訳語はユーザー層によって好みが分かれます。本ツールでは、日本の技術コミュニティで一般的な表現を優先しつつ、ツールチップで補足説明を追加するバランスを取りました。
法的・倫理的なラインについて(ここはしっかり)
技術的に「できる」ことと、「してよい」ことは別問題です。本ツールの利用にあたっては、以下の点を強く意識しています。
✅ 推奨される使い方
- 自分が権利を持つコンテンツのバックアップ
- 学習目的での動画構造解析
- オフライン環境での個人視聴(再配布なし)
❌ 避けるべき使い方
- ダウンロードした動画をYouTubeなどに再アップロード
- 商用サービスでの無断利用
- DRMや有料コンテンツの回避試行
ツールページにも明記していますが、ユーザー自身の行動に対する法的責任はユーザー本人にあります。技術者は「できること」を提供するだけでなく、「どう使うべきか」のガイドラインも併せて提示する責任があると考えています。
Qiita読者への特別ヒント:自作ツールに「機能追加」するなら
もし本記事を読んで「自分でも作ってみよう」と思われた方へ、追加で実装すると喜ばれる機能を3つご紹介します。
-
クリップボード自動検出
navigator.clipboard.readText()とページフォーカスイベントを組み合わせ、URLを自動入力。UXが格段に向上します。 -
進捗バーのリアルタイム表示
WebSocketまたはServer-Sent Events(SSE)で、バックエンドのCeleryタスク進捗をフロントにプッシュ。ユーザーの「待ってる感」を軽減。 -
メタデータのJSON出力
動画タイトル・投稿日・再生回数などをJSONで出力できるようにすると、データ分析用途でも活用可能に。
// 簡易例:クリップボード自動貼り付け
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible') {
try {
const text = await navigator.clipboard.readText();
if (text.includes('naver.com')) {
document.querySelector('#url-input').value = text;
}
} catch (e) {
// 権限がない場合は無視
}
}
});
おわりに:技術は「使う人」のために
Naver動画のダウンロードという一見地味なテーマですが、裏にはHTTPプロトコル・DOM解析・非同期処理・UI設計・法遵守…と、フルスタックエンジニアの腕が試される要素が詰まっています。
今回ご紹介した Naver動画ダウンローダー は、そうした技術的課題を「誰でも使える形」に落とし込んだ一つの答えです。もちろん完璧ではなく、Naverの仕様変更には随時対応が必要ですが、オープンな技術スタックで構築しているため、コミュニティからのフィードバックも歓迎しています。
📌 最後に一言
技術の可能性を追求する一方で、コンテンツクリエイターへのリスペクトを忘れずに。
「便利」と「合法」のバランスを取ることこそ、プロフェッショナルの腕の見せ所だと信じています。
何か質問や技術的な議論があれば、コメント欄で気軽にどうぞ。
それでは、よいスクレイピングライフを!🚀
参考リンク
- Naver動画ダウンローダー
- HLS仕様書(Apple)
- yt-dlp GitHub ← Naver対応が進んでいるかも要チェック
- BeautifulSoup ドキュメント
