simplex 1.2.35__tar.gz → 1.2.36__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
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.35
3
+ Version: 1.2.36
4
4
  Summary: Official Python SDK for Simplex API
5
5
  Home-page: https://simplex.sh
6
6
  Author: Simplex Labs, Inc.
@@ -17,6 +17,16 @@ Requires-Dist: colorama
17
17
  Requires-Dist: requests
18
18
  Requires-Dist: python-dotenv
19
19
  Requires-Dist: click
20
+ Requires-Dist: playwright
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
20
30
 
21
31
  # Simplex AI Python SDK
22
32
 
@@ -1,8 +1,23 @@
1
1
  from setuptools import setup, find_packages
2
+ from setuptools.command.develop import develop
3
+ from setuptools.command.install import install
4
+ from subprocess import check_call
5
+
6
+ class PostDevelopCommand(develop):
7
+ """Post-installation for development mode."""
8
+ def run(self):
9
+ develop.run(self)
10
+ check_call(["playwright", "install"])
11
+
12
+ class PostInstallCommand(install):
13
+ """Post-installation for installation mode."""
14
+ def run(self):
15
+ install.run(self)
16
+ check_call(["playwright", "install"])
2
17
 
3
18
  setup(
4
19
  name="simplex",
5
- version="1.2.35",
20
+ version="1.2.36",
6
21
  packages=find_packages(),
7
22
  package_data={
8
23
  "simplex": ["browser_agent/dom/*.js"], # Include JS files in the dom directory
@@ -12,7 +27,12 @@ setup(
12
27
  "requests",
13
28
  "python-dotenv",
14
29
  "click",
30
+ "playwright",
15
31
  ],
32
+ cmdclass={
33
+ 'develop': PostDevelopCommand,
34
+ 'install': PostInstallCommand,
35
+ },
16
36
  entry_points={
17
37
  'console_scripts': [
18
38
  'simplex=simplex.cli:main',
@@ -63,14 +63,13 @@ def login(website, proxies):
63
63
  website = 'https://' + website
64
64
 
65
65
  animated_print(f"[SIMPLEX] Creating login session for {website}")
66
-
67
- fileName = simplex.create_login_session(website, proxies=proxies)
68
-
69
- if fileName:
70
- animated_print(f"[SIMPLEX] Login session created and saved to {fileName}")
71
- else:
72
- print(f"{Fore.YELLOW}[SIMPLEX] Warning: Session data could not be saved{Style.RESET_ALL}")
66
+ login_session_url = simplex.create_login_session(website, proxies=proxies)
73
67
 
68
+ if login_session_url:
69
+ animated_print("[SIMPLEX] Opening login page in your browser")
70
+ webbrowser.open_new_tab(login_session_url)
71
+ else:
72
+ print(f"{Fore.YELLOW}[SIMPLEX] Warning: No login URL returned from the server{Style.RESET_ALL}")
74
73
  except Exception as e:
75
74
  raise click.ClickException(str(e))
76
75
 
@@ -1,60 +1,9 @@
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
-
8
4
  BASE_URL = "https://api.simplex.sh"
9
5
 
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']}")
56
-
57
-
6
+ import json
58
7
 
59
8
  class Simplex:
60
9
  def __init__(self, api_key: str):
@@ -62,8 +11,6 @@ class Simplex:
62
11
  self.session_id = None
63
12
  atexit.register(self.close_session)
64
13
 
65
- self.playwright = Playwright(self)
66
-
67
14
  def close_session(self):
68
15
  if not self.session_id:
69
16
  return
@@ -82,18 +29,18 @@ class Simplex:
82
29
  else:
83
30
  raise ValueError(f"Failed to close session: {response.json()['error']}")
84
31
 
85
- def create_session(self, show_in_console: Optional[bool] = True, proxies: Optional[bool] = True):
32
+ def create_session(self, show_in_console: Optional[bool] = True, proxies: Optional[bool] = True, session_data: Optional[str] = None):
86
33
  response = requests.post(
87
34
  f"{BASE_URL}/create_session",
88
35
  headers={
89
36
  'x-api-key': self.api_key
90
37
  },
91
- data={'proxies': proxies}
38
+ data={'proxies': proxies, 'session_data': session_data}
92
39
  )
93
40
  # Check for non-200 status code
94
41
  if response.status_code != 200:
95
42
  raise ValueError(f"Create session request failed with status code {response.status_code}: {response.text}")
96
-
43
+
97
44
  response_json = response.json()
98
45
  if 'session_id' not in response_json:
99
46
  raise ValueError(f"It looks like the session wasn't created successfully. Did you set your api_key when creating the Simplex class?")
@@ -382,81 +329,20 @@ class Simplex:
382
329
  else:
383
330
  raise ValueError(f"Failed to wait: {response.json()['error']}")
384
331
 
385
- def create_login_session(self, url: str, save_directory: Optional[str] = None, proxies: Optional[bool] = True):
386
- def get_website_name(url: str) -> str:
387
- """Extract website name from URL"""
388
- from urllib.parse import urlparse
389
- netloc = urlparse(url).netloc
390
- # Remove www. if present
391
- if netloc.startswith('www.'):
392
- netloc = netloc[4:]
393
- return netloc.replace(".", "_")
394
-
395
- with sync_playwright() as p:
396
- browser = p.chromium.launch_persistent_context(
397
- user_data_dir="",
398
- channel="chrome",
399
- headless=False,
400
- args=[
401
- '--disable-blink-features=AutomationControlled',
402
- '--disable-automation',
403
- ],
404
- ignore_default_args=['--enable-automation']
405
- )
406
-
407
- # Close the default about:blank page
408
- if len(browser.pages) > 0:
409
- browser.pages[0].close()
410
-
411
- # Create main page for login
412
- main_page = browser.new_page()
413
- main_page.goto(url)
414
-
415
- # Create control page
416
- control_page = browser.new_page()
417
- control_page.set_content("""
418
- <html>
419
- <body style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #f5f5f5;">
420
- <button id="capture-btn" style="
421
- padding: 20px 40px;
422
- font-size: 18px;
423
- cursor: pointer;
424
- background-color: #2196F3;
425
- color: white;
426
- border: none;
427
- border-radius: 5px;
428
- box-shadow: 0 2px 4px rgba(0,0,0,0.2);
429
- ">Click here when logged in to capture session</button>
430
- </body>
431
- </html>
432
- """)
433
-
434
- # Wait for button click using Playwright's wait_for_event
435
- control_page.wait_for_selector('#capture-btn')
436
- control_page.evaluate("""
437
- () => {
438
- return new Promise((resolve) => {
439
- document.getElementById('capture-btn').onclick = () => {
440
- resolve(true);
441
- }
442
- });
443
- }
444
- """)
445
-
446
- storage = browser.storage_state()
447
- if save_directory:
448
- filename = os.path.join(save_directory, get_website_name(url) + "_session_data.json")
449
- else:
450
- filename = get_website_name(url) + "_session_data.json"
451
-
452
- with open(filename, 'w') as f:
453
- json.dump(storage, f, indent=2)
454
-
455
- print(f"Session data saved to '{filename}'")
456
-
457
- browser.close()
458
-
459
- return filename
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']}")
460
346
 
461
347
  def restore_login_session(self, session_data: str, cdp_url: str = None):
462
348
  """
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.35
3
+ Version: 1.2.36
4
4
  Summary: Official Python SDK for Simplex API
5
5
  Home-page: https://simplex.sh
6
6
  Author: Simplex Labs, Inc.
@@ -17,6 +17,16 @@ Requires-Dist: colorama
17
17
  Requires-Dist: requests
18
18
  Requires-Dist: python-dotenv
19
19
  Requires-Dist: click
20
+ Requires-Dist: playwright
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
20
30
 
21
31
  # Simplex AI Python SDK
22
32
 
@@ -2,3 +2,4 @@ colorama
2
2
  requests
3
3
  python-dotenv
4
4
  click
5
+ playwright
@@ -0,0 +1,75 @@
1
+ from simplex import Simplex
2
+ import os
3
+ from dotenv import load_dotenv
4
+ import time
5
+ from playwright.async_api import Page
6
+
7
+ load_dotenv()
8
+
9
+ def login():
10
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
11
+ simplex.create_session(proxies=True)
12
+ simplex.goto("https://bill.com")
13
+
14
+ simplex.wait(100000)
15
+
16
+ import asyncio
17
+ from playwright.async_api import async_playwright
18
+ from hyperbrowser import AsyncHyperbrowser
19
+ from hyperbrowser.models.session import CreateSessionParams, ScreenConfig
20
+ import os
21
+ import dotenv
22
+
23
+ dotenv.load_dotenv()
24
+
25
+ async def main():
26
+ client = AsyncHyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
27
+ # Create a session and connect to it using Pyppeteer
28
+ session = await client.sessions.create(
29
+ params=CreateSessionParams(
30
+ use_stealth=True,
31
+ use_proxy=True,
32
+ operating_systems=["macos"],
33
+ device=["desktop"],
34
+ locales=["en"],
35
+ )
36
+ )
37
+ print(session.live_url)
38
+ async with async_playwright() as p:
39
+
40
+ browser = await p.chromium.connect_over_cdp(session.ws_endpoint)
41
+
42
+ # Create context with permissions
43
+ context = await browser.new_context(
44
+ )
45
+ import json
46
+ page = await context.new_page()
47
+
48
+ session_data = json.load(open("bill_session.json"))
49
+ await page.goto("https://bill.com")
50
+ await restore_session_data(page, session_data)
51
+ await page.wait_for_timeout(10000000)
52
+
53
+ async def restore_session_data(page: Page, session_data: dict):
54
+ # First set cookies
55
+ if 'cookies' in session_data:
56
+ await page.context.add_cookies(session_data['cookies'])
57
+
58
+ # Now set localStorage
59
+ if 'localStorage' in session_data:
60
+ for key, value in session_data['localStorage'].items():
61
+ await page.evaluate("""({ key, value }) => {
62
+ localStorage.setItem(key, value);
63
+ }""", {"key": key, "value": value})
64
+
65
+ # Set sessionStorage
66
+ if 'sessionStorage' in session_data:
67
+ for key, value in session_data['sessionStorage'].items():
68
+ await page.evaluate("""({ key, value }) => {
69
+ sessionStorage.setItem(key, value);
70
+ }""", {"key": key, "value": value})
71
+ print("restored")
72
+
73
+ if __name__ == "__main__":
74
+ asyncio.run(main())
75
+
@@ -1,22 +0,0 @@
1
- from simplex import Simplex
2
- import os
3
- from dotenv import load_dotenv
4
- import time
5
-
6
- load_dotenv()
7
-
8
- def login():
9
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
10
- simplex.create_session(proxies=False)
11
- simplex.goto("https://dropbox.com")
12
-
13
- with open("dropbox_com_session_data.json", "r") as f:
14
- session_data = f.read()
15
- simplex.restore_login_session(session_data=session_data)
16
-
17
- simplex.wait(1000)
18
- print(simplex.extract_text("footer texts"))
19
- print(simplex.wait(5000))
20
-
21
- if __name__ == "__main__":
22
- login()
File without changes
File without changes
File without changes
File without changes
File without changes