Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

VBAプログラム開発、スクレイピング・データ取得をレコード単位に修正する【2】レコード要素を取り出して表示する

前回までにスクレイピングデータをレコード単位で取得できるようにしました。

今回は取得したレコードデータを要素毎に指定のセルへ表示させていきます。

今回の目的

スクレイピングによりレコード単位で取得したデータから、必要なデータをとりだしてExcelへ表示させる

なぜやるか

レコードを意識したデータ取得を実現したので、取得データから必要な情報をExcelに表示できるように処理変更するため

やりたいこと

  • レコード単位データから必要な要素をとりだす
  • 取り出した要素をExcel画面上に出力する

やったこと

  • レコード単位で取得したデータから必要なデータを取得する
  • タイトル名を取得して表示させる
  • クラス指定で取得したデータから更にクラス指定をする

実施内容

レコードデータを扱う

変数名を修正する

初めにHTML要素を取得したデータはStrという名前の変数にいれていました。文字情報を格納していたので、こういう名前にしていたのですが、今はレコード単位でHTMLを格納するという目的となっているので、StrからBookdataという名前に変更しました。

意味のある変数名とすることで、名前からどういうデータを扱っているかがよく分かるようになりました。

タイトル名を取得して表示する

レコード単位でデータ出力できたので、ここからタイトル名など、Excel上に表示させるデータを取得できるようにしていきます。

 

# スクレイピング

Dim Bookdata As Object
Dim i As Integer

i = 1

'レコード単位出力をためす
For Each Bookdata In htmlDoc.getElementsByClassName("book-table__list")
 '2列目にHTML全体を出力
 Worksheets("テスト").Cells(i + 1, 2).Value = Bookdata.innerHTML
 '3列目にタイトル名を出力
 Worksheets("テスト").Cells(i + 1, 3).Value =

  Bookdata.getElementsByClassName("list-book-title")(0).innerText
 '次のレコードの行番号
 i = i + 1
Next Bookdata

前回までに、レコード単位のデータを取得し、2列目にレコード単位のHTMLを表示させる処理を作成していました。

3列目処理として、タイトル名だけを個別に指定して出力するコードを追加しました。

 

レコードとしてBookdata変数に取得しているHTMLを確認して、どこのどのデータを取得しているか確認します。

# HTML

<div class="book-table__list">

 

 ↓ここからのデータがBookdataに入っている
 <div class="book-table__list--checkbox">
  <input name="select_books[]" type="checkbox" value="8">
 </div>
 <div class="book-table__list--picture">
  <a href="/book/8">
   <img src="https://cover.openbd.jp/9784797398892.jpg">
  </a>
 </div>
 <div class="book-table__list--detail">
  <a href="/book/8">

   <h3 class="list-book-title">

    1冊ですべて身につくHTML &amp; CSSとWebデザイン入門講座

   </h3>

  </a>
  <p class="list-book-detail">

   日本で2年間...

  </p>
 </div>

 ↑ここまで


</div>

Bookdataは、"book-table__list"を指定したので、上記のHTMLを取得した状態です。

この中からタイトル名を取得するために"list-book-title"を指定することでタイトル名を取得しました。

f:id:Fippiy:20190610131053j:plain

レコードからタイトル名取得

タイトル名取得コードはBookdata.getElementsByClassName("list-book-title")として、"list-book-title"というクラス名の全データを取得しました。

指定元がBookdataの為結果としては1個のデータしかありませんが、全件取得となっているので(0)として一つ目の要素を取り出す形としました。

これでレコード単位でデータを取得した上で必要な要素を取り出せました。

 

他の要素についても、同様にレコードデータから要素をしていする形に変更します。

 

要素の取り出し方を考える

同様の手順で実施すれば終了すると思っていましたが、詳細ページURLを処理している時点で気がついた事があります。

 

それは…。

 

初めにスクレイピングコード作成していた時、詳細ページURLにはクラス名指定がないので、親要素タグに設定したクラス名からデータを取得し、配下のaタグ要素というデータの取り方をしていたということ。

 

どういうことかおさらいすると…

# book.index(HTML)

<div class="book-table__list--detail">
 <a href="/book/8">

  <h3 class="list-book-title">

   1冊ですべて身につくHTML &amp; CSSとWebデザイン入門講座

  </h3>

 </a>
 <p class="list-book-detail">

  日本で2年間グラフィックデザイナーとして...

 </p>
</div>

詳細ページへのリンクはaタグで記載していました。しかし、このタグにはクラス名がありません。

また、書籍画像にも同じaタグによるリンクを設定してどちらをクリックしても詳細ページに遷移できるように作成しています。

この為、初めに作成していたスクレイピングコードでは、aタグの親となるdivタグのクラス名"book-table__list--detail"によって要素を特定し、その中のaタグとして指定することでURLを取得していました。

この記述を利用するのであれば、"book-table__list--detail"の中身を一端取得して、そこからURLの取得とID番号も取得していたので処理が必要です。

 

と、これはおさらいで、気づいたことは何か…それは。

 

"book-table__list--detail"の中に

  1. タイトル名
  2. 詳細テキスト
  3. 詳細ページURL
  4. ID番号

が全て含まれているということ。

# book.index(HTML)

<div class="book-table__list--detail">
 <a href="/book/8"> ’3.詳細ページURL、4.ID番号

  <h3 class="list-book-title">

   1冊ですべて身につくHTML &amp; CSSとWebデザイン入門講座 '1.タイトル名

  </h3>

 </a>
 <p class="list-book-detail">

  日本で2年間グラフィックデザイナーとして... '2.詳細テキスト

 </p>
</div>

初めにタイトル名を取得したときは直接タイトル名が入っているクラス"list-book-title"を指定、詳細テキストも同様に作成してURL処理の時点で気づいたというわけです。

処理すべき要素が全て入っているなら、"book-table__list--detail"を取得してから各要素取得処理を実施するほうがいいのではないかと考えました。

 

ただ、画像データはこのクラスに含まれていませんので、レコード単位全体のデータは必要です。

 

詳細情報が格納されたクラスからテキストを取得する

データを取得する手順が決まりましたので、これに沿ってレコードから要素を取得してExcel画面上に出力していきます。

Dim Bookdata As Object 'レコード単位データ
Dim detailField As Variant '詳細フィールドデータ

 

Dim GetUrl As String '詳細ページURL
Dim GetUrlData() As String '詳細ページURL,Splitデータ
Dim GetUrlElement As Integer 'URLSplit要素数
Dim GetID As Integer 'ID番号

Dim i As Integer

i = 1

 

' book-table__listの要素をBookdataとして処理
For Each Bookdata In htmlDoc.getElementsByClassName("book-table__list")

 'Bookdata要素全体HTMLを出力

 Worksheets("テスト").Cells(i + 1, 2).Value = Bookdata.innerHTML

 '--detail部を取得してそれぞれ反映

  '--detailを取得

  detailField = Bookdata.getElementsByClassName("book-table__list--detail")
  'タイトル名
  Worksheets("テスト").Cells(i + 1, 3).Value = _

   detailField.getElementsByClassName("list-book-title")(0).innerText
  '詳細テキスト
  Worksheets("テスト").Cells(i + 1, 4).Value = _

   detailField.getElementsByClassName("list-book-detail")(0).innerText

 

  '詳細ページURL取得
  GetUrl = detailField.getElementsByTagName("a")
'URL取得
  Worksheets("テスト").Cells(i + 1, 5).Value = GetUrl
'取得URL反映

  'URLからID取得

  GetUrlData = Split(GetUrl, "/") 'URL要素取得
  GetUrlElement = UBound(GetUrlData) 'URL要素数確認
  GetID = GetUrlData(GetUrlElement) 'URLからID取得
  Worksheets("テスト").Cells(i + 1, 1).Value = GetID '取得ID反映

 '--detail部を取得してそれぞれ反映ここまで

 

 '次のレコードの行番号
 i = i + 1
Next Bookdata

レコード要素をBookdataとして取得していました。

そこから、"book-table__list--detail"内の情報を取得し、detailFieldという変数に格納しました。

あとはdetailFieldから必要な情報を取り出してExcelワークシートへ反映していけば完了です。

詳細ページURL情報取得はもっと処理を考える必要があるかもしれませんが、まずはレコード単位処理完了を目指して、前回作成コードをできるだけ流用しています。

f:id:Fippiy:20190610145559j:plain

レコードデータ単位で出力

データが表示されていることを確認しました。

 

そして、レコード単位で処理できていることも確認しておきます。

f:id:Fippiy:20190610145752j:plain

ForEach処理にブレークポイント

ForEachの1件目処理が終わった段階でVBAを停止するポイントを設定しておき、1件目だけを処理させて中断します。

f:id:Fippiy:20190610145941j:plain

1件目出力

レコード単位で処理結果が出力されました。

カラム単位となっていた処理がレコード単位に変更できていることが確認できました。

 

以上でレコード単位でデータを扱う方法でスクレイピングすることができるようになってきました。

 

残るは画像処理です。こちらは次回記事として作成します。