ソース
package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/chromedp"
)
func main() {
edgePath, err := findEdgePath()
if err != nil {
log.Fatalf("Edgeが見つかりませんでした: %v", err)
}
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.ExecPath(edgePath),
chromedp.NoFirstRun,
chromedp.NoDefaultBrowserCheck,
chromedp.Flag("disable-extensions", false),
chromedp.Flag("enable-automation", false),
chromedp.Flag("headless", true),
chromedp.WindowSize(1280, 800),
chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"),
)
var buf []byte
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()
startTime := time.Now()
ctx, cancelurl := chromedp.NewContext(allocCtx)
defer cancelurl()
stealthJS := `(() => {
// navigator.webdriver を削除
delete Navigator.prototype.webdriver;
window.chrome = {
runtime: {},
};
// languages を偽装
Object.defineProperty(navigator, 'languages', {
get: () => ['ja-JP', 'ja', "en-US", "en",]
});
// plugins を偽装
const createFakePluginArray = () => {
const fakeMimeType = {
type: "application/pdf",
suffixes: "pdf",
description: "Portable Document Format"
};
function makePlugin(name) {
const plugin = {
name,
filename: "internal-pdf-viewer",
description: "Portable Document Format",
0: fakeMimeType,
length: 1,
item: i => fakeMimeType,
namedItem: name => fakeMimeType
};
fakeMimeType.enabledPlugin = plugin;
return plugin;
}
const plugins = [
makePlugin("PDF Viewer"),
makePlugin("Chrome PDF Viewer"),
makePlugin("Chromium PDF Viewer"),
makePlugin("Microsoft Edge PDF Viewer"),
makePlugin("WebKit built-in PDF")
];
const pluginArray = {
length: plugins.length,
item: i => plugins[i],
namedItem: name => plugins.find(p => p.name === name),
[Symbol.iterator]: function* () {
yield* plugins;
}
};
plugins.forEach((p, i) => pluginArray[i] = p);
Object.setPrototypeOf(pluginArray, PluginArray.prototype);
return pluginArray;
};
// defineProperty を使わず直接代入することで検出回避(definePropertyはウイルスソフトの要監視対象)
navigator.plugins = createFakePluginArray();
// permissions.query の notifications 対応
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = function (parameters) {
if (parameters.name === 'notifications') {
return Promise.resolve({ state: Notification.permission });
}
return originalQuery(parameters);
};
Object.defineProperty(window, 'chrome', {
writable: true,
enumerable: true,
configurable: false,
value: {
app: {},
csi: function () {},
loadTimes: function () {}
}
});
Object.defineProperty(window.chrome, 'webstore', {
get: function () {
throw new TypeError("Cannot read properties of undefined (reading 'constructor')");
}
});
Object.defineProperty(window.chrome, 'runtime', {
get: function () {
throw new TypeError("Cannot read properties of undefined (reading 'constructor')");
}
});
Object.defineProperty(window.chrome, 'connect', {
get: function () {
throw new TypeError("Cannot read properties of undefined (reading 'connect')");
}
});
Object.defineProperty(window.chrome, 'sendMessage', {
get: function () {
throw new TypeError("Cannot read properties of undefined (reading 'sendMessage')");
}
});
})();`
if err := chromedp.Run(ctx,
chromedp.ActionFunc(func(ctx context.Context) error {
_, err := page.AddScriptToEvaluateOnNewDocument(stealthJS).Do(ctx)
return err
}),
); err != nil {
log.Fatal(err)
}
url := "https://bot.sannysoft.com/"
if err := chromedp.Run(ctx,
chromedp.Navigate(url),
chromedp.Sleep(2*time.Second),
chromedp.FullScreenshot(&buf, 90),
chromedp.Sleep(1*time.Second),
); err != nil {
log.Fatal(err)
}
if err := os.WriteFile("screenshot.jpg", buf, 0644); err != nil {
log.Fatal(err)
}
fmt.Println(time.Since(startTime))
}
func findEdgePath() (string, error) {
candidates := []string{
`C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe`,
`C:\Program Files\Microsoft\Edge\Application\msedge.exe`,
filepath.Join(os.Getenv("LOCALAPPDATA"), `Microsoft\Edge\Application\msedge.exe`),
}
for _, path := range candidates {
if _, err := os.Stat(path); err == nil {
return path, nil
}
}
return "", errors.New("Microsoft Edge の実行ファイルが見つかりませんでした")
}