本題に入る前に先にやりたいことを整理しておくと、ブログを投稿した後に



任意の記事ページを開き、



次の記事へのリンクを押して、ブログ内の全記事を巡回するという事を自動化したかった。

巡回したい理由は、アクセスが少ない時間帯に記事投稿後に巡回することで、全記事のHTMLキャッシュを生成して、その後のアクセスの負荷を減らしておきたかった。

【SEO対策】最終産物のHTMLのキャッシュで高速化


この対応はSelenium + php-webdriverを組み合わせれば簡単なように見えるけれども、一つ問題があった。

Seleniumとphp-webdriverでUIテストの自動化


上記のサイトでは、CSSのcontent-visibility:auto;を利用して、部分的に遅延実行していたため、php-webdriverが次の記事へのリンクを発見することができないという問題が発生した。

【SEO対策】content-visibility:auto;でコンテンツの遅延読み込み


だったら、php-webdriverで

// 事前に$driverを用意するコードを書いておく

$ele = $driver->findElement(WebDriverBy::partialLinkText("次の記事へ"));
$ele->getLocationOnScreenOnceScrolledIntoView();
$ele->click();

※$driver周りのコードはJenkins + ヘッドレスChromeでテスト自動化の省力化の記事をご覧ください。

のようにして、該当の箇所までスクロールしてからリンクをクリックすれば良いのでは?となるけれども、何故かこの対応はエラーになった。


原因を調べてみたら、ページの表示速度の高速化と遅延読み込みの影響で該当の箇所までスクロールしても、クリックしたいリンクが表示されないという問題が勃発した。

SOY CMSで外部CSSファイルを自動でインライン化する


そこで、

// 事前に$driverを用意するコードを書いておく

$ele = $driver->findElement(WebDriverBy::partialLinkText("次の記事へ"));
$ele->getLocationOnScreenOnceScrolledIntoView();

// 一度上に戻ってから、再度該当箇所にスクロールする
$locY = $ele->getLocation()->getY();  //該当箇所のY座標を取得しておく
foreach(range(0, $locY, 10) as $y){
	$driver->executeScript("window.scrollTo(0, " . $y . ");");
}
$ele->getLocationOnScreenOnceScrolledIntoView();

$ele->click();

上記のコードのように該当箇所にスクロールした後、ページの一番上に戻り、徐々に該当箇所にスクロールしながら、再び該当箇所にスクロールという処理を追加したら、無事に次の記事へのリンクをクリックする事が出来るようになった。


追記

今回の対応をする前に、Google AnalyticsでSeleniumを動かしているサーバのIPアドレスを除外しておくと良い。

内部トラフィックの除外 - アナリティクス ヘルプ


関連記事

php-webdriverでelement click interceptedのエラーに対して