Seleniumは、ブラウザの起動、ページ遷移、クリック操作、フォーム送信、ウィンドウサイズの変更など、Web上の多岐にわたる操作を自動化するための強力なフレームワークです。特にスクレイピングやテスト自動化において重宝されるのは、JavaScriptのレンダリングを含め、実際のブラウザと同じようにページを描画できる点にあります。
PhantomJSはWebKitベースのヘッドレスブラウザであり、GUIを持たないことが最大の特徴です。画面描画のオーバーヘッドがないため、通常のブラウザと比較して高速に動作します。DOM操作やCSSセレクタ、Canvas、SVGなどのWeb標準技術をサポートしており、画面なしでの自動化テストやネットワーク監視、Webページのスクリーンショット取得などに適しています。
基本的な初期化とページ取得
SeleniumからPhantomJSを操作する基本的なコードは以下のようになります。
from selenium import webdriver
headless_browser = webdriver.PhantomJS()
headless_browser.get("https://www.example.com")
page_title = headless_browser.title
print(page_title)
要素の抽出とWindows環境でのパス指定
Windows環境でPhantomJSを利用する場合は、実行ファイルのパスを明示的に指定する必要があります。Linux環境ではパスの指定を省略できることが多いです。XPathを使用して特定の要素を取得し、テキストや属性を抽出する例を示します。
from selenium import webdriver
scraper = webdriver.PhantomJS(executable_path=r'D:\phantomjs\bin\phantomjs.exe')
target_url = 'https://www.example.com'
scraper.get(target_url)
elements = scraper.find_elements_by_xpath('//div[@class="content"]')
for el in elements:
print(el.text)
print(el.get_attribute('class'))
scraper.quit()
GUIブラウザとヘッドレスブラウザの比較
FirefoxなどのGUIブラウザとPhantomJSの操作を比較してみます。GUIブラウザでの操作は以下のようになります。
from selenium import webdriver
gui_driver = webdriver.Firefox()
gui_driver.get("https://www.example.com/login")
gui_driver.find_element_by_id("username").send_keys("test_user")
gui_driver.find_element_by_id("login_btn").click()
gui_driver.quit()
同じ操作をPhantomJSで実行する場合、ウィンドウサイズの設定が必要になることがありますが、基本動作は同じです。処理後にURLを取得し、正しく遷移したかを確認できます。
from selenium import webdriver
headless_driver = webdriver.PhantomJS()
headless_driver.set_window_size(1280, 720)
headless_driver.get("https://www.example.com/login")
headless_driver.find_element_by_id("username").send_keys("test_user")
headless_driver.find_element_by_id("login_btn").click()
print(headless_driver.current_url)
headless_driver.quit()
ユニットテストを用いたURL検証
Pythonの標準ライブラリであるunittestを使用して、PhantomJSによるページ遷移後のURLが期待通りであるかを検証するテストスクリプトを構築できます。
import unittest
from selenium import webdriver
class HeadlessNavigationTest(unittest.TestCase):
def setUp(self):
self.bot = webdriver.PhantomJS()
self.bot.set_window_size(1280, 720)
def test_login_redirect(self):
self.bot.get("https://www.example.com/login")
self.bot.find_element_by_id("username").send_keys("test_user")
self.bot.find_element_by_id("login_btn").click()
self.assertEqual("https://www.example.com/dashboard", self.bot.current_url)
def tearDown(self):
self.bot.quit()
if __name__ == "__main__":
unittest.main()
実行速度の比較検証
PhantomJSの最大の利点の一つは、GUI描画を伴わないためテスト実行が高速である点です。FirefoxとPhantomJSでのテスト実行時間を計測・比較するテストケースです。
import unittest
import time
from selenium import webdriver
class ExecutionSpeedComparison(unittest.TestCase):
def test_firefox_duration(self):
start_time = time.time()
driver = webdriver.Firefox()
driver.get("https://www.example.com")
btn_type = driver.find_element_by_id("main_btn").get_attribute("data-type")
self.assertEqual("submit", btn_type)
driver.quit()
print(f"Firefox: {time.time() - start_time:.3f} sec")
def test_phantomjs_duration(self):
start_time = time.time()
driver = webdriver.PhantomJS()
driver.get("https://www.example.com")
btn_type = driver.find_element_by_id("main_btn").get_attribute("data-type")
self.assertEqual("submit", btn_type)
driver.quit()
print(f"PhantomJS: {time.time() - start_time:.3f} sec")
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(ExecutionSpeedComparison)
unittest.TextTestRunner(verbosity=2).run(suite)
高度な操作:WaitとカスタムUser-Agentの設定
動的に要素が変わるページでは、明示的な待機(Explicit Wait)を導入し、要素が操作可能になるまで待つ必要があります。また、PhantomJSはデフォルトのUser-Agentが特殊なため、通常のブラウザと同じUser-Agentを偽装してアクセスしたいケースがよくあります。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
ACCOUNT_ID = 'user@example.com'
SECRET = 'secure_password'
custom_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36'
pjs_executable = '/usr/local/bin/phantomjs'
caps = {
"phantomjs.page.settings.userAgent": custom_user_agent,
'marionette': True
}
bot = webdriver.PhantomJS(executable_path=pjs_executable, desired_capabilities=caps)
wait = WebDriverWait(bot, 10)
bot.get('https://www.example.com/login')
wait.until(EC.presence_of_all_elements_located)
# ログインフォームの表示
bot.find_element_by_id('show_signin').click()
# アカウント入力
id_field_xpath = '//input[@name="email"]'
wait.until(EC.visibility_of_element_located((By.XPATH, id_field_xpath)))
id_field = bot.find_element_by_xpath(id_field_xpath)
id_field.clear()
id_field.send_keys(ACCOUNT_ID)
# パスワード入力
pwd_field_xpath = '//input[@name="password"]'
wait.until(EC.visibility_of_element_located((By.XPATH, pwd_field_xpath)))
pwd_field = bot.find_element_by_xpath(pwd_field_xpath)
pwd_field.clear()
pwd_field.send_keys(SECRET)
# 送信
bot.find_element_by_xpath('//button[@type="submit"]').click()
# ログイン後の検証
bot.get('https://www.example.com/dashboard')
wait.until(EC.presence_of_all_elements_located)
displayed_user = bot.find_element_by_xpath('//span[@class="user-email"]').get_attribute("textContent")
assert ACCOUNT_ID == displayed_user
bot.quit()