[WinRT] Kindle の購入リストを取得する

Kindle Launcher ネタの続きです。

どうせならば、購入済みの一覧を拾ってきて、それに対してセカンダリタイルを付けれたほうが便利ですよね。ということで、購入リストを Kindle Cloud Reader から取得します。
Kindle Cloud Reader 自体がブラウザなので、なんとかなるだろう、という予想のもとに進めて方針を立てます。

  1. WebBrowser を使って Kindle Cloud Reader を表示する。
  2. 中身の DOM を拾って ASIN のリストを取得する。

な感じで ok でしょうってことで。

実際やってみると、いくつか難関があって、

  • WebBrowser で接続するときに User-Agent を偽装しないといけない。
  • WebBrowser 出 iframe 内ので HTML をどうやって取るのか?

というところです。本来はWindows ストアアプリとして作りたいところですが、WinRT の WebView と使うとまともに動かないので、WPF の WebBrowser を使います。HttpClient で直接データを持ってきてもよいのですが、購入リスト自体が iframe になっているのと、HTML のパースが面倒なのでパスします。そのうち、HTML のパーサーを作って試してみましょう。

■WebBrowser で User-Agent を偽装する

何故、偽装が必要かというと、そのまま WebBrowser で呼び出したときには、

こんな画面が出て接続ができません。そんな訳で、User-Agent を偽装しています。

private void OnClickCheck(object sender, RoutedEventArgs e)
{
    // url を取得
    string url = "http://read.amazon.co.jp" + "?dummy=" + DateTime.Now.Ticks.ToString();
    string ua = "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko"; // IE
    wb.Navigate(new Uri(url), null, null, ua);
}

偽装自体は簡単で、Navigate メソッドの第4引数に設定します。ここにヘッダを追加できるので、複数追加したいときは “rn” で追加すればよいそうです。すると、初回だけ Kindle のログイン画面が出て、その後はブラウザの cookie(かな?)が使われます。
URL に dummy を渡しているのはキャッシュが使われないようにするためです。

■購入リストを取得する

購入リストは iframe の中にあります。WebBrowser.Document が mshtml.HTMLDocument にあたるので、これを使って DOM で解析していきます。mshtml 自体は、参照設定で「アセンブリ」→「拡張」にある「Microsoft.mshtml」をチェックします。

結構、手間取ったのですが、iframe の中身を取るためには、doc.frames.item(0) な感じで iframe を取ってきて、mshtml.HTMLWindow2 で iframe のウィンドウを取得します。その後は、再び document プロパティで解析するというパターンですね。

private void OnClickGetList(object sender, RoutedEventArgs e)
{
    var doc = wb.Document as mshtml.HTMLDocument;
    var iwin = doc.frames.item(0) as mshtml.HTMLWindow2;
    var idoc = iwin.document as mshtml.HTMLDocument;
    var titles = idoc.getElementById("titles_inner_wrapper");

    vm.Books.Clear();
    var books = vm.Books;
    foreach (mshtml.IHTMLElement it in titles.children)
    {
        var id = it.getAttribute("id") as string;
        books.Add(GetBook(it));
        Debug.WriteLine(id);
    }
}

上記の方法は、WPF の WebBrowser でやった方法ですが、Windows デスクトップアプリの WebBrowser では次のようになります。既に、HtmlDocument が定義されているのでそのまま使います。iframe に対しては、GetElementById を使っては取れないので、Frames コレクションから直接取ってきます。

private void button2_Click(object sender, EventArgs e)
{
    var doc = webBrowser1.Document;
    // var iframe = doc.GetElementById("KindleLibraryIFrame");
    var iwin = doc.Window.Frames[0];
    var idoc = iwin.Document;
    var titles = idoc.GetElementById("titles_inner_wrapper");
    var ids = new List<string>();
    foreach ( HtmlElement it in titles.Children ) {
        ids.Add(it.Id);
        Debug.WriteLine(it.Id);
    }
}

購入一覧の場合は、最初の frame にあるので無条件に 0 を指定していますが、複数の iframe がある場合はチェックが必要でしょう。

こうすることで、WebBrowser を使って Kindle の購入一覧を取得できます。

お次は、取得した履歴をどうやってストアアプリと連携させるか、のトリックを紹介しましょう。

カテゴリー: C#, WPF パーマリンク