戻る


YouTubeに投稿した動画の再生回数を調べる

サンプルプログラム => YouTubeUploadsCheck.lzh

YouTubeに投稿した動画の再生回数、コメント数、お気に入りに登録された数を調べるサンプルです。 YouTube Insightを使えば詳細な情報を確認できます。 ですが私の場合はたまにサラッと見るだけなのでわざわざログオンして何度もクリックするのは面倒でした。 そこでYouTube Data APIを使って見たい情報だけをまとめる簡単なコードを作りました。

確認した環境は以下の通りです。

OSWindowsXP home edition
jdkversion 1.6.0

YouTubeの「デベロッパーガイド」を見るとData APIを使って色々なことができるようですが、今回試すのはチャンネルのエントリー情報を得るだけのコードです。 まずは、ブラウザで次のアドレスにアクセスしてみてください。

「Uploads by PieceOfNostalgy」というタイトルのページが表示されるはずです。 投稿動画のタイトルや説明の一覧が表示されます。 PieceOfNostalgyというのは私のチャンネルです。 先ほどのアドレスのPieceOfNostalgyの部分を別のチャンネル名に変えればそのチャンネルの情報が表示されます。 表示されたページはAtom形式なのでxmlファイルとして保存できます。

ブラウザで直接表示したときの情報は少ないですが、ダウンロードしたxmlファイルを開きなおすと様々な情報が入っていることがわかります。 xmlファイルのフォーマットはYouTubeの「リファレンスガイド」で調べられます。 このxmlファイルから必要な情報だけ取り出せば目的は達成できそうです。 投稿した動画の数が少ないなら1度のアクセスで済みます。 しかし、数が多い場合は1度のアクセスだけでは全てのエントリーの情報を得られません。 1アクセスで得られるエントリー数に上限があるためです。 全部の情報を得るには何度かに分けてxmlファイルを落とす必要があります。

全てのエントリーを調べる方法は2つあります。 1つ目は、エントリーの総数や1ページのエントリー数を調べてループする方法です。 これらの数字はfeed要素の子の3要素を見ればわかります。

最初のページのstartIndexは1です。 0からではないので注意しましょう。 アドレスでstart-indexを指定すればそのエントリー以降を得られます。 例えば、5つ目以降を得るには次のアドレスにアクセスします。

itemsPerPageのデフォルト値は25なので、84のエントリーがあるときは次の4つのアドレスにアクセスすれば全部調べられます。

itemsPerPageの値は将来変更されるかもしれません。 お行儀よくやるなら毎回startIndex+itemsPerPageを計算して次のstartIndexを求めたほうが良いでしょう。 全てのエントリーを調べる2つ目の方法ですが、その次のstartIndexが計算済みのアドレスが書かれた要素があるのでそれを調べます。

次のstartIndex付きのアドレスは途中のページを落としたときのみ書いてあります。 いくつかある「/feed/link」の中で「@rel="next"」の属性を持つ要素を探しましょう。 そのhref属性に目的のアドレスが書いてあります。

<link rel="next" type="略" href="次のアドレス"/>

そのアドレスにアクセスすれば芋づる式に全部のエントリーを得られます。 このページではこちらの方法を試しています。

サンプルコード

サンプルコードではダウンロードしたxmlファイルからentry要素だけをコピーして出力用xmlファイル「entries.xml」にまとめています。 javaでxmlの内容を解析するコードは長くなるので、xslで一覧表を作ることにしました。 サンプルの動作確認は、まずコマンドプロンプトでYouTubeUploadsCheckを実行し、

java YouTubeUploadsCheck チャンネル名

できた「entries.xml」をブラウザで開きます。 entries.xmlはスタイルシートに「entries.xsl」が設定されているので、開くだけで整理済みの情報が見れます。

以下、YouTubeUploadsCheck.lzhの中にある「YouTubeUploadsCheck.java」から抜粋して説明します。

javaでxmlファイルをダウンロードするコードは次のようになります。 (エラー処理は省略してます。)

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder        builder = factory.newDocumentBuilder();
Document               dataDoc = builder.parse(uri);

entry要素のコピー先Documentは次のように作ります。

private Document _createEntriesDoc(DocumentBuilder builder, String account)
{
    Document res = builder.newDocument();

    // 処理命令登録
    ProcessingInstruction pi
        = res.createProcessingInstruction(
            "xml-stylesheet", 
            "type=\"text/xsl\" href=\"entries.xsl\"");
    res.appendChild(pi);

    Element entriesElem = res.createElement("entries");

    // ネームスペース登録
    entriesElem.setAttribute("xmlns:media",
                             "http://search.yahoo.com/mrss/");
    entriesElem.setAttribute("xmlns:openSearch",
                             "http://a9.com/-/spec/opensearchrss/1.0/");
    entriesElem.setAttribute("xmlns:gd",
                             "http://schemas.google.com/g/2005");
    entriesElem.setAttribute("xmlns:yt",
                             "http://gdata.youtube.com/schemas/2007");

    // ついでにチャンネルのidも登録。
    entriesElem.setAttribute("id", account);

    res.appendChild(entriesElem);

    return res;
}

「処理命令登録」のところでxsltスタイルシート名を書いています。 属性の追加は1つの属性につき1回setAttributeを呼びますが、処理命令登録ではtype、hrefの項目両方を一度に渡します。 ルート要素を登録する前に処理命令登録をしないと無効になります。 順番を間違えたときエラーメッセージや例外は発生しないようなので注意が必要です。

ネームスペースはダウンロードしたxmlファイルを見て確認し、登録しました。 Atomの「xmlns='http://www.w3.org/2005/Atom'」は必要ありません。 ついでに、xslの見出しで使うためにチャンネル名もentries要素に登録しています。

ダウンロードしてきたxmlファイルからentry要素のコピーをするコードは次の通りです。

private void _importEntries(Document dataDoc, Document entriesDoc)
{
    Element dataElem    = dataDoc.getDocumentElement();
    Element entriesElem = entriesDoc.getDocumentElement();
    NodeList nodeList   = dataElem.getChildNodes();
    for(int i = 0; i < nodeList.getLength(); i++)
    {
        Node node = nodeList.item(i);
        if(node.getNodeName().equals("entry") )
        {
            Node importNode = entriesDoc.importNode(node, true);
            entriesElem.appendChild(importNode);
        }
    }
}

別のDocumentから要素をコピーする場合はDocument.importNodeでコピーを作ります。 コピーを作らずにdataDocのノードを直接entriesDocのノードに追加しても例外が発生するので注意しましょう。

全てのエントリーが得られなかった場合、次のアドレスを調べるためのコードは次のようになります。

private String _getNextUri(Document doc)
{
    NodeList nodeList = doc.getDocumentElement().getChildNodes();
    for(int i = 0; i < nodeList.getLength(); i++)
    {
        Node node = nodeList.item(i);
        if(node.getNodeName().equals("link") )
        {
            Element linkElem = (Element)node;
            if(linkElem.getAttribute("rel").equals("next") )
            {
                return linkElem.getAttribute("href");
            }
        }
    }
    
    return null;
}

次のアドレスがあった場合はその文字列を、次のアドレスがない場合はnullを返します。 呼び出し元は文字列が返されたら、

  1. 次のエントリー情報のダウンロード
  2. entry要素のコピー
  3. さらに次のアドレスが無いかチェック

を繰り返します。

entry要素を全てコピーし終わったら「entries.xml」に出力します。 (エラー処理は省略してます。)

private void _write(Document doc)
{
    TransformerFactory factory     = TransformerFactory.newInstance();
    Transformer        transformer = factory.newTransformer();

    DOMSource        source  = new DOMSource(doc);
    File             outFile = new File(OUT_FILE_NAME);
    FileOutputStream fos     = new FileOutputStream(outFile);
    StreamResult     result  = new StreamResult(fos);
    transformer.transform(source, result);
}

あとは「entries.xsl」に動画タイトルや再生回数のtableを表示するコードを書けばOKです。 「entries.xsl」のルート要素「xsl:stylesheet」には「entries.xml」に登録したのと同じネームスペースを書かなくてはならないので注意しましょう。


広告 : Amazon.co.jpアソシエイト