-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathuc_presentation.py
567 lines (556 loc) · 27.8 KB
/
uc_presentation.py
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
import os
import subprocess
from seleniumbase import BaseCase
from seleniumbase import SB
BaseCase.main(__name__, __file__)
class UCPresentationClass(BaseCase):
def test_presentation(self):
self.open("data:,")
self.create_presentation(theme="beige", transition="fade")
self.add_slide(
"<p>A deep dive into <b>undetectable automation</b>, with:</p>"
"<h5><code>SeleniumBase UC Mode"
" and undetected-chromedriver</code></h5>",
image="https://seleniumbase.io/cdn/img/uc_mode_phases_3.png",
)
self.add_slide(
'<img src="https://seleniumbase.io/cdn/img/uc_mode_phases_3.png">'
)
self.add_slide(
"<p>🔹 <b>The Objective</b> 🔹</p><hr /><br />"
"<p><mk-0>By the end of this presentation, you'll learn how to"
" create bots that appear as humans to websites.</mk-0></p><br />"
"<p><mk-1>(These bots won't get detected or blocked.)</mk-1></p>"
"<br /><p><mk-2>Here's a live demo of that...</mk-2></p>"
)
self.begin_presentation(filename="uc_presentation.html")
self.get_new_driver(undetectable=True)
url = "https://gitlab.com/users/sign_in"
try:
self.driver.uc_open_with_reconnect(url, reconnect_time=3)
try:
self.assert_text("Username", '[for="user_login"]', timeout=3)
self.post_message("SeleniumBase wasn't detected", duration=4)
except Exception:
self.driver.uc_open_with_reconnect(url, reconnect_time=4)
self.assert_text("Username", '[for="user_login"]', timeout=3)
self.post_message("SeleniumBase wasn't detected", duration=4)
finally:
self.quit_extra_driver()
if os.path.exists("multi_uc.py"):
self.create_presentation(theme="beige", transition="fade")
self.add_slide(
"<p>🔹 <b>There's a lot more to come!</b> 🔹</p><hr /><br />"
"<p><mk-0>If one bot isn't enough, how about several?</mk-0>"
"</p><br /><br />"
"<p><mk-1>Here's a demo of multithreaded bots in parallel..."
"</mk-1></p>"
)
self.begin_presentation(filename="uc_presentation.html")
subprocess.Popen("pytest multi_uc.py --uc -n3", shell=True).wait()
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
"<p>Not just an army of bots, but an army of bots<br />"
"that look just like humans using web browsers.</p><br />"
"<p>(That's how they weren't detected!)</p>"
)
self.begin_presentation(filename="uc_presentation.html")
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
"If this is what you came here for, stick around<br />to"
" learn how to do the things you just saw.<br />"
"<p>You may find it easier to build a Selenium<br />"
"bot than to navigate an obstacle course.</p>",
image="https://seleniumbase.io/other/yeah_you_passed.png",
)
self.add_slide(
"<p>But first, you may be wondering who I am...</p>"
"<p>Or maybe you're one of over one million people<br />"
"that I've already helped on Stack Overview:</p>"
'<img src="https://seleniumbase.io/other/me_st_overflow.jpg" '
'width="80%">'
)
self.add_slide(
"<p><b>About the presenter (Michael Mintz):</b></p>\n"
"<ul>\n"
"<li>I created <b>SeleniumBase</b> (for Python).</li>\n"
"<li>I lead the Automation Team at <b>iboss</b>.</li>\n"
"</ul>\n",
image="https://seleniumbase.io/other/iboss_booth.png",
)
self.add_slide(
"<p>I've been doing video podcasts since 2012!</p>"
"<p>(That's when I first co-hosted the<br />Marketing Update"
" on HubSpot TV)</p>",
image="https://seleniumbase.io/other/hub_tv.png",
)
self.add_slide(
"<p>I spoke at Selenium Conference 2023:</p>"
"<p>(As the dedicated Python Selenium speaker)</p>",
image="https://seleniumbase.io/other/me_se_conf.jpg",
)
self.add_slide(
"<p>Here's me with the creators<br />"
"of <b>Selenium</b> / <b>WebDriver</b>:</p>",
image="https://seleniumbase.io/other/selenium_builders.jpg",
)
self.add_slide(
"<b>SeleniumBase</b> Fun Fact:"
"<div />The 1st SB GitHub issue was from a Tesla engineer:",
image="https://seleniumbase.io/other/first_issue.png",
)
self.add_slide(
"<p>Now, let me explain how we got here...</p>"
"<p>And by here, I mean a time when lots of companies"
" have been building services to detect and block bots:</p>",
image="https://seleniumbase.io/other/verify_human.png",
)
self.add_slide(
"<p>In the early days, there were few bots,<br />"
"and those bots didn't look human at all.</p><br />"
"<p>Those early bots were mostly innocent, and<br />"
"most websites didn't care if they were around.</p>"
)
self.add_slide(
"<p>At some point, the number of bots grew by a lot...</p><br />"
"<p>Many bots were programmed with bad intentions...</p><br />"
"<p>And sometimes you couldn't tell apart the good bots"
" from the bad ones until it was already too late...</p>",
)
self.add_slide(
"<p>Then came Google <b>reCAPTCHA v1</b>...</p>"
"<p>Although intended as a defense against bots,<br />"
" humans on a web browser also got hit by it.</p>",
image="https://seleniumbase.io/other/recaptcha_v1.png",
)
self.add_slide(
"<p>Then Google made improvements:</p>"
"<p>(<b>reCAPTCHA v2</b> / <b>reCAPTCHA v3</b>)</p>",
image="https://seleniumbase.io/other/recaptcha_v2a.png",
)
self.add_slide(
"<p>And that annoyed a lot of people...</p>",
image="https://seleniumbase.io/other/recaptcha_v2b.png",
)
self.add_slide(
"<p>Then came the next iteration of anti-bot security:</p>"
"<p>Cloudflare <b>Turnstile</b> CAPTCHA-replacement."
"<p>That changed the game in many ways.</p>",
image="https://seleniumbase.io/other/check_if_secure.png",
)
self.add_slide(
"For awhile, Cloudflare's Turnstile did a decent<br />"
"job filtering out bot traffic from human traffic."
"<p>Then <code>undetected-chromedriver</code> arrived:</p>",
image="https://seleniumbase.io/other/undetected_ch.png",
)
self.add_slide(
'<img src="https://seleniumbase.io/other/undetected_ch.png" '
'width="90%">'
)
self.add_slide(
"<p><code>undetected-chromedriver</code> was found to be<br />"
"incredibly effective at getting past the Turnstile:</p>",
image="https://seleniumbase.io/other/connection_secure.png",
)
self.add_slide(
"<p>The maintainer of <code>undetected-chromedriver</code>:</p>"
"<hr /><p>He appears to be very busy with various projects.</p>"
'<img src="https://seleniumbase.io/other/the_uc_starter.png" '
'width="80%">'
)
self.add_slide(
"<p>The biggest challenge for undetected-chromedriver"
" has been adapting to breaking changes caused by:</p><div />"
"<ul>\n"
"<li>New versions of Chrome.</li>\n"
"<li>New versions of Selenium.</li>\n"
"<li>New versions of Cloudflare.</li>\n"
"</ul><br /><hr />\n"
"<p>Those can brake things until updates are released:</p>"
'<img src="https://seleniumbase.io/other/uc_open_issues.png" '
'width="80%">'
)
self.add_slide(
"<p>Thankfully, <code>undetected-chromedriver</code> has<br />"
"supporters helping to figure out and fix things.<p>"
'<img src="https://seleniumbase.io/other/uc_helping_out.png" '
'width="70%">'
)
self.add_slide(
"<h4>Sometimes all that help isn't enough...</h4>"
"<p>That's where <code>seleniumbase</code> UC Mode comes in:</p>"
'<img src="https://seleniumbase.io/other/sb_github.png" '
'width="70%">'
)
self.add_slide(
"<h4>SeleniumBase <b>UC Mode</b> is a modified fork of<br />"
"undetected-chromedriver with multiple changes.</h4>"
"<h4>UC Mode includes bug fixes and additional features, such as"
" multithreading support via <code>pytest-xdist</code>.</h4>"
'<img src="https://seleniumbase.io/other/super_server.jpg" '
'width="60%">'
)
self.add_slide(
"<h4><mk-0><b>UC Mode</b> is one of many SeleniumBase modes:"
"</mk-0></h4>\n<ul>\n"
"<li><mk-1>UC Mode</mk-1> (<code>--uc / uc=True</code>)</li>\n"
"<li><mk-2>Slow Mode</mk-2> (<code>--slow</code>)</li>\n"
"<li><mk-3>Demo Mode</mk-3> (<code>--demo</code>)</li>\n"
'<li><mk-4>Proxy Mode</mk-4>'
' (<code>--proxy="h:p"/"u:p@h:p"</code>)</li>\n'
"<li><mk-5>Debug Mode</mk-5> "
"(<code>--pdb/--trace/--ftrace</code>)</li>\n"
"<li><mk-6>Mobile Mode</mk-6> "
"(<code>--mobile / mobile=True)</code></li>\n"
"<li><mk-7>Recorder Mode</mk-7> "
"(<code>--rec / --rec-behave</code>)</li>\n"
"<li><mk-8>Multithreaded Mode</mk-8> "
"(<code>pytest -n4 / -n8</code>)</li>\n"
"</ul>\n"
"<p><mk-9>And more! (You can even combine modes!)</mk-9></p>\n"
)
self.add_slide(
"<p><mk-0>ℹ️: UC Mode is not enabled by default.<br />"
" It must be activated by switching it on:</mk-0></p>"
"<ul>\n"
"<li><code><mk-1>--uc</mk-1></code>  "
" (pytest command-line option)</li>\n"
"<li><code><mk-2>uc=True</mk-2></code>  "
" (SB/driver manager formats)</li>\n"
"</ul><br /><br /><hr /><br />\n<p>"
"<mk-3>Then websites can no longer detect chromedriver.</mk-3></p>"
)
self.add_slide(
"<p><mk-0>Here's an example script that uses UC Mode:</mk-0></p>\n"
"<h5><mk-1>(Note that SeleniumBase has <code>driver</code> methods"
"<br />that aren't included with standard Selenium.)</mk-1></h5>\n"
"<hr /><br />\n",
code=(
"<mk-2>from seleniumbase import Driver</mk-2>\n\n"
"<mk-3>driver = Driver(uc=True)</mk-3>\n"
"<mk-4>try:</mk-4>\n"
' <mk-5>driver.get("https://nowsecure.nl/#relax")</mk-5>\n'
" <mk-1><mk-6>driver.sleep(4)</mk-6></mk-1>\n"
" <mk-7># DO MORE STUFF</mk-7>\n"
"<mk-4>finally:</mk-4>\n"
" <mk-4>driver.quit()</mk-4>\n"
),
)
self.add_slide(
"<p><mk-0>For reference, here's a script in a different<br />"
"SeleniumBase format, with more methods:</mk-0></p>"
"<h5><mk-12>(Get ready for another live demo...)</mk-12></h5>",
code=(
"<mk-1>from seleniumbase import SB</mk-1>\n\n"
"<mk-2>with SB(uc=True) as sb:</mk-2>\n"
' <mk-3>sb.driver.get('
'"https://seleniumbase.io/simple/login")</mk-3>\n'
' <mk-4>sb.type("#username", "demo_user")</mk-4>\n'
' <mk-5>sb.type("#password", "secret_pass")</mk-5>\n'
' <mk-6>sb.click(\'a:contains("Sign in")\')</mk-6>\n'
' <mk-7>sb.assert_exact_text("Welcome!", "h1")</mk-7>\n'
' <mk-8>sb.assert_element("img#image1")</mk-8>\n'
' <mk-9>sb.highlight("#image1")</mk-9>\n'
' <mk-10>sb.click_link("Sign out")</mk-10>\n'
' <mk-11>sb.assert_text("signed out", "#top_message")'
"</mk-11>\n"
),
)
self.begin_presentation(filename="uc_presentation.html")
try:
with SB(uc=True) as sb:
sb.driver.get("https://seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
sb.assert_exact_text("Welcome!", "h1")
sb.assert_element("img#image1")
sb.highlight("#image1")
sb.click_link("Sign out")
sb.assert_text("signed out", "#top_message")
except Exception:
pass
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
"<h3><mk-0>Was that too fast for you?</mk-0></h3>"
"<h4><mk-1>Let's run that again in <b>Demo Mode</b>:</mk-1></h4>",
code=(
"from seleniumbase import SB\n\n"
"with SB(uc=True<mk-1>, demo=True</mk-1>) as sb:\n"
' sb.driver.get('
'"https://seleniumbase.io/simple/login")\n'
' sb.type("#username", "demo_user")\n'
' sb.type("#password", "secret_pass")\n'
' sb.click(\'a:contains("Sign in")\')\n'
' sb.assert_exact_text("Welcome!", "h1")\n'
' sb.assert_element("img#image1")\n'
' sb.highlight("#image1")\n'
' sb.click_link("Sign out")\n'
' sb.assert_text("signed out", "#top_message")\n'
),
)
self.begin_presentation(filename="uc_presentation.html")
try:
with SB(uc=True, demo=True) as sb:
sb.driver.get("https://seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
sb.assert_exact_text("Welcome!", "h1")
sb.assert_element("img#image1")
sb.highlight("#image1")
sb.click_link("Sign out")
sb.assert_text("signed out", "#top_message")
except Exception:
pass
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
"<p><mk-0>Note the differences between undetected-chromedriver and"
" SeleniumBase UC Mode.</mk-0><br /><hr />SeleniumBase UC Mode:"
"</p><ul>\n"
"<li><mk-1>Has driver version-detection & management.</mk-1>"
"</li>\n"
"<li><mk-2>Allows mismatched browser/driver versions.</mk-2>"
"</li>\n"
"<li><mk-3>Changes the user agent to prevent detection.</mk-3>"
"</li>\n"
"<li><mk-4>Hides chromedriver from Chrome as needed.</mk-4>"
"</li>\n"
"<li><mk-5>Allows for multithreaded tests in parallel.</mk-5>"
"</li>\n"
"<li><mk-6>Adjusts configuration based on the environment.</mk-6>"
"</li>\n"
"<li><mk-7>Has options for proxy and proxy-with-auth.</mk-7>"
"</li>\n</ul>\n"
)
self.add_slide(
"<h3><mk-0>Here's another UC Mode script:</mk-0></h3>"
"<h4><mk-1>(Get ready for another live demo...)</mk-1></h4>"
"<hr /><br />",
code=(
"from seleniumbase import SB\n\n"
"with SB(uc=True) as sb:\n"
' sb.driver.get("https://nowsecure.nl/#relax")\n'
" sb.sleep(1)\n"
' if not sb.is_text_visible("OH YEAH, you passed", "h1"):\n'
" sb.get_new_driver(undetectable=True)\n"
' sb.driver.get("https://nowsecure.nl/#relax")\n'
" sb.sleep(1)\n"
' sb.activate_demo_mode()\n'
' sb.assert_text("OH YEAH, you passed!", "h1", timeout=3)\n'
),
)
self.begin_presentation(filename="uc_presentation.html")
try:
with SB(uc=True) as sb:
sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
if not sb.is_text_visible("OH YEAH, you passed", "h1"):
sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
sb.activate_demo_mode()
sb.assert_text("OH YEAH, you passed!", "h1", timeout=3)
except Exception:
pass
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
"<p>Now let's learn how UC Mode works in general.</p>"
"<p>First, there are several things that need to happen for"
" browsers to remain undetected from anti-bot services.</p>\n",
image="https://seleniumbase.io/other/yeah_you_passed.png",
)
self.add_slide(
"<mk-0>Requirements for avoiding detection</mk-0> (UC Mode)<hr />"
"<ul>\n"
"<li><mk-1>Modify chromedriver to rename driver variables"
" that appear in the Chrome DevTools console.</mk-1></li>\n"
"<li><mk-2>Launch Chrome before attaching chromedriver.<br />"
"(Don't launch Chrome with chromedriver)</mk-2></li>\n"
"<li><mk-3>Don't use Selenium-specific Chrome options.</mk-3>"
"</li>\n<li><mk-4>If using headless Chrome, change"
" HeadlessChrome to Chrome in the User Agent.</mk-4></li>\n"
"<li><mk-5>If using a custom user_data_dir, don't let that"
" folder be used with non-UC-Mode Chrome.</mk-5></li>\n"
"<li><mk-6>Disconnect chromedriver briefly from Chrome before"
" loading websites with detection services.</mk-6></li>\n"
"</ul>"
)
self.add_slide(
"Requirements, continued... / <b>Good news:</b><hr />\n"
"<h3><mk-0>Most of those things are already done automatically"
" when using UC Mode with default settings.</mk-0></h3>\n"
"<h4><mk-1>The part that's your responsibility, (if setting a"
" custom <code>user_data_dir</code>), is making sure that"
" the u_d_d is only used by UC Mode Chrome instances. If you"
' "cross the streams", UC Mode can be detected.</mk-1></h4><div />'
"<h4><mk-2>(UC Mode takes care of the other requirements.)</mk-2>"
"</h4>"
)
self.add_slide(
"<h4>With those things done, your bot can appear human.</h4>\n"
"<h5>But if anyone looks too closely at what your bot does,<br />"
'it may raise suspicion, even if already marked "not a bot".</h5>',
image="https://seleniumbase.io/other/other_anti_bots.jpg",
)
self.add_slide(
"<h4><mk-0>There are additional methods that you can use"
" to have a better experience when using UC Mode:</mk-0></h4>\n"
"<h6><br /><mk-1>Note that <code><b>driver.get(url)</b></code> has"
" been modified from the original to<br />reconnect automatically"
" if a web page is using bot-detection software.</mk-1></h6>"
"<hr /><br />",
code=(
"driver.default_get(url)\n\n"
"driver.uc_open(url)\n\n"
"driver.uc_open_with_tab(url)\n\n"
"driver.uc_open_with_reconnect(url, reconnect_time)\n\n"
'driver.uc_click(selector, by="css selector", timeout=7)\n'
),
)
self.add_slide(
"<h4>There are additional methods that you can use"
" to have a better experience when using UC Mode:</h4>"
"<h6><br /><mark>Since <code><b>driver.get(url)</b></code> has"
" been modified, <code><b>driver.default_get(url)</b></code>"
" exists to do a regular <code><b>get(url)</b></code>,"
" which may be useful if revisiting a website.</mark></h6>"
"<hr /><br />",
code=(
"<mark>driver.default_get(url)</mark>\n\n"
"driver.uc_open(url)\n\n"
"driver.uc_open_with_tab(url)\n\n"
"driver.uc_open_with_reconnect(url, reconnect_time)\n\n"
'driver.uc_click(selector, by="css selector", timeout=7)\n'
),
)
self.add_slide(
"<h4>There are additional methods that you can use"
" to have a better experience when using UC Mode:</h4>"
"<h6><br /><mark><code><b>driver.uc_open(url)</b></code> will"
" open a URL in the same tab with a disconnect.<br />"
"(This might not be enough to bypass detection.)</mark></h6>"
"<hr /><br />",
code=(
"driver.default_get(url)\n\n"
"<mark>driver.uc_open(url)</mark>\n\n"
"driver.uc_open_with_tab(url)\n\n"
"driver.uc_open_with_reconnect(url, reconnect_time)\n\n"
'driver.uc_click(selector, by="css selector", timeout=7)\n'
),
)
self.add_slide(
"<h4>There are additional methods that you can use"
" to have a better experience when using UC Mode:</h4>\n"
"<h6><br /><mark><code><b>driver.uc_open_with_tab(url)</b></code>"
" opens a URL in a new tab with a disconnect. Similar to the new"
" <code><b>driver.get(url)</b></code>, but without the pre-check."
"</mark></h6><hr /><br />",
code=(
"driver.default_get(url)\n\n"
"driver.uc_open(url)\n\n"
"<mark>driver.uc_open_with_tab(url)</mark>\n\n"
"driver.uc_open_with_reconnect(url, reconnect_time)\n\n"
'driver.uc_click(selector, by="css selector", timeout=7)\n'
),
)
self.add_slide(
"<h4>There are additional methods that you can use"
" to have a better experience when using UC Mode:</h4>\n"
"<h6><br /><code><b>driver.uc_open_with_tab(url)</b></code> opens"
" a URL in a new tab with a disconnect. Similar to the new"
" <code><b>driver.get(url)</b></code>, but without the pre-check."
"</h6><hr /><br />\n"
"<h6><mark>As a reminder, the <code><b>driver.get(url)</b></code>"
" pre-check checks to see if a URL has bot-detection software"
" on it before opening the URL in a new tab with a disconnect."
"</mark><br /></h6><div /><div />\n"
"<h6><mark>This pre-check is done using"
" <code><b>requests.get(URL)</b></code><br />before opening"
" a URL in the <code>UC Mode</code> web browser.</mark></h6>"
"<h5><mark>If the response code is a"
' <code><b>"403"</b></code> (Forbidden),<br />'
"then the URL is opened with a <code>disconnect</code>."
"</mark></h5>"
)
self.add_slide(
"<h4><b>Customizing the default disconnect/reconnect time</b></h4>"
"<hr />\n"
"<p>Here's a method for a custom reconnect time<br />"
"when opening a page that tries to detect bots:</p>"
"<pre><mk-0>driver.uc_open_with_reconnect(url, reconnect_time)"
"</mk-0></pre>"
"<h6>(The default reconnect_time is slightly more than 2 seconds.)"
"</h6><hr /><br />",
code=(
"# Example:\n"
"<mk-1>driver.uc_open_with_reconnect(\n"
' "https://nowsecure.nl/#relax", reconnect_time=6\n)</mk-1>'
"\n\n"
"# Short form example:\n"
"<mk-2>driver.uc_open_with_reconnect("
'"https://nowsecure.nl/#relax", 6)</mk-2>\n'
),
)
self.add_slide(
"<h4><b>Clicking with a disconnect/reconnect</b></h4><hr />\n"
"<p>If your bot needs to click a button on a website that has"
" anti-bot services, you might be able to do it with this special"
" method, which forces a short disconnect:</p>\n"
"<pre><mk-0>driver.uc_click(selector)</mk-0></pre>"
'<h6>(Defaults: <code>by="css selector", timeout=7</code>)</h6>'
"<hr /><br />\n",
code=(
"# Examples:\n"
'<mk-1>driver.uc_click("button")\n\n'
'driver.uc_click("button#id", timeout=10)</mk-1>\n'
),
)
self.add_slide(
"<h2>Links to UC Mode code</h2><hr /><br /><ul>\n"
'<li><a href="https://github.com/seleniumbase/SeleniumBase'
'/blob/master/examples/verify_undetected.py" target="_blank">'
'SeleniumBase/examples/verify_undetected.py</a></li><br />\n'
'<li><a href="https://github.com/seleniumbase/SeleniumBase'
'/blob/master/examples/uc_cdp_events.py" target="_blank">'
'SeleniumBase/examples/uc_cdp_events.py</a></li><br />\n'
'<li><a href="https://github.com/seleniumbase/SeleniumBase'
'/blob/master/examples/raw_uc_mode.py" target="_blank">'
'SeleniumBase/examples/raw_uc_mode.py</a></li>'
"<br />\n</ul>\n",
)
self.add_slide(
"<h2>Things to keep in mind</h2><hr /><ul>\n"
"<li>You may need to adjust default settings<br />"
"for your bot to remain undetected.</li><br />\n"
"<li>Once your bot enters a website,<br />"
"it should continue to act accordingly.</li><br />\n"
"<li>Improvise if your bot makes any mistakes.</li><br />\n"
"<li>Your bot should look human to avoid detection.</li></ul>\n",
)
self.add_slide(
"<h2>Ethical concerns</h2><hr /><ul>\n"
"<li>Don't use bots for evil purposes.</li><br />\n"
"<li>Do use bots with honorable intentions.</li><br />\n"
"<li>Do use bots for automating tedious manual tasks.</li><br />\n"
"<li>Do take the time to train & configure your bots.</li></ul>\n",
)
self.add_slide(
"<h2>🔹 Final remarks 🔹</h2><div /><hr /><h4><br /><ul>\n"
"<li>Not all bots are created equal.</li><br />\n"
"<li>SeleniumBase UC Mode lets bots appear human.</li><br />\n"
"<li>Visit SeleniumBase on GitHub for more info:\n"
"https://github.com/seleniumbase/SeleniumBase</li></ul></h4>\n",
)
self.add_slide(
"<h3>❓ Questions? ❓</h3>"
"<h5>https://github.com/seleniumbase/SeleniumBase/discussions</h5>"
"<br /><h3>📌 Found a bug? 🐞</h3><h5>"
"https://github.com/seleniumbase/SeleniumBase/issues</h5><hr />"
"<br /><h4>🔰 Perfection takes practice. Keep iterating! 🔰</h4>"
)
self.add_slide(
"<h1>The End</h1>",
image="https://seleniumbase.io/other/sb_github.png"
)
self.begin_presentation(filename="uc_presentation.html")