GPS位置情報設定:シミュレーション.setGeolocationOverride


Selenium 4から、Chrome DevToolsプロトコル(CDP)APIを使用してGPS位置を操作できます.

ロケーションサービスの有効化



まず、オペレーティングシステム上でGPS位置のブラウザを設定するために、位置サービスを有効にする必要があります.
MacOSの場合は、システム優先パラメータ>セキュリティとプライバシー>プライバシー>ロケーションサービスで設定できます.

Selenium設定


私の位置をチェックさせてください。



ブラウザで上記のウィンドウがポップアップされないように、クロムネットワークドライバのオプションを設定する必要があります.( コメントリンク )
selenium_func.py
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager


def set_chrome_driver():
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_experimental_option("prefs", {
        "profile.default_content_setting_values.geolocation": 1  # 값이 1이면 허용, 2이면 차단
    })
    driver = webdriver.Chrome(service=Service(ChromeDriverManager(log_level=40).install()), options=chrome_options)
    return driver
なお、上記のオプションは、「秘密モード」(Incognito mode)がオンの場合は使用できません.Secretモードを無効にしてChrome Webドライバを起動する必要があります.( リンク )

場所の設定


GPS位置情報を操作するには、座標情報(緯度/経度)と精度をバイナリに入れ、CDP APIでEmulation.setGeolocationOverrideコマンドを実行する必要があります.
GPS位置に基づく地図位置情報局(https://www.gps-coordinates.net/)では、San Franciscoの座標情報(緯度/経度)と精度をランダムに入力してみる.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import selenium_func


if __name__ == '__main__':
    driver = selenium_func.set_chrome_driver()
    try:
        # Create Geo Location
        coordinates = dict({
            "latitude": 37.774929,  # 위도
            "longitude": -122.419416,  # 경도
            "accuracy": 100  # 정확도
        })

        # Emulate Location
        driver.execute_cdp_cmd("Emulation.setGeolocationOverride", coordinates)

        # Navigate to the Website
        driver.get("https://www.gps-coordinates.net/")
        driver.execute_script("arguments[0].scrollIntoView();", driver.find_element(By.ID, 'map_canvas'))
        location_name = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'iwtitle'))).get_attribute('innerText')
        print(location_name)
    finally:
        driver.quit()
実行結果は、次のように座標値の位置情報が出力されていることを示します.
Cistern at Kansas & Army, Market Street, San Francisco, CA 94102, United States of America
上記の手順は、クロムブラウザでクロム開発者ツール>More Tools>Sensorsを使用して場所をSan Franciscoに設定して検証する手順と同じです.

テスト例


これで、複数の地域のGPS位置情報を設定し、テストに適用することができます.
大韓民国行政区域17ヵ所のGPS位置情報を設置し、https://www.gps-coordinates.net/でテストを行い、この位置情報に行政区ドメイン名が含まれているかどうかを確認する.

領域座標情報を含むファイルの準備


リンクを参照して、地図データを含むshpファイルを読み込んだ後、必要なフォーマットに変換しようとしたが、shpファイルの複雑さのため、ここです。から17個の大韓民国行政区域座標情報(緯度/経度)を含むjsonファイルがダウンロードされた.
しかし、ダウンロードしたjsonファイルの座標情報が領域と一致しないため、リンクを参照してグーグルマップ上で領域を検索し、緯度と経度値を検索し、jsonファイルの再構築を試みた.
geolocation.json
{
  "regions": [
    {
      "properties":{
        "CTPRVN_CD":"41",
        "CTP_ENG_NM":"Gyeonggi-do",
        "CTP_KOR_NM":"경기도"
      },
      "geometry": {
        "coordinates": {
          "latitude": 37.5969947,
          "longitude": 126.5354486
        }
      }
    },
    {
      "properties":{
        "CTPRVN_CD":"11",
        "CTP_ENG_NM":"Seoul",
        "CTP_KOR_NM":"서울특별시"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": {
          "latitude": 37.5650172,
          "longitude": 126.8494645
        }
      }
    },
    (이하 생략)
  ]
}
GeolocationJSON.py : geolocation.jsonファイルから各地域座標情報を含むディックシリーズを構成する(region_dict).訪問したサイトが英語サイトなので、地域名は英語の地域名を使います.
import json


class GeolocationJSON:
    def __init__(self):
        with open('geolocation.json') as jf:
            json_data = json.load(jf)
            regions = json_data["regions"]
            self._region_dict = dict()
            for region in regions:
                region_name = region['properties']['CTP_ENG_NM']  # 영어 지역명
                self._region_dict[region_name] = {
                    "latitude": region['geometry']['coordinates']["latitude"],  # 위도
                    "longitude": region['geometry']['coordinates']["longitude"],  # 경도
                    "accuracy": 100
                }

    @property
    def region_name_list(self):
        return list(self._region_dict.keys())

    def coordinate_dict(self, region_name):
        return self._region_dict[region_name]

テストコード


conftest.py:テスト時に使用するwebdriverを設定します.(selenium func.pyのコードは、上のSelenium設定にあります.)
import pytest
import selenium_func


@pytest.fixture(scope="module")
def driver():
    driver = selenium_func.set_chrome_driver()
    yield driver
    driver.quit()
test_geolocation.py:テストコードを作成します.地域名でパラメータ化し、大韓民国の行政区域17ヵ所をテストした.
from GeolocationJSON import GeolocationJSON
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pytest
region_name_list = GeolocationJSON().region_name_list


@pytest.mark.parametrize('region_name', region_name_list)
def test_region_name(driver, region_name):
    coordinate_dict = GeolocationJSON().coordinate_dict(region_name=region_name)
    driver.execute_cdp_cmd("Emulation.setGeolocationOverride", coordinate_dict)

    url = "https://www.gps-coordinates.net/"
    driver.get(url)
    driver.execute_script("arguments[0].scrollIntoView();", driver.find_element(By.ID, 'map_canvas'))
    location_name = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'iwtitle'))).get_attribute('innerText')
    assert region_name in location_name

実行結果


実行結果,合計17件のイベントのうち,Passed 7件,Failed 10件であった.
(思ったほど多くの行政区ドメイン名がこのサイトの位置情報に含まれていません...行政区の緯度/経度値を間違えたのではないかと思います...)

これは簡単な例です.複数の地域のGPS位置が正しく動作しているかどうかを確認するために使用されます.これにより、GPS位置情報を設定し、サービス画面の結果が予想通りであることを確認できます.)

Reference

  • https://www.lambdatest.com/blog/geolocation-testing-with-selenium-using-examples/