AD

2024-12-18

Selenium Chrome WebDriver 進行定位模擬

直接上範例 code:
from selenium import webdriver
import time

# 設定位置的經緯度,以大慶夜市為例
latitude = 24.122629
longitude = 120.655638
accuracy = 10

driver = webdriver.Chrome()

# 用 CDP command 設定座標經緯度
driver.execute_cdp_cmd(
    "Emulation.setGeolocationOverride",
    {
        "latitude": latitude,
        "longitude": longitude,
        "accuracy": accuracy
    }
)

# 打開頁面試試看定位,這裡以 OpenStreetMap 為例
driver.get("https://www.openstreetmap.org/")
driver.find_element("css selector", "span.geolocate").click()

# 給你看個10秒
time.sleep(10)

driver.quit()
Emulation.setGeolocationOverride 中的 latitude、longitude、accuracy 對於定位來說都是「必要」參數,雖然官方文件寫 optional,但也特別說缺少任一個,定位就不會作用XD

latitude、longitude 分別是緯度和經度,沒什麼問題。比較需要解釋的是 accuracy 定位精確度,通常帶1或以上即可。accuracy 的單位是公尺,「越小越準確」。但最好不要為0,0是不準確時回傳的(有些網站可以接受,也有些不接受)。

因為定位通常由系統回傳,我找到了Android 取得 accuracy 的文件,解釋了定位精確度。簡單來說,從經緯度的點為中心,畫一個半徑等於此精準度的圓,實際位置有 68% 的機率落在該圓內。(iOS 似乎不是這樣定義,不過總體來說也是越小越精確。)

直接以 OpenStreetMap 為例,當 accuracy 是10的時候,我還知道我在大慶夜市的哪個攤位:


當 accuracy 是100,定位超級飄,在這個圈圈裡都可能是實際定位,我可能根本不在大慶夜市裡了:

同場加映,accuracy 是 0,OSM 可以定位:

沒有 accuracy,提示:Geolocation error: position unavailable.


另外補充:
  • 模擬定位在 headless (無頭)模式也可以正確定位,之前看到一些資訊說不行,那很可能是其他問題。
  • web driver 如果禁用定位,例如 options 時禁用:
    options.add_experimental_option(
        "prefs", {"profile.default_content_setting_values.geolocation": 2}
    )
    模擬定位就不能使用。
  • 可以先用 CDP command 加上權限:
    driver.execute_cdp_cmd(
        "Browser.grantPermissions",
        {
        "permissions": ["geolocation"],
        } )
    再設定定位。
  • Google Maps 也可以使用這樣來定位。有些資訊說 Google Maps 以 IP 定位,但實際上是剛載入時抓 IP 位置的國家(OSM也會這樣),而當要精確定位目前位置時,會使用裝置位置,也就是 Emulation.setGeolocationOverride 模擬的座標。
-

目前 Chrome 的許多開發者工具都可以透過 CDP(Chrome DevTools Protocol) 指令來完成。具體有哪些功能可以看看官方文件:https://chromedevtools.github.io/devtools-protocol/


2024-11-28

Postman (newman) 到 Github actions 上的一些小記錄

前陣子遇到一個需求,團隊的 API 測試放在 postman 上,所以想要試試讓 Postman 放在 Github Actions 上面執行。當時花蠻多時間的,紀錄一些過程。
 
1. 在 Postman CLI 和 Newman 做選擇
 
Postman CLI 是官方提供的 CLI 套件,而 Newman 是社群維護的。
一開始我先用了 Postman CLI。
畢竟是官方提供,整合做得很好。有些 API 測試時需要上傳的檔案,有在 postman 上傳過並儲存在 postman cloud 的話,都可以直接使用。而測試結果直接顯示在 Postman 的 Runs 裡面——
沒想到這竟然是個缺點,它的 reporter 不能自訂,唯一的 report 就是要去剛剛提到的 Runs 裡面看,不然就是直接來自執行時的 CLI ⋯⋯(來源參考 https://community.postman.com/t/postman-cli-reporting/66763)
 
所以就因為 Newman 可以自訂 reporter,直接選了 Newman XDDDD
 
2. 上傳檔案的測試
 
用了 newman 也不是就一帆風順。
比方上傳檔案的話有點麻煩,要匯出 collection 之後填上檔案路徑。
這比起用 Postman CLI 麻煩多了。原先在 postman 改完 collection 裡的任何部分之後執行就能生效。但為了讓 Newman 上傳檔案,用匯出的 collection 就沒辦法了QQ
 
3. 執行失敗的 log
 
當時還有一點痛苦的,就是失敗時沒有 response 的 log ⋯⋯Postman CLI 也一樣。
可以做到的方法大致上是在每一個 API 的 post-script 加上紀錄:
pm.test("Response status code is 200", function () {
    if (pm.response.code !== 200) {
        throw new Error(`Response Code: ${pm.response.code} | Response Body: ${pm.response.text()} | Request Body: ${JSON.stringify(pm.request.body)}`);
    }
    pm.response.to.have.status(200);
});;


總之成功在 Actions 上跑了一段時間,不過後來還是決定換成自己寫的 API 框架了。謹此紀念沒跑多久的 Postman 上 Github Actions 經歷XDD

2024-11-25

Selenium 4.6 之後你真的不用下載 webdriver 或使用 WebDriverManager

如題。

在 Selenium 4.6 之後,已經不用另外下載 webdriver,不用帶路徑,不用使用 WebDriverManager 解決下載和帶路徑的問題。

你只需要:

from selenium import webdriver
driver = webdriver.Chrome()
這樣就可以跑了!預設是目前的 stable 版本。

-

如果你需要特定版本的 chrome,可以用Options指定,selenium manager 會自動下載你指定的版本:

options = webdriver.ChromeOptions()
options.browser_version = '120'
driver = webdriver.Chrome(options=options)

除了特定版本號,也可以帶標籤如stable(目前 CfT 版本)、beta(下一個版本穩定)、dev(目前正在開發版本)、canary(為開發人員每晚建置)、esr(擴充支援版本,僅用於 Firefox)。

2024-11-19

Selenium + ChromeDriver - 開啟 DevTools 的行動裝置模式

在 Google Chrome 瀏覽器的 F12 開發工具中,有個很方便的行動裝置模式,可以模擬網站在行動裝置上的顯示和行為。在測試為手機、平板設計的網站時非常好用!
 
在自動化的時候也可以用 add_experimental_option 來設定 webdriver 開啟行動裝置模式,上個最小 Python 範例:

from selenium import webdriver

mobile_emulation = { "deviceName": "iPhone 12 Pro" }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(options=options)

deviceName 具體有哪些 device,可以看一下自己的 Chrome 有哪些內建的裝置可以使用:
點擊上面選單的 Edit,還有更多的裝置,也可以新增自己設定:

至於在 code 裡可以用類似下面的方式來設定自己需要的裝置設定:

from selenium import webdriver

mobile_emulation = {
    "deviceMetrics": { "width": 360, "height": 640, "pixelRatio": 3.0 },
    "userAgent": "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
    "clientHints": {"platform": "Android", "mobile": True} 
}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome("/driver/path", options=options)

2024-11-14

Appium iOS - 你確定 build 了 simulator 可以執行的 app,但還是一直噴錯怎辦?要不要用一下 bundleId?

事情是這樣的,我和開發拿到了可以給 simulator 執行的 .app 檔案。
直接拖曳 app 丟到 simulator 裡它可以順順打開、可以妥妥操作。

但是當我用 Appium 以這個 capability 開 app 就出4了:
  "appium:deviceName": "iPhone 15 Pro",
  "appium:automationName": "XCUITest",
  "platformName": "iOS",
  "appium:platformVersion": "17.5",
  "appium:app": "/Users/username/Desktop/folder/Demo.app" 
}

會遇到錯誤: Failed to create session. An unknown server-side error occurred while processing the command. Original error: The com.testdomain.test-demo-ios.dev application does not support the x86_64 Simulator architecture: Non-fat file: /Users/username/Desktop/folder/Demo.app/Demo is architecture: arm64 Please rebuild your application to support the x86_64 platform. 

為什麼?為什麼???直接裝也可跑啊?人家真的就有 support x86_64 啊。
我問天——我問天——甘會當莫創治—— 

然後啊,在我跟開發確認了幾次,很怕被揍的時候,我才想到我先在 simulator 安裝好就可以用 bundleId 開啟嘛:
  "appium:deviceName": "iPhone 15 Pro",
  "appium:automationName": "XCUITest", 
  "platformName": "iOS",
  "appium:platformVersion": "17.5", 
  "appium:bundleId": "com.testdomain.test-demo-ios.dev"
}

太好了,太好了!
流程上不同的大概只有要先指令裝 app,需要的話加個 reset capability。

如果文章有幫助到你可以在 LikeCoin 上幫我拍手喔