playwright驱动指纹浏览器

playwright比selenium新,检测点也少很多,通过python完成传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import asyncio
import json
from playwright.async_api import async_playwright

#--jack="{\"dnt\":\"1\",\"ua\":\"jack browser\",\"ssl_grease\":2.0,\"canvas_height\":1.0,\"bluetooth\":false,\"mobile\":true,\"memory\":100.0,\"hardware\":1024.0,\"conn_type\":\"10g\",\"conn_rtt\":10.0,\"battery_level\":100.0,\"battery_charging\":false,\"battery_time\":99.0,\"webaudio\":1.0,\"screen_pixel\":50.0,\"screen_awidth\":800.0,\"screen_aheight\":800.0,\"screen_width\":900.0,\"screen_height\":900.0,\"webrtc_public\":\"183.242.254.114\",\"webrtc_private\":\"192.168.252.119\",\"webgl_vendor\":\"ruyi\",\"productSub\":\"20240501\",\"vendor\":\"ruyi\",\"canvas_y\":1.0,\"font\":1.0}"
fingerprint = json.dumps(
{
"dnt":"1",
"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"ssl_grease":2.0,
"canvas_height":1.0,
"bluetooth":False,
"mobile":False,
"memory":9.0,
"hardware":9.0,
"conn_type":"10g",
"conn_rtt":10.0,
"battery_level":100.0,
"battery_charging":False,
"battery_time":99.0,
"webaudio":1.0,
"screen_pixel":50.0,
"screen_awidth":800.0,
"screen_aheight":800.0,
"screen_width":900.0,
"screen_height":900.0,
"webrtc_public":"183.242.254.114",
"webrtc_private":"192.168.252.119",
"webgl_vendor":"ruyi",
"productSub":"20240501",
"vendor":"ruyi",
"canvas_y":1.0,
"font":1.0
}, separators=(',', ':'))


async def main():
async with async_playwright() as p:
browser=await p.chromium.launch(
executable_path="C:\\chromium119\\src\out\\release\\chrome.exe",
args=[
f"--jack={fingerprint}"
],
headless=True
)
page=await browser.new_page()
await page.goto("https://bot.sannysoft.com/")
await page.screenshot(type='png', path='./screen.png', full_page=True)

# input(">>>")
print('程序运行完毕')

asyncio.run(main())

做高并发的话,都是选择Headless模式,对于Headless模式下还有一些独有的特征,需要进行处理,比如PermissionsPlugin插件等等检测点需要绕过。

通过page.add_init_script函数去添加js脚本,这些js代码会在浏览器启动的时候执行,但是需要针对不同的网页不同的检测点去改,不存在通用的解决方案,有时候需要结合网页逆向去看到底检测了什么。不过现在的112版本之后的chromium有一个--headless=new的启动参数,该参数会补全插件、window.chrome属性等检测点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import asyncio
import json
from playwright.async_api import async_playwright

#--jack="{\"dnt\":\"1\",\"ua\":\"jack browser\",\"ssl_grease\":2.0,\"canvas_height\":1.0,\"bluetooth\":false,\"mobile\":true,\"memory\":100.0,\"hardware\":1024.0,\"conn_type\":\"10g\",\"conn_rtt\":10.0,\"battery_level\":100.0,\"battery_charging\":false,\"battery_time\":99.0,\"webaudio\":1.0,\"screen_pixel\":50.0,\"screen_awidth\":800.0,\"screen_aheight\":800.0,\"screen_width\":900.0,\"screen_height\":900.0,\"webrtc_public\":\"183.242.254.114\",\"webrtc_private\":\"192.168.252.119\",\"webgl_vendor\":\"ruyi\",\"productSub\":\"20240501\",\"vendor\":\"ruyi\",\"canvas_y\":1.0,\"font\":1.0}"
fingerprint = json.dumps(
{
"dnt":"1",
"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"ssl_grease":2.0,
"canvas_height":1.0,
"bluetooth":False,
"mobile":False,
"memory":9.0,
"hardware":9.0,
"conn_type":"10g",
"conn_rtt":10.0,
"battery_level":100.0,
"battery_charging":False,
"battery_time":99.0,
"webaudio":1.0,
"screen_pixel":50.0,
"screen_awidth":800.0,
"screen_aheight":800.0,
"screen_width":900.0,
"screen_height":900.0,
"webrtc_public":"183.242.254.114",
"webrtc_private":"192.168.252.119",
"webgl_vendor":"ruyi",
"productSub":"20240501",
"vendor":"ruyi",
"canvas_y":1.0,
"font":1.0
}, separators=(',', ':'))


async def main():
async with async_playwright() as p:
browser=await p.chromium.launch(
executable_path="C:\\chromium119\\src\out\\release\\chrome.exe",
args=[
f"--jack={fingerprint}",
"--headless=new"
],
# headless=True
)
page=await browser.new_page()
# await page.add_init_script("""
# Object.defineProperty(window,"chrome",{value:{}})
#
#
# // 模拟 PermissionStatus 对象
# function MockPermissionStatus(state) {
# this.state = state;
# }
#
# // 定义一个返回 Promise 的 query 方法
# function MockPermissions() {
# this.query = function(params) {
# return new Promise((resolve) => {
# if (params.name === 'notifications') {
# resolve(new MockPermissionStatus('jack')); // 你可以根据需要设置初始状态
# } else {
# resolve(new MockPermissionStatus('denied'));
# }
# });
# };
# }
#
# // 注入模拟的 permissions 对象到 navigator
# Object.defineProperty(navigator, 'permissions', {
# get: function() {
# return new MockPermissions();
# }
# });
#
#
# // 定义模拟插件对象
# function MockPlugin(name, description, filename) {
# this.name = name;
# this.description = description;
# this.filename = filename;
# }
#
# MockPlugin.prototype = Object.create(Plugin.prototype);
# MockPlugin.prototype.constructor = MockPlugin;
# MockPlugin.prototype.toString = function() {
# return '[object Plugin]';
# };
#
# const mockPlugin = new MockPlugin('Mock Plugin', 'A mock plugin for testing', 'mock-plugin.dll');
#
# // 定义模拟插件数组对象
# function MockPluginArray() {
# }
#
# MockPluginArray.prototype = Object.create(PluginArray.prototype);
# MockPluginArray.prototype.constructor = MockPluginArray;
#
# MockPluginArray.prototype.item = function(index) {
# return this[index];
# };
# MockPluginArray.prototype.namedItem = function(name) {
# if (name === 'Mock Plugin') {
# return mockPlugin;
# }
# return null;
# };
# MockPluginArray.prototype.toString = function() {
# return '[object PluginArray]';
# };
#
# const mockPluginArray = new MockPluginArray();
# Object.defineProperty(mockPluginArray,"length",{value:1})
# Object.defineProperty(mockPluginArray,"0",{value:mockPlugin})
#
# // 注入模拟插件数组到 navigator 对象
# Object.defineProperty(navigator, 'plugins', {
# get: function() {
# return mockPluginArray;
# }
# });
#
#
# """)
await page.goto("https://bot.sannysoft.com/")
await page.screenshot(type='png', path='./screen.png', full_page=True)
# input(">>>")
print('程序运行完毕')

asyncio.run(main())

但是,未来headless模式下如果出现新的检测点,还是需要去逆向然后使用js注入的方式去绕过。