simplex 1.2.63__py3-none-any.whl → 1.2.65__py3-none-any.whl

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.

Potentially problematic release.


This version of simplex might be problematic. Click here for more details.

simplex/simplex.py CHANGED
@@ -4,67 +4,29 @@ from typing import Optional, Union
4
4
  import os
5
5
  import json
6
6
  import warnings
7
- import time
8
- # Try to import playwright, but don't fail if it's not available (lite version)
7
+
9
8
  try:
10
9
  from rebrowser_playwright.sync_api import sync_playwright
11
10
  PLAYWRIGHT_AVAILABLE = True
12
11
  except ImportError:
13
- PLAYWRIGHT_AVAILABLE = False
14
- warnings.warn(
15
- "Playwright is not available. Some features will be disabled. "
16
- "To enable all features, install with 'pip install simplex[playwright]'",
17
- ImportWarning
18
- )
19
-
20
- # BASE_URL = "https://simplex-dev--api-server-fastapi-app.modal.run"
21
- BASE_URL = "https://api.simplex.sh"
22
- class Playwright:
23
- def __init__(self, simplex_instance):
24
- self.simplex = simplex_instance
25
-
26
- def click(self, locator: str, locator_type: str, exact: Optional[bool] = False,
27
- element_index: Optional[str] = None, nth_index: Optional[int] = None,
28
- locator_options: Optional[dict] = None):
29
-
30
- if element_index and element_index not in ["first", "last", "nth"]:
31
- raise ValueError("element_index must be 'first', 'last', or 'nth'")
32
-
33
- if element_index=="nth" and not nth_index:
34
- raise ValueError("nth_index is required when element_index is 'nth'")
35
-
36
- data = {
37
- 'session_id': self.simplex.session_id,
38
- 'locator': locator,
39
- 'locator_type': locator_type,
40
- }
41
-
42
- if element_index:
43
- data['element_index'] = element_index
44
- data['nth_index'] = nth_index
45
-
46
- if exact:
47
- data['exact'] = exact
48
-
49
- if locator_options:
50
- data['locator_options'] = json.dumps(locator_options)
51
-
52
- response = requests.post(
53
- f"{BASE_URL}/playwright/click",
54
- headers={
55
- 'x-api-key': self.simplex.api_key
56
- },
57
- data=data
12
+ try:
13
+ from playwright.sync_api import sync_playwright
14
+ PLAYWRIGHT_AVAILABLE = True
15
+ warnings.warn(
16
+ "Using standard playwright instead of rebrowser-patches. Some anti-bot systems may detect automation. "
17
+ "To improve stealth, install with 'pip install rebrowser-playwright'",
18
+ ImportWarning
19
+ )
20
+ except ImportError:
21
+ PLAYWRIGHT_AVAILABLE = False
22
+ warnings.warn(
23
+ "Playwright is not available. Some features will be disabled. "
24
+ "To enable all features, install with 'pip install simplex[playwright]'",
25
+ ImportWarning
58
26
  )
59
27
 
60
- if 'succeeded' not in response.json():
61
- print(response.json())
62
- raise ValueError(f"It looks like the click action with playwright failed to return a response. Did you set your api_key when creating the Simplex class?")
63
-
64
- if "succeeded" in response.json():
65
- return
66
- else:
67
- raise ValueError(f"Failed to click element: {response.json()['error']}")
28
+ BASE_URL = "https://simplex-dev--api-server-and-container-service-fastapi-app.modal.run"
29
+ # BASE_URL = "https://api.simplex.sh"
68
30
 
69
31
  class Simplex:
70
32
  def __init__(self, api_key: str):
@@ -72,11 +34,9 @@ class Simplex:
72
34
  self.session_id = None
73
35
  atexit.register(self.close_session)
74
36
  if PLAYWRIGHT_AVAILABLE:
75
- self.playwright = Playwright(self)
76
37
  self.pw_browser = None
77
38
  self.pw = None
78
39
  else:
79
- self.playwright = None
80
40
  self.pw_browser = None
81
41
  self.pw = None
82
42
 
@@ -105,7 +65,7 @@ class Simplex:
105
65
  self.session_id = None
106
66
  if 'succeeded' not in response.json():
107
67
  raise ValueError(f"It looks like the close_session action failed to return a response. Did you set your api_key when creating the Simplex class?")
108
- if "succeeded" in response.json():
68
+ if response.json()['succeeded']:
109
69
  return
110
70
  else:
111
71
  raise ValueError(f"Failed to close session: {response.json()['error']}")
@@ -187,10 +147,11 @@ class Simplex:
187
147
  },
188
148
  data=data
189
149
  )
150
+
190
151
  if 'succeeded' not in response.json():
191
152
  raise ValueError(f"It looks like the goto action failed to return a response. Did you set your api_key when creating the Simplex class?")
192
153
 
193
- if "succeeded" in response.json():
154
+ if response.json()['succeeded']:
194
155
  return
195
156
  else:
196
157
  raise ValueError(f"Failed to goto url: {response.json()['error']}")
@@ -222,6 +183,65 @@ class Simplex:
222
183
  else:
223
184
  raise ValueError(f"Failed to click element: {response.json()['error']}")
224
185
 
186
+
187
+ def scroll_to_element(self, element_description: str, cdp_url: str = None):
188
+ if not element_description or not element_description.strip():
189
+ raise ValueError("element_description cannot be empty")
190
+ if not cdp_url and not self.session_id:
191
+ raise ValueError(f"Must call create_session before calling action scroll_to_element with element_description='{element_description}'")
192
+
193
+ data = {'element_description': element_description}
194
+
195
+ if cdp_url:
196
+ data['cdp_url'] = cdp_url
197
+ else:
198
+ data['session_id'] = self.session_id
199
+
200
+ response = requests.post(
201
+ f"{BASE_URL}/scroll_to_element",
202
+ headers={
203
+ 'x-api-key': self.api_key
204
+ },
205
+ data=data
206
+ )
207
+
208
+ if 'succeeded' not in response.json():
209
+ raise ValueError(f"It looks like the scroll_to_element action failed to return a response. Did you set your api_key when creating the Simplex class?")
210
+ if response.json()["succeeded"]:
211
+ return
212
+ else:
213
+ raise ValueError(f"Failed to scroll element into view: {response.json()['error']}")
214
+
215
+
216
+
217
+ def hover(self, element_description: str, cdp_url: str = None):
218
+ if not element_description or not element_description.strip():
219
+ raise ValueError("element_description cannot be empty")
220
+ if not cdp_url and not self.session_id:
221
+ raise ValueError(f"Must call create_session before calling action hover with element_description='{element_description}'")
222
+
223
+ data = {'element_description': element_description}
224
+
225
+ if cdp_url:
226
+ data['cdp_url'] = cdp_url
227
+ else:
228
+ data['session_id'] = self.session_id
229
+
230
+ response = requests.post(
231
+ f"{BASE_URL}/hover",
232
+ headers={
233
+ 'x-api-key': self.api_key
234
+ },
235
+ data=data
236
+ )
237
+ if 'succeeded' not in response.json():
238
+ raise ValueError(f"It looks like the hover action failed to return a response. Did you set your api_key when creating the Simplex class?")
239
+
240
+ if response.json()["succeeded"]:
241
+ return
242
+ else:
243
+ raise ValueError(f"Failed to hover: {response.json()['error']}")
244
+
225
245
  def type(self, text: str, cdp_url: str = None):
226
246
  if not text or not text.strip():
227
247
  raise ValueError("text cannot be empty")
@@ -242,10 +262,9 @@ class Simplex:
242
262
  },
243
263
  data=data
244
264
  )
245
- if "succeeded" in response.json():
265
+ if response.json()['succeeded']:
246
266
  return
247
267
  else:
248
- print(response.json())
249
268
  raise ValueError(f"Failed to type text: {response.json()['error']}")
250
269
 
251
270
 
@@ -269,7 +288,7 @@ class Simplex:
269
288
  )
270
289
  if 'succeeded' not in response.json():
271
290
  raise ValueError(f"It looks like the reload action failed to return a response. Did you set your api_key when creating the Simplex class?")
272
- if "succeeded" in response.json():
291
+ if response.json()['succeeded']:
273
292
  return
274
293
  else:
275
294
  raise ValueError(f"Failed to reload: {response.json()['error']}")
@@ -294,7 +313,7 @@ class Simplex:
294
313
  )
295
314
  if 'succeeded' not in response.json():
296
315
  raise ValueError(f"It looks like the press_enter action failed to return a response. Did you set your api_key when creating the Simplex class?")
297
- if "succeeded" in response.json():
316
+ if response.json()['succeeded']:
298
317
  return
299
318
  else:
300
319
  raise ValueError(f"Failed to press enter: {response.json()['error']}")
@@ -319,7 +338,7 @@ class Simplex:
319
338
  )
320
339
  if 'succeeded' not in response.json():
321
340
  raise ValueError(f"It looks like the press_tab action failed to return a response. Did you set your api_key when creating the Simplex class?")
322
- if "succeeded" in response.json():
341
+ if response.json()['succeeded']:
323
342
  return
324
343
  else:
325
344
  raise ValueError(f"Failed to press tab: {response.json()['error']}")
@@ -344,7 +363,7 @@ class Simplex:
344
363
  )
345
364
  if 'succeeded' not in response.json():
346
365
  raise ValueError(f"It looks like the delete_text action failed to return a response. Did you set your api_key when creating the Simplex class?")
347
- if "succeeded" in response.json():
366
+ if response.json()['succeeded']:
348
367
  return
349
368
  else:
350
369
  raise ValueError(f"Failed to delete text: {response.json()['error']}")
@@ -371,7 +390,7 @@ class Simplex:
371
390
  )
372
391
  if 'succeeded' not in response.json():
373
392
  raise ValueError(f"It looks like the extract_bbox action failed to return a response. Did you set your api_key when creating the Simplex class?")
374
- if "succeeded" in response.json():
393
+ if response.json()['succeeded']:
375
394
  return response.json()["bbox"]
376
395
  else:
377
396
  raise ValueError(f"Failed to extract bbox: {response.json()['error']}")
@@ -426,7 +445,7 @@ class Simplex:
426
445
  )
427
446
  if 'succeeded' not in response.json():
428
447
  raise ValueError(f"It looks like the extract_image action failed to return a response. Did you set your api_key when creating the Simplex class?")
429
- if "succeeded" in response.json():
448
+ if response.json()['succeeded']:
430
449
  return response.json()["image"]
431
450
  else:
432
451
  raise ValueError(f"Failed to extract image: {response.json()['error']}")
@@ -451,7 +470,7 @@ class Simplex:
451
470
  )
452
471
  if 'succeeded' not in response.json():
453
472
  raise ValueError(f"It looks like the scroll action failed to return a response. Did you set your api_key when creating the Simplex class?")
454
- if "succeeded" in response.json():
473
+ if response.json()['succeeded']:
455
474
  return
456
475
  else:
457
476
  raise ValueError(f"Failed to scroll: {response.json()['error']}")
@@ -476,7 +495,7 @@ class Simplex:
476
495
  )
477
496
  if 'succeeded' not in response.json():
478
497
  raise ValueError(f"It looks like the wait action failed to return a response. Did you set your api_key when creating the Simplex class?")
479
- if "succeeded" in response.json():
498
+ if response.json()['succeeded']:
480
499
  return
481
500
  else:
482
501
  raise ValueError(f"Failed to wait: {response.json()['error']}")
@@ -495,24 +514,23 @@ class Simplex:
495
514
  return netloc.replace(".", "_")
496
515
 
497
516
  with sync_playwright() as p:
498
- context = p.chromium.launch_persistent_context(
517
+ browser = p.chromium.launch(
499
518
  channel="chrome",
500
519
  headless=False,
501
520
  args=[
502
521
  '--disable-blink-features=AutomationControlled',
503
522
  '--disable-automation',
504
523
  ],
505
- ignore_default_args=['--enable-automation'],
506
- user_data_dir="/home/simplex/.config/google-chrome/Profile 1/",
507
- user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
508
- viewport={"width": 1243, "height": 681}
524
+ ignore_default_args=['--enable-automation']
509
525
  )
510
- main_page = context.pages[0]
511
- main_page.goto(url, wait_until="networkidle")
512
-
513
- # # Create control page in same context
526
+ # Create context and pages
527
+ context = browser.new_context(viewport=None)
528
+ main_page = context.new_page()
529
+ main_page.goto(url)
530
+
531
+ # Create control page in same context
514
532
  control_page = context.new_page()
515
- # Use a simple HTML file instead of set_content
533
+ # Use a simple HTML file instead of set_content
516
534
  html_content = """
517
535
  <!DOCTYPE html>
518
536
  <html>
@@ -560,6 +578,7 @@ class Simplex:
560
578
  os.unlink(temp_path)
561
579
  except:
562
580
  pass
581
+
563
582
  # Use context.storage_state() instead of browser.storage_state()
564
583
  storage = context.storage_state()
565
584
  if save_directory:
@@ -572,9 +591,37 @@ class Simplex:
572
591
 
573
592
  print(f"Session data saved to '{filename}'")
574
593
 
575
- context.close()
576
- # return filename
577
-
594
+ browser.close()
595
+
596
+ return filename
597
+
598
+ def get_network_response(self, url: str, cdp_url: str = None):
599
+ print(f"Getting network response for {url}")
600
+ if not cdp_url and not self.session_id:
601
+ raise ValueError(f"Must call create_session before calling action get_network_response with url='{url}'")
602
+
603
+ data = {'url': url}
604
+
605
+ if cdp_url:
606
+ data['cdp_url'] = cdp_url
607
+ else:
608
+ data['session_id'] = self.session_id
609
+
610
+ response = requests.post(
611
+ f"{BASE_URL}/get_network_response",
612
+ headers={
613
+ 'x-api-key': self.api_key
614
+ },
615
+ data=data
616
+ )
617
+
618
+ if 'status' not in response.json():
619
+ raise ValueError(f"It looks like the get_network_response action failed to return a response. Did you set your api_key when creating the Simplex class?")
620
+ if response.json()['status'] == 'success':
621
+ return response.json()['response']
622
+ else:
623
+ raise ValueError(f"Failed to get network response: {response.json()['error']}")
624
+
578
625
  def restore_login_session(self, session_data: str, cdp_url: str = None):
579
626
  """
580
627
  Restore a login session from either a file path or a JSON string.
@@ -611,7 +658,7 @@ class Simplex:
611
658
  )
612
659
  if 'succeeded' not in response.json():
613
660
  raise ValueError(f"It looks like the restore_login_session action failed to return a response. Did you set your api_key when creating the Simplex class?")
614
- if "succeeded" in response.json():
661
+ if response.json()['succeeded']:
615
662
  return
616
663
  else:
617
664
  raise ValueError(f"Failed to restore login session: {response.json()['error']}")
@@ -655,7 +702,7 @@ class Simplex:
655
702
  )
656
703
  if 'succeeded' not in response.json():
657
704
  raise ValueError(f"It looks like the click_and_upload action failed to return a response. Did you set your api_key when creating the Simplex class?")
658
- if "succeeded" in response.json():
705
+ if response.json()['succeeded']:
659
706
  return
660
707
  else:
661
708
  raise ValueError(f"Failed to click and upload: {response.json()['error']}")
@@ -726,7 +773,8 @@ class Simplex:
726
773
  if 'succeeded' not in response.json():
727
774
  raise ValueError(f"It looks like the exists action failed to return a response. Did you set your api_key when creating the Simplex class?")
728
775
  response_json = response.json()
729
- if "succeeded" in response_json:
776
+
777
+ if response_json['succeeded']:
730
778
  return response_json['exists'], response_json['reasoning']
731
779
  else:
732
780
  raise ValueError(f"Failed to check if element exists: {response_json['error']}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.63
3
+ Version: 1.2.65
4
4
  Summary: Official Python SDK for Simplex API
5
5
  Home-page: https://simplex.sh
6
6
  Author: Simplex Labs, Inc.
@@ -0,0 +1,11 @@
1
+ simplex/__init__.py,sha256=L_5i__xt_ZDkr6e-Wx9cr84t9sXpioOT7j01NJYJCTE,75
2
+ simplex/cli.py,sha256=0K_pzoVdF7vfTJPUONhFzzTvjZk2M7FZPpEONjZWJC8,2268
3
+ simplex/simplex.py,sha256=rWS3XpNjAgpLkj05VwZKAJzWMhJT-A5WKp1_x_e4sww,30887
4
+ simplex/deploy/__init__.py,sha256=_JQ81F_Nu7hSAfMA691gzs6a4-8oZ-buJ9h3Au12BKw,96
5
+ simplex/deploy/push.py,sha256=hRAbtFZaECKnBljaOLQ5nzJ6hk7tZgc1c7QdgxKQFoY,6123
6
+ simplex-1.2.65.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
7
+ simplex-1.2.65.dist-info/METADATA,sha256=XriIpgMHUdRrTMAioGI3sZIMtgh15w_b1TZig8C111M,1045
8
+ simplex-1.2.65.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
9
+ simplex-1.2.65.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
10
+ simplex-1.2.65.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
11
+ simplex-1.2.65.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- simplex/__init__.py,sha256=L_5i__xt_ZDkr6e-Wx9cr84t9sXpioOT7j01NJYJCTE,75
2
- simplex/cli.py,sha256=0K_pzoVdF7vfTJPUONhFzzTvjZk2M7FZPpEONjZWJC8,2268
3
- simplex/simplex.py,sha256=iY_zM02VwS6ru2eHUTz1sNnnZ9pdf4Y7XnT6FQJKKgE,29206
4
- simplex/deploy/__init__.py,sha256=_JQ81F_Nu7hSAfMA691gzs6a4-8oZ-buJ9h3Au12BKw,96
5
- simplex/deploy/push.py,sha256=hRAbtFZaECKnBljaOLQ5nzJ6hk7tZgc1c7QdgxKQFoY,6123
6
- simplex-1.2.63.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
7
- simplex-1.2.63.dist-info/METADATA,sha256=gQZ7RVjUwC8Yk6SsxkuvLl4v9ijC3PfuC3Uky8mUmeA,1045
8
- simplex-1.2.63.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
9
- simplex-1.2.63.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
10
- simplex-1.2.63.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
11
- simplex-1.2.63.dist-info/RECORD,,