質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

1回答

2235閲覧

VBAでスクレイピングを行いたいのですが、取得したい要素を取得することができずに困っています

ConCon_

総合スコア12

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2021/09/02 12:06

前提・実現したいこと

VBAで、Webサイトから、以下の「取得したい要素①~③」の値を抽出したいと思っています。
サイトの構造は簡単に書くと以下のようになっています。
取得したい要素は、テキストボックスに入力されている値です。

取得したいページのソースコード

html

1<section id="AAA" Class="BBB"> 2 <form> 3 <div Class="CCC">...</div> 4 <div Class="CCC">...</div> 5 <div Class="DDD"> 6 <div Class="EEE"> 7 <div Class="DDD">...</div> 8 <div Class="DDD">...</div> 9 <div Class="DDD"> 10 <div Class="FFF">...</div> 11 <div Class="GGG"> 12 <table Class="HHH"> 13 <tbody> 14 <tr> 15 <th>あああ</th> 16 <td> 17 <div Class="III"> *取得したい要素① 18 </td> 19 </tr> 20 <tr> 21 <th>いいい</th> 22 <td> 23 <input type="JJJ" name="KKK" value class="LLL"> *取得したい要素② 24 </td> 25 </tr> 26 <tr> 27 <th>ううう</th> 28 <td> 29 <input type="JJJ" name="KKK" value class="LLL"> *取得したい要素③ 30 </td> 31 </tr> 32 </tbody> 33 </table> 34 </div> 35 </div> 36 </div> 37 </div> 38 </form> 39</section> 40 41<div Class="MMM">...</div> *ボタン① 42<div Class="NNN">...</div> *ボタン①を押すと開くポップアップウィンドウ 43<div Class="OOO">...</div> *ボタン② 44<div Class="PPP"> *ボタン②を押すと開くポップアップウィンドウ 45 <div id="QQQ" class="RRR"> 46 <div Class="SSS"> 47 <div Class="TTT"> 48 <div Class="UUU"> 49 <div id="VVV" class="WWW"> 50 <aside>...</aside> *ここのtdが取得される 51 <main>...</main> *ここのthが取得される 52 </div> 53 </div> 54 </div> 55 </div> 56 </div> 57</div> 58 59</div> 60 61

試したこと

以下のサイト等を参考にしてgetElementsを試しました。
https://dailyrecords.blog/archives/5052
https://tonari-it.com/vba-ie-get-table/

試したソースコード

以下は共通部分です。

vba

1Dim objIE As InternetExplorer 2Set objIE = New InternetExplorer 3 4'****指定した案件の詳細ページを開く*** 5 '※以下はページを表示するために行っていることなのであまり気にしないでください 6 7 Dim matterNumber As String '番号 8 Dim pageNumber As String '番号の下4桁(URL生成用) 9 10'番号を入力するボックスを表示 11 matterNumber = InputBox("案件番号を入力してください") 12 13'番号の下4桁を取得 14 pageNumber = Right(matterNumber, 4) 15 16'URL末尾に番号を付け加える 17 objIE.Visible = True 18 objIE.navigate "※取得したいページのURL※" & pageNumber 19 20'応答があるまで待つ 21 Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE 22 DoEvents 23 Loop

上記の下に次のコードを記述して実行すると、

<div id="VVV" class="WWW">の要素が取得されます。 これはボタンを押すと、取得したいページの上に開くポップアップウィンドウの要素です。 th→tdにすると取得される値は変わるものの、同様のウィンドウの要素なことは変わりません。 ``` Dim i As Integer i = 1 For Each element In objIE.document.getElementsByTagName("th") Cells(i, 1) = element.innerText i = i + 1 Next ```

以下の場合、
「実行時エラー'438':オブジェクトは、このプロパティまたはメソッドをサポートしていません」と表示され、elementの値は「empty値」となります。

Dim i As Integer i = 1 For Each element In objIE.document.getElementsById("AAA") Cells(i, 1) = element.innerText i = i + 1 Next

###最後に

初心者なものでどこをどう削れば良いか分からず、大変長くなってしまい申し訳ありません。
getElementsの使い方も理解できていない点が多いので、ここをこうすると取得できるのではないかというものがありましたら、教えていただけると嬉しいです。
また、不足している情報がありましたら、追記しますので、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

1T2R3M4

2021/09/02 12:38

>Webサイトから どこのサイトですか。
ConCon_

2021/09/02 13:28

すみません、会社関連でこちらに貼り付けるわけにはいかないサイトだったもので、構造だけ記載させていただきました…!
ishina_yum

2021/09/02 14:06

そもそもとして、『取得したいページのソースコード』の形のデータが取得できているのでしょうか。 Debug.Print objIE.document.DocumentElement.outerHTML などをしてみて、本当に想定通りのHTMLであるかの確認はお済みですか?
ku__ra__ge

2021/09/03 00:48 編集

取得したい要素を特定するための条件を明確にしてください。 Class="III"を持った要素とclass="LLL"を持った要素を取得したいのですか?
ConCon_

2021/09/03 01:30

ishina_yum様 今までは単純なサイトでしか実行していなかったので問題なく取得できていたのですが、想定通りのHTMLではないという可能性もあるのですね… 教えていただいたコードを試したところ、文字数制限で全ては確認できなかったのですが、 Excelに転記すると、取得したいページのソースコードの1行目<html style=...>から表示され、 イミディエイトウィンドウは最後の1、2行</body></html>で終わっているため、 その間にある、取得したい部分も取得できる状態にはあるのではないかと思うのですが、 そういうものでもないのでしょうか?(本当に初心者で申し訳ありません) また、例えばフレーム構造になっていて取得できないということがあるのかと思いつき、<Frame>タグがないか調べましたが、使われてはいませんでした。 「想定通りのHTMLではない」というのは、例えばどういう状態なのでしょうか…?
ConCon_

2021/09/03 01:39

ku__ra__ge様 確かにどこを取得したいのかが明確ではないですね。大変失礼しました。 取得したい部分はどれも、<td>部分なのですが、サイト上では左に<tr>の見出し、右に<td>の入力フォームがあり、入力フォームに元から入力されている値を取得したいのです。 入力フォームからの取得の場合、方法が違うのでしょうか…? つまり、サイト上で見ると以下のような表示となっていて、|で挟まれた入力フォームの中身、「わわわ」「ををを」「んんん」を取得したいということです。 ①あああ |わわわ| ②いいい |ををを| ③ううう |んんん|
ku__ra__ge

2021/09/03 02:15

> 入力フォームからの取得の場合、方法が違うのでしょうか…? はい。div要素内の文字を取得する方法と、input要素のvalue値を取得する方法は異なります。 値を取得する要素を1つに特定できるように、どんな条件で要素を取得するのかを質問者さんが決める必要があります。 (テーブルはページ内に1つしか存在しない前提なのか、2つ以上ある場合はどんな条件で取得したい値が入っているテーブルを特定するのかなども)
ConCon_

2021/09/03 03:38

ku__ra__ge様 >はい。div要素内の文字を取得する方法と、input要素のvalue値を取得する方法は異なります。 なるほど!そもそもの前提条件が違っていたんですね… >値を取得する要素を1つに特定できるように、どんな条件で要素を取得するのかを質問者さんが決める必要があります。 こちらにも気をつけながら調べ直し、また行き詰ったら質問させていただきたいと思います! 気付かせてくださってありがとうございました!
h.horikoshi

2021/09/03 04:09

横からですが一点。気がつきにくいので… IDをキーにして検索する場合はnameやclassNameの時と異なり getElementの後ろに"s"がつきません。具体的には 誤:getElementsById("AAA") → 正:getElementById("AAA") です。 ご質問の「実行時エラー'438'」はたぶんそのためです。
ConCon_

2021/09/03 08:08

h.horikoshi様 >IDをキーにして検索する場合はnameやclassNameの時と異なりgetElementの後ろに"s"がつきません。 すっかり見落としていました…! ID検索のときだけ違うエラーが出るのが気になっていたのですが、すっきりしました。 教えていただきありがとうございます!
ishina_yum

2021/09/04 13:00

> 「想定通りのHTMLではない」というのは、例えばどういう状態なのでしょうか…? 1. 渡すパラメータが間違っているなどして、欲しい情報が取れる状態になっていない(「データが見つかりません」状態)の可能性 2. URLが間違っている可能性 3. 仕様が変わっていて『取得したいページのソースコード』の形式とは異なったHTMLが取得された可能性 何か取得できているから大丈夫だろう、ではなくて『本当にそれが目的のデータであるのか』の確認をしましょうと言うことです。
guest

回答1

0

こんにちは。
getElementsByTagName と getElementById 名前は似ていますが、
1つのHTMLの中に、<th>などのタグは複数現れることが普通にあるので、getElementsByTagName
はElement ではなくてElements(複数形)になっていて、結果が対象オブジェクトの配列で
返ってきます。たとえ当該HTMLに対象のタグがたまたま1つしかなくても1個の配列として返って
きます。一方IDは一意なのでgetElementByIdはElements ではなくelement(単数形)で
結果は、対象のオブジェクトただ1つです。

試したことの中でgetElementsById("AAA") を指定したときにエラーになったのは
elementsと書いたためそもそもメソッドがなかったか、かりに実際にはgetElementById("AAA")
と書いていたとしても、戻り値がオブジェクト配列ではないのでFor Eachの対象にならなかったのでは
ないかと思います。

似たような名前のgetElementsByClassNameもタグ同様1つのHTML内に同一クラスのオブジェクトが
複数ある可能性があるので、複数形で、返ってくるのはオブジェクトの配列です。
getElementsByNameも複数形ですね。

例えば文章にある「取得したいページのソースコード」で取得したい要素1が含まれるDIVには
”III"というクラスが指定されていて、このクラスは当該HTML内に1つしかありませんので

objIE.document.getElementsByClassName("III") とすると、このDIVが1つだけ入った
配列が取得できます。今回はDIVの中にある文字列が欲しいようですので

objIE.document.getElementsByClassName("III")(0).InnerText

とすれば、取得したい要素1が見つかるのではないかと思います。
(配列は0番目からスタートなので、1ではなく0ですね)

また、取得したい要素2、3はどちらもLLLというクラスで、このクラスもこの2要素以外は
存在しないようですから

objIE.document.getElementsByClassName("LLL")(0).Value
で要素2が、同様に
objIE.document.getElementsByClassName("LLL")(1).Value
で要素3が取得できると思います。
(こちらは取得した要素がDIVでなくINPUTなので値はInnerTextではなくてValueで取得としました)

ちなみに要素2と3はクラス以外にも名前もKKKで統一されていますので、
getElementsByClassNameの代わりにgetElementsBYNameを使って

objIE.document.getElementsByName("KKK")(0).Value
objIE.document.getElementsByName("KKK")(1).Value

と指定しても同様の結果が得られると思います。

投稿2021/09/28 02:57

beadv

総合スコア144

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問