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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

Q&A

解決済

1回答

193閲覧

Python+Selenium で JavaScriptで記述されたボタンをクリックできない

fuzy

総合スコア1

スクレイピング

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

0グッド

1クリップ

投稿2024/03/19 14:05

実現したいこと

Python+Selenium で JavaScriptで記述されたボタンをクリックできない。

あるフィットネスサイトをSeleniumで自動予約しようとしています。
レッスンの座席を指定するところまで遷移できましたが、座席がJavaScriptで記述されており、クリックできない状態となり、行き詰っております。

座席は、Excelの表形式の形で表示されており、1~50まで座が表示されています。
空きの席の有無判定し、空き席をクリックして予約したいのですが、JavaScriptで記述されており、HTMLのタグを利用したスクレイピングでは歯が立ちません。

以下が座席のデータで、座席番号(1~50)、画面上の座標軸(X、Y)、空きの有無(reserved/enable)が確認できます。
しかしながら、HTMLではないため、Seleniumでは操作できません。

JavaScript

1RsvApp.mapData = {"x":"9","y":"6","label":{"format":"{$NUM}","x":"number","y":"number"},"data":[{"num":1,"y":0,"x":0,"status":"reserved"},{"num":2,"y":0,"x":1,"status":"reserved"},{"num":3,"y":0,"x":2,"status":"reserved"},{"num":4,"y":0,"x":3,"status":"reserved"},{"num":5,"y":0,"x":4,"status":"reserved"},{"num":6,"y":0,"x":5,"status":"reserved"},{"num":7,"y":0,"x":6,"status":"reserved"},{"num":8,"y":0,"x":7,"status":"reserved"},{"num":-1,"y":0,"x":8,"status":"hidden"},{"num":9,"y":1,"x":0,"status":"reserved"},{"num":10,"y":1,"x":1,"status":"reserved"}

どなたか対処方法のお知恵を拝借できないでしょうか。
HTMLを抜粋して添付致します。

宜しくお願い致します。

発生している問題・分からないこと

Python+Selenium で JavaScriptで記述されたボタンをクリックできない

該当のソースコード

HTML

1<div class="contentsWrap"> 2<h1 id="pagetitle">レッスン予約サービス予約</h1> 3 4<!-- content --> 5<div id="sectionMain"> 6 7<link rel="stylesheet" type="text/css" href="/i/rsv-pos/assets/css/rsv.css"> 8<script src="/i/rsv-pos/assets/js/jquery-3.5.1.min.js"></script> 9<script src="/i/rsv-pos/assets/js/libs.js"></script> 10<script src="/i/rsv-pos/app/main.js"></script> 11 12 <pre id="hm-result"></pre> 13 14 <div id="appWrap"> 15 <div id="appContainer"> 16 17 </div> 18 19</div><!-- /appWrap --> 20 21<form action="" method="post"> 22<input type="hidden" name="pos" role="waku_data"/> 23<input type="submit" class="btn" name="btn-next" formaction="./confirm" value="次へ"/> 24<button type="button" class="btnback" onClick="history.go(-1)">戻る</button></li> 25 26</form> 27 28<div class="pad10 txtC fontMS"> 29※(PC)ドラックで移動、マウスホイールで拡大・縮小<br> 30※(スマホ)スワイプで移動、ピンチで拡大・縮小 31</div> 32 33<script> 34 35 let defaultMapData = { 36 "x": 10, 37 "y": 10, 38 "label": { 39 "format": "-", 40 "x": "number", 41 "y": "alphabet" 42 }, 43 "data": [] 44 }; 45 let defaultDrawData = []; 46 47 const RsvApp = ReserveApplication.getInstance(); 48 RsvApp.pixiConfig.assetsPath = '/i/rsv-pos/assets/'; 49 RsvApp.mapData = {"x":"9","y":"6","label":{"format":"{$NUM}","x":"number","y":"number"},"data":[{"num":1,"y":0,"x":0,"status":"reserved"},{"num":2,"y":0,"x":1,"status":"reserved"},{"num":3,"y":0,"x":2,"status":"reserved"},{"num":4,"y":0,"x":3,"status":"reserved"},{"num":5,"y":0,"x":4,"status":"reserved"},{"num":6,"y":0,"x":5,"status":"reserved"},{"num":7,"y":0,"x":6,"status":"reserved"},{"num":8,"y":0,"x":7,"status":"reserved"},{"num":-1,"y":0,"x":8,"status":"hidden"},{"num":9,"y":1,"x":0,"status":"reserved"},{"num":10,"y":1,"x":1,"status":"reserved"},{"num":11,"y":1,"x":2,"status":"reserved"},{"num":12,"y":1,"x":3,"status":"reserved"},{"num":13,"y":1,"x":4,"status":"reserved"},{"num":14,"y":1,"x":5,"status":"reserved"},{"num":15,"y":1,"x":6,"status":"enable"},{"num":16,"y":1,"x":7,"status":"reserved"},{"num":17,"y":1,"x":8,"status":"reserved"},{"num":18,"y":2,"x":0,"status":"reserved"},{"num":19,"y":2,"x":1,"status":"enable"},{"num":20,"y":2,"x":2,"status":"reserved"},{"num":21,"y":2,"x":3,"status":"reserved"},{"num":22,"y":2,"x":4,"status":"reserved"},{"num":23,"y":2,"x":5,"status":"enable"},{"num":24,"y":2,"x":6,"status":"reserved"},{"num":25,"y":2,"x":7,"status":"reserved"},{"num":-1,"y":2,"x":8,"status":"hidden"},{"num":26,"y":3,"x":0,"status":"reserved"},{"num":27,"y":3,"x":1,"status":"reserved"},{"num":28,"y":3,"x":2,"status":"reserved"},{"num":29,"y":3,"x":3,"status":"reserved"},{"num":30,"y":3,"x":4,"status":"reserved"},{"num":31,"y":3,"x":5,"status":"reserved"},{"num":32,"y":3,"x":6,"status":"reserved"},{"num":33,"y":3,"x":7,"status":"reserved"},{"num":34,"y":3,"x":8,"status":"reserved"},{"num":35,"y":4,"x":0,"status":"reserved"},{"num":36,"y":4,"x":1,"status":"reserved"},{"num":37,"y":4,"x":2,"status":"reserved"},{"num":38,"y":4,"x":3,"status":"enable"},{"num":39,"y":4,"x":4,"status":"reserved"},{"num":40,"y":4,"x":5,"status":"reserved"},{"num":41,"y":4,"x":6,"status":"reserved"},{"num":42,"y":4,"x":7,"status":"reserved"},{"num":-1,"y":4,"x":8,"status":"hidden"},{"num":43,"y":5,"x":0,"status":"reserved"},{"num":44,"y":5,"x":1,"status":"reserved"},{"num":45,"y":5,"x":2,"status":"reserved"},{"num":46,"y":5,"x":3,"status":"reserved"},{"num":47,"y":5,"x":4,"status":"reserved"},{"num":48,"y":5,"x":5,"status":"reserved"},{"num":49,"y":5,"x":6,"status":"reserved"},{"num":50,"y":5,"x":7,"status":"reserved"},{"num":-1,"y":5,"x":8,"status":"hidden"}]}; 50 RsvApp.drawData = [ 51 { 52 "position": { 53 "x": 159, 54 "y": 427 55 }, 56 "angle": 0, 57 "lineStyle": { 58 "width": "1", 59 "color": "0xFBAF5A", 60 "alpha": 1 61 }, 62 "label": { 63 "text": "出入口", 64 "fontStyle": { 65 "fontFamily": [ 66 "Helvetica Neue", 67 "Arial", 68 "Hiragino Kaku Gothic ProN", 69 "Hiragino Sans", 70 "Meiryo", 71 "sans-serif" 72 ], 73 "fontSize": "30px", 74 "fontScale": 0.8, 75 "fontWeight": "bold", 76 "fill": "#000000", 77 "stroke": "#FFFFFF", 78 "strokeThickness": 0 79 } 80 }, 81 "fillColor": "0xF7941D", 82 "rect": { 83 "width": 102, 84 "height": 37, 85 "x": -51, 86 "y": -18.5 87 }, 88 "rotation": 0 89 }, 90 { 91 "position": { 92 "x": 324, 93 "y": 65 94 }, 95 "angle": 0, 96 "lineStyle": { 97 "width": "0.5", 98 "color": "0xFBAF5A", 99 "alpha": 1 100 }, 101 "label": { 102 "text": "インストラクター", 103 "fontStyle": { 104 "fontFamily": [ 105 "Helvetica Neue", 106 "Arial", 107 "Hiragino Kaku Gothic ProN", 108 "Hiragino Sans", 109 "Meiryo", 110 "sans-serif" 111 ], 112 "fontSize": "30px", 113 "fontScale": 0.9, 114 "fontWeight": "bold", 115 "fill": "#000000", 116 "stroke": "#FFFFFF", 117 "strokeThickness": 0 118 } 119 }, 120 "fillColor": "0xF7941D", 121 "rect": { 122 "width": 270, 123 "height": 51, 124 "x": -135, 125 "y": -25.5 126 }, 127 "rotation": 0 128 }, 129 { 130 "position": { 131 "x": 335, 132 "y": 484 133 }, 134 "angle": 0, 135 "lineStyle": { 136 "width": "1", 137 "color": "0x000000", 138 "alpha": 1 139 }, 140 "label": { 141 "text": "2.4列目は右に半分ズレた位置になります", 142 "fontStyle": { 143 "fontFamily": [ 144 "Helvetica Neue", 145 "Arial", 146 "Hiragino Kaku Gothic ProN", 147 "Hiragino Sans", 148 "Meiryo", 149 "sans-serif" 150 ], 151 "fontSize": "30px", 152 "fontScale": 1, 153 "fontWeight": "bold", 154 "fill": "#000000", 155 "stroke": "#FFFFFF", 156 "strokeThickness": 0 157 } 158 }, 159 "fillColor": "0xFFF100", 160 "rect": { 161 "width": 364, 162 "height": 29, 163 "x": -182, 164 "y": -14.5 165 }, 166 "rotation": 0 167 } 168]; 169 170 // ウィンドウリサイズ処理 171 $(window).on('resize', function (e) { 172 RsvApp.containerElement.style.width = innerWidth; 173 }); 174 175 // event: アプリケーションの初期化完了だ 176 RsvApp.on('initComplete', function (e) { 177 console.log('application start'); 178 }); 179 180 // event:枠が選択された 181 RsvApp.on('wakuSelect', function (sprite) { 182 if(sprite) { 183 $('input[name=pos]').val(sprite.pos.y+':'+sprite.pos.x); 184 } else { 185 $('[role=waku_data]').val(''); 186 } 187 }); 188 189 RsvApp.init('#appContainer'); 190 191</script> 192 193</div> 194<script> 195$('#wclick').on('click', function () { 196 $(this).addClass('disabled'); 197}); 198</script> 199 200<style> 201 .disabled{ 202 background:#CCCCCC!important; 203 border-color:#CCCCCC!important; 204 color: #F1F1F1; 205 pointer-events: none; 206 } 207</style> 208 209</div><!-- .contentsWrap -->

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

「Selenium JavaScript ボタン クリック」で検索しましたが解決しませんでした。

補足

特になし

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

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

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

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

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

otn

2024/03/20 05:01

状況がよくわかりませんが、JavaScriptで実現されているなら、JavaScriptのコードを読んで、期待する動作と同じ事をするJavaScriptコードをexecute_scriptで実行するのでしょうか。 数年前に似たことをやったことがある気がします。状況を覚えてませんが。
fuzy

2024/03/21 08:43 編集

ご助言、ありがとうございます。 「move_by_offset」で回避しました。
guest

回答1

0

自己解決

ご助言、ありがとうございます。
ご指摘の通り、JavaScriptコードを execute_script で実行するのが王道だと思います。
しかしながら、JavaScriptの処理内容に私の理解が追い付かず、私のスキル不足により困難な案だと感じました。

その為、回避手段として、「move_by_offset」を利用して、X,Yの座標軸指定してクリックすることで解決しました。
Chrome拡張機能 page-ruler を導入することで、座標軸を調べ、指定しています。

actions = ActionChains(driver)
actions.move_by_offset(chrome_x, chrome_y) # 座標 X, Y は、Chrome拡張機能 page-ruler で測定可能。ブラウザの左上からの座標を指定する。
actions.click()
actions.perform()

ご参考まで。

投稿2024/03/21 08:42

fuzy

総合スコア1

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問