Seleniumでヘッドレススクレイピングを組んでいると、ElementClickInterceptedException(element click intercepted)で処理が止まった経験がある人は多いはずです。ブラウザ表示ありでは動くのに、ヘッドレスや自動化サーバー上でだけ再現するケースも多く、原因の切り分けに時間を取られがちです。本記事では発生原因を整理したうえで、待機・スクロールといった基本対処から、それでも直らない場合の強制クリック回避策まで、実装コード付きで解説します。
「element click intercepted」エラーが起きる原因
このエラーは「クリックしようとした座標に、目的の要素とは別の要素が重なっていてクリックが届かない」ときに発生します。要素が存在しないわけではなく、DOM上にはあるのに物理的にクリックできない状態です。よくある原因は次の通りです。
原因 | 具体例 | ヘッドレスで起きやすいか |
|---|---|---|
要素がビューポート外 | ページ下部のボタンをスクロールせずクリック | ◎(画面サイズ未設定だと特に起きやすい) |
オーバーレイ要素の重なり | Cookie同意バナー、広告モーダル、ローディングスピナー | ◎ |
アニメーション中の要素 | フェードイン中のメニューをクリック | ○ |
固定ヘッダー・フッター | position: fixedのナビゲーションが要素に被る | ◎ |
要素サイズが0または非表示 | display: noneが解除される前にクリック | ○ |
ヘッドレスモードでは既定のウィンドウサイズが小さい(800×600など)ことが多く、通常表示なら見えている要素が画面外に押し出されて発生するケースが特に多く見られます。
基本対処:待機とスクロールで大半は解決する
WebDriverWaitで要素がクリック可能になるまで待つ
最初に確認すべきは「要素が存在するか」ではなく「クリック可能な状態か」です。presence_of_element_locatedではなくelement_to_be_clickableを使うだけで解決するケースが少なくありません。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.submit")))
btn.click()
scrollIntoViewで画面内に入れてからクリックする
ヘッドレス特有の「ウィンドウサイズが小さくて画面外にある」問題は、クリック前に明示的にスクロールすることで解消できます。
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'center'});", btn
)
btn.click()
加えて、ヘッドレス起動時に--window-size=1920,1080を指定して十分な描画領域を確保しておくと、この種のエラー自体の発生頻度がかなり下がります。動的サイトのレンダリング待ちや要素の出現タイミングの見極めについては、スクレイピング実践テク|動的・ログイン攻略【26年8月】でも詳しく扱っています。
それでも解決しない場合の強制操作テクニック3選
待機・スクロールを尽くしても直らない場合は、オーバーレイそのものを避けてクリックを成立させる方法に切り替えます。ただし多用は本来の挙動を無視した力技のため、後述の注意点も必ず確認してください。
1. JavaScriptで直接click()を実行する
Seleniumのクリック処理は要素の可視性・座標判定を厳密に行いますが、JavaScriptのclick()はブラウザ標準のイベント発火だけを行うため、重なり判定を回避できます。
driver.execute_script("arguments[0].click();", btn)
2. ActionChainsでオフセット指定してクリックする
要素の一部だけが隠れている場合は、隠れていない座標を狙ってクリックすることで解決できます。
from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(btn).move_by_offset(2, 2).click().perform()
3. キーボード操作で代替する
フォーム送信ボタンなどは、クリックの代わりにフォーカスを当ててEnterキーを送る方法でも代替できます。
from selenium.webdriver.common.keys import Keys
btn.send_keys(Keys.ENTER)
優先順位としては「1. JavaScript click()」が最も汎用的で成功率が高く、まず試す価値があります。
Cookie同意バナー・広告オーバーレイが原因のケース
バナー要素を検出して先に消してしまう
クリックのたびに同じバナーが邪魔をする場合、都度回避するより先に要素自体を削除・非表示化したほうが安定します。
from selenium.common.exceptions import NoSuchElementException
try:
banner = driver.find_element(By.CSS_SELECTOR, "#cookie-consent")
driver.execute_script("arguments[0].remove();", banner)
except NoSuchElementException:
pass
iframe内にバナーがある場合の注意
同意管理プラットフォーム(CMP)系のバナーはiframe内に描画されていることが多く、この場合はdriver.switch_to.frame()でiframeに入ってから要素を取得しないとNoSuchElementExceptionになります。バナーの構造はサイトごとに大きく異なるため、対象サイトが変わるたびに個別調査が必要になるのが実務上の負担どころです。
この記事に関連するアイテム
実際に使うものを選ぶ際の参考にどうぞ。
※ 本サイトはAmazonアソシエイト・プログラムの参加者です。紹介リンクを経由してご購入いただいた場合、手数料を受け取ることがあります。
強制クリックを使う際の規約・法令面の注意と大量取得設計
技術的に回避できても許可されているとは限らない
「element click intercepted」を回避するテクニックは、あくまでUI操作を成立させる手段であり、対象サイトの利用規約でクローリング・自動操作が禁止されていないかは別問題として必ず確認が必要です。特にログイン必須サイトや会員限定コンテンツは、規約でスクレイピング・自動アクセスを明示的に禁止していることが多く、著作権法・不正アクセス禁止法・利用規約違反によるアカウント停止のリスクを伴います。取得前に必ずrobots.txtと利用規約を確認し、個人情報を含むデータの取得・保存は個人情報保護法の観点でも設計段階からチェックすべきです。
大量ページ処理でエラーを再発させない設計
1〜2ページなら力技でも回せますが、数百〜数千ページを回すバッチ処理では、強制クリックだけに頼ると別要因(レイアウト崩れ・レート制限・一時的な広告表示)で再発します。実務では次のような多層防御で安定化させます。
- クリック処理を関数化し、待機→スクロール→JS click→例外時リトライの順に段階的にフォールバックさせる
- リクエスト間隔を空け、対象サイトのサーバー負荷・自社アクセス元のブロックリスク(レート制限・IP規制)を避ける
- 失敗ページのURLと例外内容をログに残し、後から差分だけ再実行できる設計にする
- 可能であればブラウザ操作を介さず、ページが内部的に呼んでいるAPIを直接叩く方式に切り替える(速度・安定性ともに大幅改善)
この種の「例外処理の設計」「APIの見つけ方」「大量取得時の負荷設計」は、サイトごとに固有の癖があり自動化するほど工数がかさむ領域です。より広い実装パターンはスクレイピング実装テクニック【2026年8月最新】にまとめています。
「element click intercepted」は待機・スクロールで解決することが多い一方、Cookie同意バナーや広告オーバーレイが原因の場合はJavaScriptによる強制clickやiframe対応が必要になります。ただし強制操作は規約違反リスクを高める力技でもあるため、大量取得を前提とした業務利用では、規約確認・エラーハンドリング・レート制御まで含めた設計が欠かせません。自社で構築・保守するには相応の工数がかかるため、業務自動化・スクレイピングの導入をご検討の方はnashiまでお問い合わせください。https://nashi-portfolio.netlify.app