simplex 1.2.36__tar.gz → 1.2.38__tar.gz

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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.36
3
+ Version: 1.2.38
4
4
  Summary: Official Python SDK for Simplex API
5
5
  Home-page: https://simplex.sh
6
6
  Author: Simplex Labs, Inc.
@@ -17,7 +17,7 @@ class PostInstallCommand(install):
17
17
 
18
18
  setup(
19
19
  name="simplex",
20
- version="1.2.36",
20
+ version="1.2.38",
21
21
  packages=find_packages(),
22
22
  package_data={
23
23
  "simplex": ["browser_agent/dom/*.js"], # Include JS files in the dom directory
@@ -63,13 +63,14 @@ def login(website, proxies):
63
63
  website = 'https://' + website
64
64
 
65
65
  animated_print(f"[SIMPLEX] Creating login session for {website}")
66
- login_session_url = simplex.create_login_session(website, proxies=proxies)
67
-
68
- if login_session_url:
69
- animated_print("[SIMPLEX] Opening login page in your browser")
70
- webbrowser.open_new_tab(login_session_url)
66
+
67
+ fileName = simplex.create_login_session(website)
68
+
69
+ if fileName:
70
+ animated_print(f"[SIMPLEX] Login session created and saved to {fileName}")
71
71
  else:
72
- print(f"{Fore.YELLOW}[SIMPLEX] Warning: No login URL returned from the server{Style.RESET_ALL}")
72
+ print(f"{Fore.YELLOW}[SIMPLEX] Warning: Session data could not be saved{Style.RESET_ALL}")
73
+
73
74
  except Exception as e:
74
75
  raise click.ClickException(str(e))
75
76
 
@@ -1,9 +1,58 @@
1
1
  import requests
2
2
  import atexit
3
3
  from typing import Optional
4
+ from playwright.sync_api import sync_playwright
5
+ import os
6
+ import json
7
+
4
8
  BASE_URL = "https://api.simplex.sh"
5
9
 
6
- import json
10
+ class Playwright:
11
+ def __init__(self, simplex_instance):
12
+ self.simplex = simplex_instance
13
+
14
+ def click(self, locator: str, locator_type: str, exact: Optional[bool] = False,
15
+ element_index: Optional[str] = None, nth_index: Optional[int] = None,
16
+ locator_options: Optional[dict] = None):
17
+
18
+ if element_index and element_index not in ["first", "last", "nth"]:
19
+ raise ValueError("element_index must be 'first', 'last', or 'nth'")
20
+
21
+ if element_index=="nth" and not nth_index:
22
+ raise ValueError("nth_index is required when element_index is 'nth'")
23
+
24
+ data = {
25
+ 'session_id': self.simplex.session_id,
26
+ 'locator': locator,
27
+ 'locator_type': locator_type,
28
+ }
29
+
30
+ if element_index:
31
+ data['element_index'] = element_index
32
+ data['nth_index'] = nth_index
33
+
34
+ if exact:
35
+ data['exact'] = exact
36
+
37
+ if locator_options:
38
+ data['locator_options'] = json.dumps(locator_options)
39
+
40
+ response = requests.post(
41
+ f"{BASE_URL}/playwright/click",
42
+ headers={
43
+ 'x-api-key': self.simplex.api_key
44
+ },
45
+ data=data
46
+ )
47
+
48
+ if 'succeeded' not in response.json():
49
+ print(response.json())
50
+ 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?")
51
+
52
+ if response.json()["succeeded"]:
53
+ return
54
+ else:
55
+ raise ValueError(f"Failed to click element: {response.json()['error']}")
7
56
 
8
57
  class Simplex:
9
58
  def __init__(self, api_key: str):
@@ -11,6 +60,8 @@ class Simplex:
11
60
  self.session_id = None
12
61
  atexit.register(self.close_session)
13
62
 
63
+ self.playwright = Playwright(self)
64
+
14
65
  def close_session(self):
15
66
  if not self.session_id:
16
67
  return
@@ -30,13 +81,33 @@ class Simplex:
30
81
  raise ValueError(f"Failed to close session: {response.json()['error']}")
31
82
 
32
83
  def create_session(self, show_in_console: Optional[bool] = True, proxies: Optional[bool] = True, session_data: Optional[str] = None):
33
- response = requests.post(
34
- f"{BASE_URL}/create_session",
35
- headers={
36
- 'x-api-key': self.api_key
37
- },
38
- data={'proxies': proxies, 'session_data': session_data}
39
- )
84
+ if session_data:
85
+ try:
86
+ # Try to parse as JSON string first
87
+ session_data_dict = json.loads(session_data)
88
+ except json.JSONDecodeError:
89
+ # If parsing fails, treat as file path
90
+ try:
91
+ with open(session_data, 'r') as f:
92
+ session_data_dict = json.load(f)
93
+ except Exception as e:
94
+ raise ValueError(f"Failed to load session data. Input must be valid JSON string or path to JSON file. Error: {str(e)}")
95
+ print(session_data_dict)
96
+ response = requests.post(
97
+ f"{BASE_URL}/create_session",
98
+ headers={
99
+ 'x-api-key': self.api_key
100
+ },
101
+ data={'proxies': proxies, 'session_data': json.dumps(session_data_dict)}
102
+ )
103
+ else:
104
+ response = requests.post(
105
+ f"{BASE_URL}/create_session",
106
+ headers={
107
+ 'x-api-key': self.api_key
108
+ },
109
+ data={'proxies': proxies}
110
+ )
40
111
  # Check for non-200 status code
41
112
  if response.status_code != 200:
42
113
  raise ValueError(f"Create session request failed with status code {response.status_code}: {response.text}")
@@ -50,7 +121,7 @@ class Simplex:
50
121
  if show_in_console:
51
122
  print(f"Livestream URL: {livestream_url}")
52
123
 
53
- return livestream_url
124
+ return self.session_id, livestream_url
54
125
 
55
126
  def goto(self, url: str, cdp_url: str = None):
56
127
  if not cdp_url and not self.session_id:
@@ -240,12 +311,12 @@ class Simplex:
240
311
  else:
241
312
  data['session_id'] = self.session_id
242
313
 
243
- response = requests.get(
314
+ response = requests.post(
244
315
  f"{BASE_URL}/extract-text",
245
316
  headers={
246
317
  'x-api-key': self.api_key
247
318
  },
248
- params=data
319
+ data=data
249
320
  )
250
321
  if 'succeeded' not in response.json():
251
322
  raise ValueError(f"It looks like the extract_text action failed to return a response. Did you set your api_key when creating the Simplex class?")
@@ -329,20 +400,78 @@ class Simplex:
329
400
  else:
330
401
  raise ValueError(f"Failed to wait: {response.json()['error']}")
331
402
 
332
- def create_login_session(self, url: str, proxies: Optional[bool] = True):
333
- response = requests.post(
334
- f"{BASE_URL}/create_login_session",
335
- headers={
336
- 'x-api-key': self.api_key
337
- },
338
- data={'url': url, 'proxies': proxies}
339
- )
340
- if 'succeeded' not in response.json():
341
- raise ValueError(f"It looks like the create_login_session action failed to return a response. Did you set your api_key when creating the Simplex class?")
342
- if response.json()["succeeded"]:
343
- return response.json()["login_session_url"]
344
- else:
345
- raise ValueError(f"Failed to create login session: {response.json()['error']}")
403
+ def create_login_session(self, url: str, save_directory: Optional[str] = None):
404
+ def get_website_name(url: str) -> str:
405
+ """Extract website name from URL"""
406
+ from urllib.parse import urlparse
407
+ netloc = urlparse(url).netloc
408
+ # Remove www. if present
409
+ if netloc.startswith('www.'):
410
+ netloc = netloc[4:]
411
+ return netloc.replace(".", "_")
412
+
413
+ with sync_playwright() as p:
414
+ browser = p.chromium.launch(
415
+ channel="chrome",
416
+ headless=False,
417
+ args=[
418
+ '--disable-blink-features=AutomationControlled',
419
+ '--disable-automation',
420
+ ],
421
+ ignore_default_args=['--enable-automation']
422
+ )
423
+
424
+ # Create context and pages
425
+ context = browser.new_context()
426
+ main_page = context.new_page()
427
+ main_page.goto(url)
428
+
429
+ # Create control page in same context
430
+ control_page = context.new_page()
431
+ control_page.set_content("""
432
+ <html>
433
+ <body style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f5f5f5;">
434
+ <button id="capture-btn" style="
435
+ padding: 20px 40px;
436
+ font-size: 18px;
437
+ cursor: pointer;
438
+ background-color: #2196F3;
439
+ color: white;
440
+ border: none;
441
+ border-radius: 5px;
442
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
443
+ ">Click here when logged in to capture session</button>
444
+ </body>
445
+ </html>
446
+ """)
447
+
448
+ # Wait for button click using Playwright's wait_for_event
449
+ control_page.wait_for_selector('#capture-btn')
450
+ control_page.evaluate("""
451
+ () => {
452
+ return new Promise((resolve) => {
453
+ document.getElementById('capture-btn').onclick = () => {
454
+ resolve(true);
455
+ }
456
+ });
457
+ }
458
+ """)
459
+
460
+ # Use context.storage_state() instead of browser.storage_state()
461
+ storage = context.storage_state()
462
+ if save_directory:
463
+ filename = os.path.join(save_directory, get_website_name(url) + "_session_data.json")
464
+ else:
465
+ filename = get_website_name(url) + "_session_data.json"
466
+
467
+ with open(filename, 'w') as f:
468
+ json.dump(storage, f, indent=2)
469
+
470
+ print(f"Session data saved to '{filename}'")
471
+
472
+ browser.close()
473
+
474
+ return filename
346
475
 
347
476
  def restore_login_session(self, session_data: str, cdp_url: str = None):
348
477
  """
@@ -462,4 +591,4 @@ class Simplex:
462
591
  if response_json['succeeded']:
463
592
  return response_json['exists'], response_json['reasoning']
464
593
  else:
465
- raise ValueError(f"Failed to check if element exists: {response_json['error']}")
594
+ 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.36
3
+ Version: 1.2.38
4
4
  Summary: Official Python SDK for Simplex API
5
5
  Home-page: https://simplex.sh
6
6
  Author: Simplex Labs, Inc.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes