概要

PlaywrightのPageから正確な画像ファイルを抽出する

問題

Playwrightでテスト対象のページが生成した画像をファイルとして取得するAPIは2022/12現在存在しない

そのため Pageevaluate を活用して上手く取り出してやる必要がある

解決

第一候補に挙がるのは、Canvas + toDataURL だが、画像をサブドメインのCDNなどに乗せているとOriginの問題が発生する

加えて、jpegの場合はcanvasを通すと完全に同一の画像にはならない

そこで、evaluate で画像をBlobからbase64に変換するコードを実行し、結果のbase64 encoded string を外に取り出して、Python側でdecodeする

実際のコード

Server

echo '<html><head></head><body><img src="https://playwright.dev/img/logos/Browsers.png"></body></html>' > target.html
python3 -m http.server

Playwright

import base64
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    for browser_type in [p.chromium]:
        browser = browser_type.launch()
        page = browser.new_page()
        page.goto('localhost:8000')

	image_locator = page.locator("img[src*='$target_condition']").nth(0)
        image_src = orig_image_locator.get_attribute("src")
        page.goto(image_src)

	image_b64 = page.evaluate("async () => {return await fetch(window.location.href).then( response => response.blob() ).then( blob => new Promise( callback => {let reader = new FileReader(); reader.onload = function(){ callback(this.result) } ; reader.readAsDataURL(blob) }))}")

	with open('extracted.png', 'wb') as f:
		# jpg: .replace("data:image/jpeg;base64,", "").
		image_b64 = image_b64.replace("data:image/png;base64,", "")
		f.write(base64.b64decode(image_b64))