Kindle Launcher ネタの続きです。
どうせならば、購入済みの一覧を拾ってきて、それに対してセカンダリタイルを付けれたほうが便利ですよね。ということで、購入リストを Kindle Cloud Reader から取得します。
Kindle Cloud Reader 自体がブラウザなので、なんとかなるだろう、という予想のもとに進めて方針を立てます。
- WebBrowser を使って Kindle Cloud Reader を表示する。
- 中身の 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 の購入一覧を取得できます。
お次は、取得した履歴をどうやってストアアプリと連携させるか、のトリックを紹介しましょう。