brave-real-browser 2.0.8 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/index.js +5 -0
- package/lib/esm/index.mjs +5 -0
- package/package.json +4 -2
- package/test/cjs/test.js +32 -6
- package/test/esm/test.js +32 -6
package/lib/cjs/index.js
CHANGED
|
@@ -29,6 +29,11 @@ async function connect({
|
|
|
29
29
|
} else {
|
|
30
30
|
// Use DEFAULT_FLAGS from brave-real-launcher
|
|
31
31
|
const flags = [...DEFAULT_FLAGS];
|
|
32
|
+
// Add AutomationControlled to "disable-features" flag to improve ReCaptcha V3 score
|
|
33
|
+
const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
|
|
34
|
+
if (indexDisableFeatures !== -1) {
|
|
35
|
+
flags[indexDisableFeatures] = `${flags[indexDisableFeatures]},AutomationControlled`;
|
|
36
|
+
}
|
|
32
37
|
braveFlags = [
|
|
33
38
|
...flags,
|
|
34
39
|
...args,
|
package/lib/esm/index.mjs
CHANGED
|
@@ -28,6 +28,11 @@ export async function connect({
|
|
|
28
28
|
} else {
|
|
29
29
|
// Use DEFAULT_FLAGS from brave-real-launcher
|
|
30
30
|
const flags = [...DEFAULT_FLAGS];
|
|
31
|
+
// Add AutomationControlled to "disable-features" flag to improve ReCaptcha V3 score
|
|
32
|
+
const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
|
|
33
|
+
if (indexDisableFeatures !== -1) {
|
|
34
|
+
flags[indexDisableFeatures] = `${flags[indexDisableFeatures]},AutomationControlled`;
|
|
35
|
+
}
|
|
31
36
|
braveFlags = [
|
|
32
37
|
...flags,
|
|
33
38
|
...args,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "This package is designed to bypass puppeteer's bot-detecting captchas such as Cloudflare. It acts like a real browser and can be managed with puppeteer.",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/esm/index.mjs",
|
|
@@ -37,9 +37,11 @@
|
|
|
37
37
|
"license": "ISC",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"brave-real-launcher": "^1.2.48",
|
|
40
|
-
"brave-real-puppeteer-core": "^24.34.0-patch.
|
|
40
|
+
"brave-real-puppeteer-core": "^24.34.0-patch.13",
|
|
41
41
|
"ghost-cursor": "^1.4.1",
|
|
42
42
|
"puppeteer-extra": "^3.3.6",
|
|
43
|
+
"puppeteer-extra-plugin-adblocker": "^2.13.6",
|
|
44
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
43
45
|
"tree-kill": "^1.2.2",
|
|
44
46
|
"xvfb": "^0.4.0"
|
|
45
47
|
},
|
package/test/cjs/test.js
CHANGED
|
@@ -2,11 +2,18 @@ const test = require('node:test');
|
|
|
2
2
|
const assert = require('node:assert');
|
|
3
3
|
const { connect } = require('../../lib/cjs/index.js');
|
|
4
4
|
|
|
5
|
+
// Import Stealth and Adblocker Plugins
|
|
6
|
+
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
|
7
|
+
const AdblockerPlugin = require('puppeteer-extra-plugin-adblocker');
|
|
8
|
+
|
|
5
9
|
const realBrowserOption = {
|
|
6
10
|
turnstile: true,
|
|
7
11
|
headless: false,
|
|
8
12
|
customConfig: {},
|
|
9
|
-
plugins: [
|
|
13
|
+
plugins: [
|
|
14
|
+
StealthPlugin(),
|
|
15
|
+
AdblockerPlugin({ blockTrackers: true })
|
|
16
|
+
]
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
// Shared browser instance for all tests
|
|
@@ -38,11 +45,14 @@ test('DrissionPage Detector', async () => {
|
|
|
38
45
|
assert.strictEqual(result, true, "DrissionPage Detector test failed!")
|
|
39
46
|
})
|
|
40
47
|
|
|
41
|
-
test('
|
|
42
|
-
await page.goto("https://
|
|
48
|
+
test('Sannysoft WebDriver Detector', async () => {
|
|
49
|
+
await page.goto("https://bot.sannysoft.com/");
|
|
43
50
|
await new Promise(r => setTimeout(r, 3000));
|
|
44
|
-
let result = await page.evaluate(() => {
|
|
45
|
-
|
|
51
|
+
let result = await page.evaluate(() => {
|
|
52
|
+
const webdriverEl = document.getElementById('webdriver-result');
|
|
53
|
+
return webdriverEl && webdriverEl.classList.contains('passed');
|
|
54
|
+
});
|
|
55
|
+
assert.strictEqual(result, true, "Sannysoft WebDriver Detector test failed! Browser detected as bot.")
|
|
46
56
|
})
|
|
47
57
|
|
|
48
58
|
test('Cloudflare WAF', async () => {
|
|
@@ -117,8 +127,24 @@ test('Datadome Bot Detector', async (t) => {
|
|
|
117
127
|
// If this test fails, please first check if you can access https://antcpt.com/score_detector/
|
|
118
128
|
test('Recaptcha V3 Score (hard)', async () => {
|
|
119
129
|
await page.goto("https://antcpt.com/score_detector/");
|
|
130
|
+
|
|
131
|
+
// Human-like warm-up interactions before clicking
|
|
132
|
+
// 1. Random mouse movements using realCursor
|
|
133
|
+
await page.realCursor.move('body', { paddingPercentage: 20 });
|
|
134
|
+
await new Promise(r => setTimeout(r, 500 + Math.random() * 500));
|
|
135
|
+
|
|
136
|
+
// 2. Scroll down a bit to simulate reading
|
|
137
|
+
await page.mouse.wheel({ deltaY: 100 + Math.random() * 100 });
|
|
138
|
+
await new Promise(r => setTimeout(r, 800 + Math.random() * 400));
|
|
139
|
+
|
|
140
|
+
// 3. Move mouse towards button area naturally
|
|
141
|
+
await page.realCursor.move('button', { paddingPercentage: 10 });
|
|
142
|
+
await new Promise(r => setTimeout(r, 300 + Math.random() * 300));
|
|
143
|
+
|
|
144
|
+
// 4. Now click the button
|
|
120
145
|
await page.realClick("button")
|
|
121
|
-
await new Promise(r => setTimeout(r,
|
|
146
|
+
await new Promise(r => setTimeout(r, 6000));
|
|
147
|
+
|
|
122
148
|
const score = await page.evaluate(() => {
|
|
123
149
|
return document.querySelector('big').textContent.replace(/[^0-9.]/g, '')
|
|
124
150
|
})
|
package/test/esm/test.js
CHANGED
|
@@ -2,11 +2,18 @@ import test from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
import { connect } from '../../lib/esm/index.mjs';
|
|
4
4
|
|
|
5
|
+
// Import Stealth and Adblocker Plugins
|
|
6
|
+
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
7
|
+
import AdblockerPlugin from 'puppeteer-extra-plugin-adblocker';
|
|
8
|
+
|
|
5
9
|
const realBrowserOption = {
|
|
6
10
|
turnstile: true,
|
|
7
11
|
headless: false,
|
|
8
12
|
customConfig: {},
|
|
9
|
-
plugins: [
|
|
13
|
+
plugins: [
|
|
14
|
+
StealthPlugin(),
|
|
15
|
+
AdblockerPlugin({ blockTrackers: true })
|
|
16
|
+
]
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
// Shared browser instance for all tests
|
|
@@ -38,11 +45,14 @@ test('DrissionPage Detector', async () => {
|
|
|
38
45
|
assert.strictEqual(result, true, "DrissionPage Detector test failed!")
|
|
39
46
|
})
|
|
40
47
|
|
|
41
|
-
test('
|
|
42
|
-
await page.goto("https://
|
|
48
|
+
test('Sannysoft WebDriver Detector', async () => {
|
|
49
|
+
await page.goto("https://bot.sannysoft.com/");
|
|
43
50
|
await new Promise(r => setTimeout(r, 3000));
|
|
44
|
-
let result = await page.evaluate(() => {
|
|
45
|
-
|
|
51
|
+
let result = await page.evaluate(() => {
|
|
52
|
+
const webdriverEl = document.getElementById('webdriver-result');
|
|
53
|
+
return webdriverEl && webdriverEl.classList.contains('passed');
|
|
54
|
+
});
|
|
55
|
+
assert.strictEqual(result, true, "Sannysoft WebDriver Detector test failed! Browser detected as bot.")
|
|
46
56
|
})
|
|
47
57
|
|
|
48
58
|
test('Cloudflare WAF', async () => {
|
|
@@ -118,8 +128,24 @@ test('Datadome Bot Detector', async (t) => {
|
|
|
118
128
|
// If this test fails, please first check if you can access https://antcpt.com/score_detector/
|
|
119
129
|
test('Recaptcha V3 Score (hard)', async () => {
|
|
120
130
|
await page.goto("https://antcpt.com/score_detector/");
|
|
131
|
+
|
|
132
|
+
// Human-like warm-up interactions before clicking
|
|
133
|
+
// 1. Random mouse movements using realCursor
|
|
134
|
+
await page.realCursor.move('body', { paddingPercentage: 20 });
|
|
135
|
+
await new Promise(r => setTimeout(r, 500 + Math.random() * 500));
|
|
136
|
+
|
|
137
|
+
// 2. Scroll down a bit to simulate reading
|
|
138
|
+
await page.mouse.wheel({ deltaY: 100 + Math.random() * 100 });
|
|
139
|
+
await new Promise(r => setTimeout(r, 800 + Math.random() * 400));
|
|
140
|
+
|
|
141
|
+
// 3. Move mouse towards button area naturally
|
|
142
|
+
await page.realCursor.move('button', { paddingPercentage: 10 });
|
|
143
|
+
await new Promise(r => setTimeout(r, 300 + Math.random() * 300));
|
|
144
|
+
|
|
145
|
+
// 4. Now click the button
|
|
121
146
|
await page.realClick("button")
|
|
122
|
-
await new Promise(r => setTimeout(r,
|
|
147
|
+
await new Promise(r => setTimeout(r, 6000));
|
|
148
|
+
|
|
123
149
|
const score = await page.evaluate(() => {
|
|
124
150
|
return document.querySelector('big').textContent.replace(/[^0-9.]/g, '')
|
|
125
151
|
})
|