前提・実現したいこと
楽天ブックスの書籍ページから、ポイント情報をスクレイピングで取得したい。
いただきたいアドバイス
現状、楽天ブックスのポイント情報が取得できない状況のため、具体的にどのようなクラス/メソッドを使用して情報を取得するのが好ましいのか、アドバイスいただきたい。
発生している問題・エラーメッセージ
HTMLAgilityPack の DocumentNode.SelectNodes メソッドに以下の XPath を指定し、楽天のポイント情報を取得しようとしているが取得できない。
<ページ例>
https://books.rakuten.co.jp/rb/14660161/?s-id=books_pc_all_normal_nt_pt_item
<XPath 例>
"//div[contains (@class,'point-summary__total')]/span/text()"
→ 496 を取得したい
ブラウザの開発者モードにて、以下のコマンドで正しくポイントを含む要素が取得できることは確認済みである。
$x("//div[contains (@class,'point-summary__total')]/span/text()")
考察
デバッグを行い、取得している HTML の内容を解析したところ、ポイント情報はユーザーによって異なるため javascript で動的に取得しているように見受けられた。
ポイント数以外の静的な情報 (例えば著者名やタイトル) などは正常に取得できていることから、XPath の指定方法やメソッドの使い方の問題ではなく、取得した HTML の Javascript が解釈できていない? ことが問題であると推察している。
<!-- Point Summary --> <script type="text/template" data-component-template="bdg-point-display" data-name="point-summary"> <div class="bdg-point-display-summary point-summary rat-visible"> <img class="p-icon point-icon" src="https://r.r10s.jp/com/inc/home/20080930/ris/img/spux/icon_point.png" /> <div class="total"><span>{{points}}</span>ポイント</div> {{multiplier}}{{multiplierUp}}{{rebate}} <div class="link breakdown-link rat-click">内訳を見る</div> {{annotations}} </div> </script> <script type="text/template" data-component-template="bdg-point-display" data-name="point-summary-loading" data-component="point-summary"> <div class="loading"> <div></div> <div></div> <div></div> </div> </script> <script type="text/template" data-component-template="bdg-point-display" data-name="point-summary-error" data-component="point-summary"> <div class="message error rat-tracker">ポイント情報の取得に失敗しました。獲得予定ポイントが正しく表示されなかったため、時間をおいて、再度お試しください。</div> </script>
実装
MyWebClient クラスは、WebClient クラスを継承したクラス
Dim wc As MyWebClient = New MyWebClient Dim st As IO.Stream = wc.OpenRead(url) Dim enc As Text.Encoding = Text.Encoding.GetEncoding("euc-jp") '楽天ブックスは euc-jp の模様 Dim sr As IO.StreamReader = New IO.StreamReader(st, enc) Dim html As String = sr.ReadToEnd sr.Close() st.Close() Dim doc As HtmlAgilityPack.HtmlDocument = New HtmlAgilityPack.HtmlDocument doc.LoadHtml(html) Dim node As HtmlAgilityPack.HtmlNodeCollection node = doc.DocumentNode.SelectNodes("//div[contains (@class,'point-summary__total')]/span/") → ここで指定した XPath ヒットするオブジェクトが存在せず Null になっている
なお、特に WebClient クラスへのこだわりはない。
むしろ、MS が非推奨としている古いクラスなので他のクラス (e.g. HttpClient) に書き換えることを検討している。
しかし、現状、上記のようにポイント情報が取得できていない状況のため、HttpClient クラスに書き換えるのが良いのか、それとも、Selenium を使ったほうが良いのか、はたまた、ブラウザ機能ごと読み込んだほうがいいのか (WebView2 クラスを使ってブラウザそのものを表示させ、ログインなどをしたあとにブラウザを非表示にしたりする) 判断がつかない状況である。
検索をした限り、動的に評価される情報を含むページは、ブラウザを使って読み込みが完了するまで無限ループするような実装を見たが、それが好ましいのか、それ以外の方法がないのか判断ができていない。
(以前見たサイトなので URL がなく、うろ覚えだが、ページ読み込みが完了したイベントが発生した際に、現在の URL がもともとの URL? と同じか判断し、同じであれば読み込が完了したと判断していたように記憶している。)
補足情報(FW/ツールのバージョンなど)
VB.NET (C# でも可)
.NET Framework 4.7.2
HTMLAgilityPack 1.11.40
回答1件
あなたの回答
tips
プレビュー