浏览器初始化:playwright install

基本用法:

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
class DyLogin:
def __init__(self, playwright, dir_path, username, password, shop_name):
self.pw = playwright
self.home_url = "https://compassbrand.jinritemai.com/cabin"
self.user_dir = dir_path
self.browser = None
self.page = None
self.frame = None
self.username = username
self.password = password
self.shop_name = shop_name
# self.chrome = False

def start(self):
"""
主调度程序
"""
self.launch()
self.login()
self.save()
self.browser.close()

def launch(self):
self.browser = self.pw.chromium.launch(
# proxy={"server": "http://10.20.1.242:31280"},
headless=False,
args=[
"--start-maximized",
"--disable-features=AutomationControlled",
"--disable-blink-features",
],
ignore_default_args=["--enable-automation"],
# executable_path="C:\\Program Files (x86)\\Google\\Chrome\\chrome.exe",
)
context = self.browser.new_context(
# viewport={"width": 1920, "height": 1080},
no_viewport=True, # 最大化
# user_agent 不用设置,默认用的chrome
ignore_https_errors=True,
)
self.page = context.new_page()
code = (
"""Object.defineProperties(navigator, {webdriver:{get:()=>undefined}});"""
)
self.page.add_init_script(code)

def login(self):
self.page.goto(self.home_url)
self.page.wait_for_timeout(10000)
self.page.click("div.switch-switch.email")
self.page.wait_for_timeout(1000)
self.page.fill('input[fieldname="item_label_email"]', "") # 清空
self.page.type(
'input[fieldname="item_label_email"]',
self.username,
delay=random.randint(100, 150),
)
self.page.wait_for_timeout(1000)
self.page.fill('input[fieldname="item_label_pwd"]', "")
self.page.type(
'input[fieldname="item_label_pwd"]',
self.password,
delay=random.randint(100, 150),
)
self.page.wait_for_timeout(1000)
self.page.click("input.ecom-checkbox-input")
self.page.wait_for_timeout(1000)
self.page.click("button.account-center-action-button")
self.page.wait_for_timeout(2000)
# 滑块
frames = self.page.frames
if len(frames) > 1:
logger.info("出现滑块,开始模拟滑动")
self.frame = frames[1]
self.mouse_slide()
# 检查元素是否存在
ele = self.page.query_selector(slider_css)

# ele = self.page.locator("div.ecom-dropdown-trigger>span:first-of-type")
# self.shop_name = ele.text_content()

def mouse_slide(self):
for _ in range(10):
self.download_pic()
self.puzzle_pic()
slider = self.frame.locator("img#captcha-verify_img_slide")
cdn = slider.bounding_box()
length = cdn["x"] + 27 + 4
high = cdn["y"]
move_length = self.get_distance()
real_length = move_length * 340 / 552
logger.info(f"开始滑动操作,滑动距离:{move_length}")
self.frame.hover("img#captcha-verify_img_slide")
self.page.mouse.down()
self.page.mouse.move(length, high)
for x in self.get_track(real_length):
length = length + x
self.page.mouse.move(length, high)
self.page.wait_for_timeout(random.randint(10, 15))
self.page.mouse.up()
self.page.wait_for_timeout(5000)
# 判断是否滑动通过
frames = self.page.frames
if len(frames) < 2:
logger.info("滑动通过".center(150, "-"))
break
else:
logger.info("滑动失败,重新滑动".center(150, "~"))
self.page.wait_for_timeout(3000)

拦截请求

1
2
3
4
5
6
page.route('**/*', handle_request)

def handle_request(route, request):
if "strategy_market" in request.url:
print(request.url)
route.continue_()

隐藏webdriver / 执行JS

1
2
code = """Object.defineProperties(navigator, {webdriver:{get:()=>false}});"""
self.page.evaluate(code)

开启stealth模式

pip install playwright_stealth

1
2
3
from playwright_stealth import stealth_sync  # 同步模式

stealth_sync(self.page)

Cookie操作

1
2
3
4
5
6
7
8
9
10
11
12
13
# 配置ck
ck_dct = [
{"name": k, "value": v, "domain": ".jd.com", "path": "/"}
for k, v in cookies.items()
]
with sync_playwright() as pw:
browser = pw.chromium.launch()
context = browser.new_context()
context.add_cookies(ck_dct)

# 获取ck
for ck in self.page.context.cookies():
cookie += f"{ck['name']}={ck['value']};"

使用浏览器缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.browser = self.pw.chromium.launch_persistent_context(
# proxy={"server": "http://10.20.1.19:31280"},
headless=False,
executable_path="C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
args=[
"--start-maximized",
"--disable-features=AutomationControlled",
"--disable-blink-features",
],
ignore_default_args=["--enable-automation"],
user_data_dir="C:\\Users\\14276\\Desktop\\btConfig",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
no_viewport=True,
ignore_https_errors=True,
)
self.page = self.browser.new_page()

贝塞尔曲线轨迹

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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import math
import random

import numpy as np


class BezierTrajectory:
"""
根据贝塞尔曲线生成鼠标轨迹
使用直接调用get_track,传入需要滑动的距离
"""

def _bztsg(self, dataTrajectory):
lengthOfdata = len(dataTrajectory)

def staer(x):
t = (x - dataTrajectory[0][0]) / (
dataTrajectory[-1][0] - dataTrajectory[0][0]
)
y = np.array([0, 0], dtype=np.float64)
for s in range(len(dataTrajectory)):
y += dataTrajectory[s] * (
(
math.factorial(lengthOfdata - 1)
/ (math.factorial(s) * math.factorial(lengthOfdata - 1 - s))
)
* math.pow(t, s)
* math.pow((1 - t), lengthOfdata - 1 - s)
)
return y[1]

return staer

def _type(self, type, x, numberList):
numberListre = []
pin = (x[1] - x[0]) / numberList
if type == 0:
for i in range(numberList):
numberListre.append(i * pin)
if pin >= 0:
numberListre = numberListre[::-1]
elif type == 1:
for i in range(numberList):
numberListre.append(1 * ((i * pin) ** 2))
numberListre = numberListre[::-1]
elif type == 2:
for i in range(numberList):
numberListre.append(1 * ((i * pin - x[1]) ** 2))
elif type == 3:
dataTrajectory = [
np.array([0, 0]),
np.array([(x[1] - x[0]) * 0.8, (x[1] - x[0]) * 0.6]),
np.array([x[1] - x[0], 0]),
]
fun = self._bztsg(dataTrajectory)
numberListre = [0]
for i in range(1, numberList):
numberListre.append(fun(i * pin) + numberListre[-1])
if pin >= 0:
numberListre = numberListre[::-1]
numberListre = np.abs(np.array(numberListre) - max(numberListre))
biaoNumberList = (
(numberListre - numberListre[numberListre.argmin()])
/ (
numberListre[numberListre.argmax()]
- numberListre[numberListre.argmin()]
)
) * (x[1] - x[0]) + x[0]
biaoNumberList[0] = x[0]
biaoNumberList[-1] = x[1]
return biaoNumberList

def getFun(self, s):
"""
:param s: 传入P点
:return: 返回公式
"""
dataTrajectory = []
for i in s:
dataTrajectory.append(np.array(i))
return self._bztsg(dataTrajectory)

def simulation(self, start, end, le=1, deviation=0, bias=0.5):
"""
:param start:开始点的坐标 如 start = [0, 0]
:param end:结束点的坐标 如 end = [100, 100]
:param le:几阶贝塞尔曲线,越大越复杂 如 le = 4
:param deviation:轨迹上下波动的范围 如 deviation = 10
:param bias:波动范围的分布位置 如 bias = 0.5
:return:返回一个字典equation对应该曲线的方程,P对应贝塞尔曲线的影响点
"""
start = np.array(start)
end = np.array(end)
cbb = []
if le != 1:
e = (1 - bias) / (le - 1)
cbb = [[bias + e * i, bias + e * (i + 1)] for i in range(le - 1)]
dataTrajectoryList = [start]
t = random.choice([-1, 1])
w = 0
for i in cbb:
px1 = start[0] + (end[0] - start[0]) * (
random.random() * (i[1] - i[0]) + (i[0])
)
p = np.array([px1, self._bztsg([start, end])(px1) + t * deviation])
dataTrajectoryList.append(p)
w += 1
if w >= 2:
w = 0
t = -1 * t
dataTrajectoryList.append(end)
return {
"equation": self._bztsg(dataTrajectoryList),
"P": np.array(dataTrajectoryList),
}

def trackArray(
self, start, end, numberList, le=1, deviation=0, bias=0.5, type=0, cbb=0, yhh=10
):
"""
:param start:开始点的坐标 如 start = [0, 0]
:param end:结束点的坐标 如 end = [100, 100]
:param numberList:返回的数组的轨迹点的数量 numberList = 150
:param le:几阶贝塞尔曲线,越大越复杂 如 le = 4
:param deviation:轨迹上下波动的范围 如 deviation = 10
:param bias:波动范围的分布位置 如 bias = 0.5
:param type:0表示均速滑动,1表示先慢后快,2表示先快后慢,3表示先慢中间快后慢 如 type = 1
:param cbb:在终点来回摆动的次数
:param yhh:在终点来回摆动的范围
:return:返回一个字典trackArray对应轨迹数组,P对应贝塞尔曲线的影响点
"""
s = []
fun = self.simulation(start, end, le, deviation, bias)
w = fun["P"]
fun = fun["equation"]
if cbb != 0:
numberListOfcbb = round(numberList * 0.2 / (cbb + 1))
numberList -= numberListOfcbb * (cbb + 1)
xTrackArray = self._type(type, [start[0], end[0]], numberList)
for i in xTrackArray:
s.append([i, fun(i)])
dq = yhh / cbb
kg = 0
ends = np.copy(end)
for i in range(cbb):
if kg == 0:
d = np.array(
[
end[0] + (yhh - dq * i),
((end[1] - start[1]) / (end[0] - start[0]))
* (end[0] + (yhh - dq * i))
+ (
end[1]
- ((end[1] - start[1]) / (end[0] - start[0])) * end[0]
),
]
)
kg = 1
else:
d = np.array(
[
end[0] - (yhh - dq * i),
((end[1] - start[1]) / (end[0] - start[0]))
* (end[0] - (yhh - dq * i))
+ (
end[1]
- ((end[1] - start[1]) / (end[0] - start[0])) * end[0]
),
]
)
kg = 0
# print(d)
y = self.trackArray(
ends,
d,
numberListOfcbb,
le=1,
deviation=0,
bias=0.5,
type=type,
cbb=0,
yhh=yhh,
)
s += list(y["trackArray"])
ends = d
y = self.trackArray(
ends,
end,
numberListOfcbb,
le=2,
deviation=0,
bias=0.5,
type=type,
cbb=0,
yhh=yhh,
)
s += list(y["trackArray"])
else:
xTrackArray = self._type(type, [start[0], end[0]], numberList)
for i in xTrackArray:
s.append([i, fun(i)])
return {"trackArray": np.array(s), "P": w}


def get_track(distance: int):
"""
获取鼠标轨迹
:param distance: 滑块距离
:return: 轨迹数组
"""
bei = BezierTrajectory()
start_point = [0, 0]
end_point = [distance, random.randint(-150, 150)]
res = bei.trackArray(
start=start_point,
end=end_point,
numberList=random.randint(8, 10),
le=random.randint(3, 5),
deviation=random.randint(7, 13),
bias=random.choice([0.3, 0.4, 0.5, 0.6, 0.7]),
type=random.choice([1, 2, 3]),
cbb=1,
yhh=10,
)
return res["trackArray"]