メインコンテンツへスキップ
【Golang】playwright-goでファイルをアップロードする

【Golang】playwright-goでファイルをアップロードする

·3 分
Programming Golang
かずさプログラマー
著者
かずさプログラマー
業務の作業自動化を行っています。Go、VBA、Pythonを主に使用しています。過去にはC#、VB.Net、JavaScriptも使用していました。
目次

PlaywrightはE2Eテストを行うためのツールですが、ブラウザを自動操作することができるので、作業の自動化にも使用できます。
JavascirptやPythonなどでもPlaywrightを使用できますが、playwright-goがあるので、GolangでもPlaywrightを使用できます。

playwright-community/playwright-go

Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API.

Go
2277
163

ファイルをアップロードする自動化を行うときに、input要素に対してはSetInputFilesが使用できるのですが、 input以外の要素だとSetInputFilesは動作しないため、別の方法でファイルをアップロードする必要があります。

テストアップロード環境の準備
#

ファイルをアップロードする環境をhtml、javascript、golangを使用して用意します。
下記のindex.html、main.js、main.goを同じパスに配置し、go run main.goでサーバーを起動します。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ファイルアップロード</title>
    <style>
        #drop-area {
            width: 300px;
            height: 200px;
            border: 2px dashed #ccc;
            text-align: center;
            padding: 20px;
            margin: 50px auto;
        }
    </style>
</head>
<body>

<div id="drop-area" ondragover="allowDrop(event)" ondrop="handleDrop(event)">
    ファイルをここにドロップ
</div>

<script src="main.js"></script>

</body>
</html>

main.js

function allowDrop(event) {
  event.preventDefault();
}

function handleDrop(event) {
  event.preventDefault();

  var files = event.dataTransfer.files;

  if (files.length > 0) {
    var file = files[0];
    uploadFile(file);
  }
}

function uploadFile(file) {
  var formData = new FormData();
  formData.append('file', file);

  fetch('/upload', {
    method: 'POST',
    body: formData,
  })
    .then((response) => response.json())
    .then((data) => {
      console.log('File uploaded successfully:', data);
    })
    .catch((error) => {
      console.error('Error uploading file:', error);
    });
}

main.go

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	http.HandleFunc("/upload", uploadHandler)
	http.Handle("/", http.FileServer(http.Dir(".")))

	port := 8080
	fmt.Printf("Server is running on http://localhost:%d\n", port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	if err != nil {
		fmt.Println("Error starting server:", err)
	}
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(1000000) // 1MB制限

	file, handler, err := r.FormFile("file")
	if err != nil {
		fmt.Println("Error retrieving the file:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer file.Close()

	fmt.Printf("Received file: %+v\n", handler.Filename)

	f, err := os.Create("./" + handler.Filename)
	if err != nil {
		fmt.Println("Error creating file:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer f.Close()

	io.Copy(f, file)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"message": "File uploaded successfully"}`))
}

サーバーを起動してhttp://localhost:8080/にアクセスすると、ブラウザに「ファイルをここにドロップ」が表示されます。

「ファイルをここにドロップ」と表示されているエリアに1MB以内のファイルをドラッグ&ドロップすると、サーバーにファイルがアップロードされます。

playwright-goでファイルをアップロード
#

先ほどのindex.htmlだと、div要素のid="drop-area"にファイルをドラッグ&ドロップするとファイルをアップロードできますが、input要素ではないのでplaywright-goのSetInputFilesだと動作しません。

<div id="drop-area" ondragover="allowDrop(event)" ondrop="handleDrop(event)">
    ファイルをここにドロップ
</div>

下記のコードではChromeを使用して、SetInputFiles以外の方法でtest.txtファイルをアップロードします。

package main

import (
	"encoding/base64"
	"fmt"
	"os"

	"github.com/playwright-community/playwright-go"
)

func main() {
	runOption := &playwright.RunOptions{
		SkipInstallBrowsers: true,
	}

	if err := playwright.Install(runOption); err != nil {
		panic(err)
	}

	pw, err := playwright.Run()
	if err != nil {
		panic(err)
	}
	defer pw.Stop()

	contextOption := playwright.BrowserTypeLaunchPersistentContextOptions{
		Channel:    playwright.String("chrome"),
		Headless:   playwright.Bool(false),
		Timeout:    playwright.Float(0),
		NoViewport: playwright.Bool(true),
	}

	// ユーザーディレクトリは絶対パスで指定する必要があります
	userDataDir := `C:\userDataDir`
	browser, err := pw.Chromium.LaunchPersistentContext(userDataDir, contextOption)
	if err != nil {
		panic(err)
	}
	defer browser.Close()

	page := browser.Pages()[0]
	defer page.Close()

	page.Goto("http://localhost:8080")

	bytes, err := os.ReadFile("test.txt")
	if err != nil {
		panic(err)
	}
	fileBase64 := base64.StdEncoding.EncodeToString(bytes)
	js := `
 (data) => {
            const dt = new DataTransfer();
            // Convert the binary string to a hexadecimal string
            const hexString = Uint8Array.from(atob(data), c => c.charCodeAt(0));
            const file = new File([hexString], 'test.txt', { type: 'text/plain' });
            dt.items.add(file);
            return dt;
        }
	`
	handle, err := page.EvaluateHandle(js, fileBase64)
	if err != nil {
		panic(err)
	}

	element := page.Locator("#drop-area")
	if err := element.DispatchEvent("drop", map[string]interface{}{"dataTransfer": handle}); err != nil {
		panic(err)
	}

	fmt.Println("ファイルをアップロードしました。")
}

コードを実行するとサーバー側のターミナルで「Received file: test.txt」と表示されて、サーバーを起動しているパスにtest.txtがアップロードされます。

Server is running on http://localhost:8080
Received file: test.txt

参考サイト
#

関連記事

【Golang】png画像に枠線をつける
·1 分
Programming Golang
【Golang】zip内のファイル一覧を展開せずに取得する
··2 分
Programming Golang
【Golang】Collyを使用してWebスクレイピングを行う
··5 分
Programming Golang