
https://www.oddsportal.com/football/albania/supe …
と云うサイトの表(サッカーの試合のオッズを表示)のデータをキチンと取り込めません。
以前は
Driver.FindElementByXPath("//*[@id=""tournamentTable""]/tbody").AsTable().ToExcel (Worksheets("table").Cells(1, 1))
でExcelのシートに正常に取り込めていたのですが、最近、HTMLの記述が変わった為かこの方法が使えません(そもそも、"tournamentTable"というIDが見当たらなくなりました)。
また、別の手段として
Driver.SendKeys ks.Control, "A" '全選択
Driver.SendKeys ks.Control, "C" 'コピー
ActiveSheet.PasteSpecial Format:="HTML", link:=False, DisplayAsIcon:=False, NoHTMLFormatting:=True
でも動作していたのですが、現在、このコードでは表のデータの下半分の大部分が取り込めません(どういう訳か、最下部の数行は正常に取得)。
この場合、マウス操作で表だけを範囲選択すればデータを正常に取得できます。
しかし、これでは自動化にならないので、上記サイトに対しての何か適切なスクレイピング手段があれば教えて下さい。
宜しくお願いします。
No.4ベストアンサー
- 回答日時:
No3です。
>戴いた2つのプロシージャを一つのプロシージャとして~~
二番目の方は再帰利用する仕組みにしているので、簡単にはまとめられないと思いますけれど??
・・どうやら回答の意味も内容も伝わっていないように感じます。
>この中に macro_Scrapeの名前がありません
引数をとるプロシージャの形式のままなら、そのマクロから処理を始められるはずはありません。
「疑似的に」と書きましたように、No3のコードはHTMLDocumentが取得できているものとして、解析部分だけを普通のVBAで記述したものです。
通常のVBAからでもHTMLソースのDocumentは取得可能ですが、ご質問のサイトではデータ部分は後から作成している関係で、ソースからだけでは情報が得られません。
ブラウザ経由にしないと取得したい情報は得られない状態になっています。
(No3では表示後のDOMをHTML化したものを作成し、それを疑似的に読み込んでパースしたものを解析しています)
記載がないので推測になりますが、多分、質問者様はSeleniumを利用して取得なさっているものと思いますので、そのDocumentに対して「同様」の処理を行えばできるだろうという意味での例示がNo3です。
とは言え、Seleniumと通常のVBAではオブジェクトが異なるので、そのままをコピペしても動作しないはずです。
(No3に「このまま使うことはないでしょう」と記したのはそういう意味です)
そのままでは動きませんので、Seleniumのオブジェクトに合わせて変換する必要があります。
とは言え、Basic言語が元なので変換は比較的簡単であろうと推測した次第です。
(No2で示したjavascriptでの処理の方が配列処理やループを記述しやすいので、遥かに簡単な記述ですみますが(=配列化までなら 十行程)、それを提示したところでそちらでVBA化するのは大変だろうと考え、親和性の高い通常のVBAでの回答にしたものがNo3です。)
当方には環境もなく記述法も知りませんので、書き換えまではできないため「これ以上は無理」と書きました。
一方で、DOM操作に関してはSeleniumの方が便利そうで、FindElementByCssのようなメソッドもあるようなので、二重ループも一重にすることができると思います。
また、VBAには配列を扱うメソッドがほとんど無いのに対して、(内容は知りませんが)ToArrayやSort、ToExcelといったメソッドもあるようですので、全体的にコードを簡略化できるのではないかと想像します。
詳細なコメント、有り難うございました。
・・どうやら回答の意味も内容も伝わっていないように感じます。
→ 情け無いのですが御指摘のとおりです。
ところが先程ネット検索をしていた所、「Selenium サポート終了」の記事を発見。
従って、これからは別の手段(Pythonとか HTTPなど)を使う必要がありそうなので、これらに挑戦してみたいと思っています。
fujillinさんにはお忙しい中、今回も多くの丁重なアドバイスを頂戴し心より感謝しております。
宜しければ、これに懲りず今後も宜しくお願いします。
No.3
- 回答日時:
No2です。
No2のデータ取得はjavascriptで行ったものですが、VBAで同じことを疑似的にやってみました。
VBAの HTMLDocument はquerySelectorが使えないなどいろいろと面倒なのですが、(Seleniumは存じませんけれど)Seleniumにはもっと効率の良い方法があるのではと想像します。
HTNLDocumentが取得できているものとして、以下のOUTPUTプロシージャで、シートに添付図のような結果が得られます。
順にテキストを取得してゆく方式なので、タイトル行の「1 X 2 B's」の部分が左に寄っていますけれど、手抜きで全行同じ処理にしてしまったためです。
このまま使うことはないでしょうし、容易に調整できると思いますので、そのままにしてあります。
当方、Selenium環境がありませんので、残念ながらこれ以上は無理です。
以下、ご参考にでもなれば。
※ 引数Docは HTMLDocment です。
※ Selenium Basic ではメソッド等も変わるはずですが、似た様な感じではと想像します。
Sub OutPut(ByRef Doc)
Dim elms, elm, el
Dim rg As Range
Cells.ClearContents
Cells.Interior.Color = xlNone
Set rg = Cells(1, 1)
Set elms = Doc.body.getElementsByClassName("eventRow")
For Each elm In elms
For Each el In elm.Children
If el.Children.Length > 1 Then _
rg.Resize(, 10).Interior.Color = RGB(230, 230, 230)
Call getText(el, rg)
Set rg = Cells(rg.Row + 1, 1)
Next el
Next elm
End Sub
Sub getText(ByRef el, ByRef r As Range)
Dim s As String, e
If el.Children.Length Then
For Each e In el.Children
Call getText(e, r)
Next e
Else
s = Trim(Replace(Replace(el.textContent, Chr(13), ""), Chr(10), ""))
If Len(s) And InStr(el.className, "mr-3") = 0 Then
r.Value = s
Set r = r.Offset(, 1)
End If
End If
End Sub

此処まで作業して頂くとは思いも寄りませんでした。
本当に感謝の言葉もありません。
ところで、戴いた2つのプロシージャを一つのプロシージャ(マクロ名 : macro_Scrape)としてVBAの実行ボタンを押してもマクロがスタートせずにマクロ名の一覧が出てきてしまいます。
この中に macro_Scrapeの名前がありません(当然なのかもしれませんが)。
そこで OutPutと getTextのプロシージャを切り分けて夫々を実行してみたのですが、いずれも上記と全く同じ反応でした。
そこでもう少し試行錯誤してみたいので暫く時間を頂ければと思います。
宜しくお願いします。
P.S.
結果として添付図のようであれば完璧です。
タイトル行が左に寄っているのは小生でも修正できるので御安心下さい。(笑)
No.2
- 回答日時:
No1です。
時間ができたので、もう少し調べてみました。
div.eventRow の孫要素が概ね1行分のデータを保持しています。
(セレクタで言うなら、「div.eventRow > div > div」)
仮に、これを単位として、その子要素が持つテキストを一律で列挙させてみると、以下のようになります。
以下は最初の約10行分ですが、全試合分取得可能です。
(実際のテキストはもっと深い階層にありますが、直接の子要素でまとめて取得したものです)
['07 May 2023 ']
['1', 'X', '2', "B's"]
['22:00', 'Laci11–1Erzeni1', '', '2.10', '3.28', '3.22', '3']
['01:00', 'Partizani33–1Kukesi1', '', '1.64', '3.52', '5.22', '7']
['01:00', 'Teuta22–1KF Tirana1', '', '3.40', '3.31', '2.06', '12']
['06 May 2023 ']
['1', 'X', '2', "B's"]
['21:00', 'Egnatia22–0Bylis0', '', '1.85', '3.31', '4.19', '11']
['01 May 2023 ']
['1', 'X', '2', "B's"]
['01:00', 'Vllaznia00–4Egnatia4', '', '2.16', '3.22', '3.25', '12']
・・・・・・・
・・・・・・・
子要素数が1のものと4のものはセットになっていて、グレーバックで表示されているタイトル行になっています。
子要素数7の行が個々の試合結果のデータになっています。
チーム名と得点の部分は、上記ではまとまっていてわかりにくいですが、2番目の子要素だけ更にその子要素を調べる様にすれば、チーム名、得点等も分割して取得することが可能です。
1行コードではすみませんけれど、上記の規則性を利用すれば、単純なループ処理と分岐でそれぞれの値を取得することが可能と思います。
fujillinさんからの回答に気づくのが遅れてしまい申し訳ありませんでした。
ご多用中、わざわざ解析して具体的なデータを提示頂き恐縮です。
小生としてはこれを多少なりとも理解するのに大分時間がかかりそうなので、正式や返信は暫くお待ち頂ければ幸いです。
No.1
- 回答日時:
こんばんは
ざっと見ただけですが・・・
>表のデータをキチンと取り込めません。
>そもそも、"tournamentTable"というIDが見当たらなくなりました
無いものを探しても取得できるはずはありませんよね。
多分、構成が変わったのではないでしょうか?
(見た目にさほど違いはなくても、HTMLの構成が変わっているのでは?)
「表」というのは、「Football / Albania / Superliga」が一番上の行になっている表のことでしょうか?
その部分は、
<div class="flex flex-col px-3 text-sm max-mm:px-0">
<div data-v-238d5b4d="">
以下の子要素(div)で構成されています。
細かなレイアウトまでは調べていませんが、flexレイアウトで表に見える様にレイアウトしているようです。
直接の子要素のDIVは表示上では1~3行分のになっているようなので、1行分はさらにその子要素になっているのでしょう。
ただし、上記はご提示のサイトの現状の表示を調べてみただけなので、日付や内容が変わったりした際に、常に同じ識別子なのかどうかまではわかりません。
(例えば、「data-v-238d5b4d」のようなdata名は、日付や節等に応じて変わりそうな感じがします)
>上記サイトに対しての何か適切なスクレイピング手段があれば教えて下さい。
表の親要素さえ特定できれば、後の構成は規則性のあるものだろうと想像できますので、その構成さえ理解できればさほど難しくはないと思われます。
Seleniumは存じませんので、.AsTable() メソッドでTable ではないものをまとめて解釈してくれるのかどうかは知りませんけれど、少なくとも1行分に該当する要素がわかれば、後はループ等で順に処理すれば良いのではないでしょうか?
ざっと見たところ
<div class="eventRow">
という要素が、基本的な行の単位として構成されているようです。
とは言え、日付等のタイトルの1行分を含んでいる場合と、含んでいない場合(=同じ日の2行目以降)とがあるようですけれど・・
今回も迅速なる対応を有り難うございました(HTMLの中身まで検証頂き感謝です)。
以下で、fujillinさんのご指摘に対する小生のコメントを → 以降に書いてみました。
多分、構成が変わったのではないでしょうか?
(見た目にさほど違いはなくても、HTMLの構成が変わっているのでは?)
→ その通りだと思います。
見た目で変わったのはチーム名にチームのロゴ画像が追加された事です。
また、"tournamentTable" が無くなってしまった事から HTMLが変わった事は間違いありませんが、以前のHTMLのデータが無いので詳細は不明です。
このサイトでは、以前からHTML内にオッズ等のデータは直接には記述されていませんでした。
小生にとってはこれが問題解決を難しくしている一因です。
「表」というのは、「Football / Albania / Superliga」が一番上の行になっている表のことでしょうか?
→ その通りです。舌っ足らずで済みません。
(例えば、「data-v-238d5b4d」のようなdata名は、日付や節等に応じて変わりそうな感じがします)
→ これが変数のようなので挫折の原因でしたが、先程、他のページでも同じdata名が使われている事を確認できたので定数と考えて良さそうです。
<div class="eventRow">
という要素が、基本的な行の単位として構成されているようです。
とは言え、日付等のタイトルの1行分を含んでいる場合と、含んでいない場合(=同じ日の2行目以降)とがあるようですけれど・・
→ そのようですね。
fujillinさんには貴重な時間を割いて教えて頂いて恐縮なのですが、これ以上は手に余りそうなので HTMLでの処理は断念して コピペ方式で模索してみようと思います。
この度も丁重なご指導、誠に有り難うございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) Excelのマクロコードについて教えてください。 1 2022/03/27 13:25
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- その他(プログラミング・Web制作) Windowsのマクロプログラムで、こんなことできますか? 3 2022/06/28 14:30
- その他(プログラミング・Web制作) パイソン。スクレイピング。Chromeドライバーの使い方を教えてください。 1 2023/06/14 21:55
- Visual Basic(VBA) 別シートから年齢別の件数をカウントしたい 6 2023/01/23 12:00
- その他(Microsoft Office) マクロVBAについて 1 2022/09/06 18:12
- Visual Basic(VBA) VBA 参照先で選んだファイルをコピーし、出力先に別名で保存したい 8 2022/05/13 20:37
- Visual Basic(VBA) Excel VBA キーワードから列を取得して、さらに空欄行を非表示にする 3 2022/10/21 22:49
- Visual Basic(VBA) 集めたシートのシート名を変更したい。 下記のコードでサブフォルダにあるファイルのSheet3を集めて 6 2022/08/23 10:38
- Excel(エクセル) 【困っています】VBA 追加処理の記述を教えてください。 1 2022/08/25 22:54
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
サンプルサイズが異なるデータ...
-
JRAの即パットにゆうちょ銀行で...
-
りそな銀行デビットカードで、...
-
東京競馬場で馬券の購入
-
競馬の祭典 凱旋門賞❗ 日本の馬...
-
出銭はゲンが悪いといいますが
-
【競馬場】競馬場の馬券購入時...
-
自分の性格(金銭感覚??)
-
人に頼まれた馬券をインターネ...
-
調教師の受験
-
粗品さんがやっている競馬払い...
-
競馬と統計学?
-
至急!!競馬の代理購入につい...
-
麻雀や競馬でほぼ負けない人間...
-
競馬のビンゴで当たった人って ...
-
ありきたりな質問ですが、もし...
-
競馬で1000万当てるのと、宝く...
-
東風?なんとよむんでしょうか?
-
競馬予想業者はなぜ逮捕されない?
-
高校生の競馬についてです。そ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
サンプルサイズが異なるデータ...
-
【競馬場】競馬場の馬券購入時...
-
出銭はゲンが悪いといいますが
-
競馬に関しまして。私よく知ら...
-
競馬歴3か月で50万負けました。...
-
人に頼まれた馬券をインターネ...
-
高校生の競馬についてです。そ...
-
学生バイトについての質問です...
-
スポーツとしての競馬が好きなのに
-
オイチョカブの数字、「4」の...
-
即PATを家族にばれないように。
-
海外から馬券購入
-
馬主資格を取るには?
-
4頭でワイド馬券を買う場合、組...
-
粗品さんがやっている競馬払い...
-
日本中央競馬会の職員について
-
競馬大好き女子大生です。 卒論...
-
競馬攻略本について
-
馬券での激しい後悔、悔しい思...
-
注文って?
おすすめ情報