diff --git a/LICENSE b/LICENSE index d0ce461..2bbeabd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2023 Vladislav Zenkevich +Copyright (c) 2024 Vladislav Zenkevich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in index 6d5cf82..75e1aa5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ include README.MD include LICENSE -include selenium_dolphin/api.py -include selenium_dolphin/utils.py \ No newline at end of file +include pyanty/api.py +include pyanty/utils.py \ No newline at end of file diff --git a/README.MD b/README.MD index 1810ddd..1415779 100644 --- a/README.MD +++ b/README.MD @@ -1,6 +1,6 @@ -# 🐬 selenium-dolphin +# 🐬 pyanty -A Python module for controlling Dolphin browser profiles using Selenium or Pyppeteer 🤖. It also has a Dolphin API for creating, editing, and deleting profiles. +Python module for controlling Dolphin browser profiles using Selenium, Pyppeteer, and Playwright. Includes Dolphin API for profile management. ## ⚠️ Warning! @@ -14,9 +14,8 @@ Selenium and some features working only if Dolphin Anty is opened!!! (Local API ```python import random -import selenium_dolphin as dolphin -from selenium_dolphin import DolphinAPI, STABLE_CHROME_VERSION -from selenium.webdriver.chrome.options import Options +import pyanty as dolphin +from pyanty import DolphinAPI, STABLE_CHROME_VERSION api = DolphinAPI(api_key='Your Api Key') @@ -37,12 +36,7 @@ profile_id = api.create_profile(data)['browserProfileId'] response = dolphin.run_profile(profile_id) port = response['automation']['port'] -##### custom chrome options demonstration ##### -options = Options() -options.add_argument("--start-maximized") -############################################### - -driver = dolphin.get_driver(options=options, port=port) +driver = dolphin.get_driver(port=port) driver.get('https://google.com/') print(driver.title) driver.quit() @@ -55,8 +49,8 @@ dolphin.close_profile(profile_id) ```python import asyncio import random -import selenium_dolphin as dolphin -from selenium_dolphin import DolphinAPI, STABLE_CHROME_VERSION +import pyanty as dolphin +from pyanty import DolphinAPI, STABLE_CHROME_VERSION api = DolphinAPI(api_key='Your Api Key') @@ -90,10 +84,50 @@ asyncio.run(main()) dolphin.close_profile(profile_id) ``` +### Pyppeteer + +```python +import asyncio +import random +import pyanty as dolphin +from pyanty import DolphinAPI, STABLE_CHROME_VERSION + +api = DolphinAPI(api_key='Your Api Key') + +response = api.get_profiles() +if response['data']: + profile_id = response['data'][-1]['id'] + if profile_id: + api.delete_profiles([profile_id]) + +fingerprint = [] +while not fingerprint: + fingerprint = api.generate_fingerprint(platform='windows', browser_version=f'{random.randint(114, STABLE_CHROME_VERSION)}') + +data = api.fingerprint_to_profile(name='my superprofile', fingerprint=fingerprint) + +profile_id = api.create_profile(data)['browserProfileId'] + +response = dolphin.run_profile(profile_id) +port = response['automation']['port'] +ws_endpoint = response['automation']['wsEndpoint'] + +async def main(): + browser = await dolphin.get_browser(ws_endpoint, port, core='playwright') + pages = await browser.pages() + page = pages[0] + await page.goto('http://google.com/') + await asyncio.sleep(5) + await browser.disconnect() + +asyncio.run(main()) +dolphin.close_profile(profile_id) +``` + ## 📝 Get profiles ```python -from selenium_dolphin import DolphinAPI +from pyanty import DolphinAPI api = DolphinAPI() # you can enter api_key='Your key' inside instance ``` @@ -117,7 +151,7 @@ response = api.get_profiles(page=1, limit=300) # default page - 1 limit - 50 ```python fingerprint = api.generate_fingerprint(platform='linux') # you can use platform windows/linux/macos, also you can use screen='1366x768' and browser_version='116' if you need -data = api.fingerprint_to_profile(name='my profile', fingerprint=fingerprint) # also you can add tags=['test', 'selenium_dolphin'] and other +data = api.fingerprint_to_profile(name='my profile', fingerprint=fingerprint) # also you can add tags=['test', 'pyanty'] and other response = api.create_profile(data) @@ -180,7 +214,7 @@ data.update({'proxy':{ ## ✏️ Edit profile ```python -from selenium_dolphin import DolphinAPI +from pyanty import DolphinAPI api = DolphinAPI() @@ -196,7 +230,7 @@ print(response) ## 🗑️ Delete profile(s) ```python -from selenium_dolphin import DolphinAPI +from pyanty import DolphinAPI api = DolphinAPI() @@ -205,6 +239,46 @@ response = api.delete_profiles([190438486]) # you need specify list ids of profi print(response) ``` +## 🧩 Using Extensions + +### Get extensions + +```python +response = api.get_extensions() + +print(response) +``` + +### Pagination and limitation + +```python +response = api.get_extensions(page=1, limit=300) # default page - 1 limit - 50 +``` + +## 🏪 Load from Chrome Extensions Store + +```python +response = api.load_extension_from_url('https://chromewebstore.google.com/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm') + +print(response) +``` + +## 📦 Load from ZIP Archive + +```python +response = api.load_extension_from_zip(extension_name='Test', path='path/to/archive.zip') + +print(response) +``` + +## 🗑️ Delete extension(s) + +```python +response = api.delete_extensions([63654]) # you need specify list ids of profiles + +print(response) +``` + ## 🔍 Other features ### Proxy checker @@ -239,4 +313,4 @@ Response: ## Conclusion -selenium-dolphin provides a straightforward way to control Dolphin browser profiles for automation testing using Selenium or Pyppeteer 🤖. With the Dolphin API, you can easily create, customize, and manage profiles right from Python. Give it a try for your next web scraping or test automation project! 🐬 \ No newline at end of file +pyanty provides a straightforward way to control Dolphin browser profiles for automation testing using Selenium, Pyppeteer or Playwright 🤖. With the Dolphin API, you can easily create, customize, and manage profiles right from Python. Give it a try for your next web scraping or test automation project! 🐬 \ No newline at end of file diff --git a/selenium_dolphin/__init__.py b/pyanty/__init__.py similarity index 60% rename from selenium_dolphin/__init__.py rename to pyanty/__init__.py index 3e5a5d4..a66629c 100644 --- a/selenium_dolphin/__init__.py +++ b/pyanty/__init__.py @@ -1,2 +1,2 @@ -from .selenium_dolphin import * +from .pyanty import * from .api import DolphinAPI, STABLE_CHROME_VERSION \ No newline at end of file diff --git a/selenium_dolphin/api.py b/pyanty/api.py similarity index 84% rename from selenium_dolphin/api.py rename to pyanty/api.py index 719afd1..50e5e26 100644 --- a/selenium_dolphin/api.py +++ b/pyanty/api.py @@ -42,6 +42,55 @@ def get_profiles(self, page=1, limit=50): except: raise RuntimeError(r.text) + + def get_extensions(self, page=1, limit=50): + r = self.s.get( + f'https://api.dolphin-anty-ru.online/extensions?page={page}&limit={limit}') + try: + return r.json() + except: + raise RuntimeError(r.text) + + def load_extension_from_url(self, url): + r = self.s.post( + f'https://api.dolphin-anty-ru.online/extensions', json={ + 'url': url, + 'sharedToEntireTeam': False, + 'mainWebsite': ['all'] + }) + try: + return r.json() + except: + raise RuntimeError(r.text) + + def load_extension_from_zip(self, extension_name, path): + with open(path, 'rb') as file: + files = {'file': ('a.zip', file, 'application/x-zip-compressed')} + data = { + 'extensionName': extension_name, + 'sharedToEntireTeam': '0', + 'mainWebsite[]': 'all' + } + r = self.s.post( + f'https://api.dolphin-anty-ru.online/extensions/upload-zipped', + files=files, + data=data + ) + try: + return r.json() + except: + raise RuntimeError(r.text) + + def delete_extensions(self, ids): + r = self.s.delete( + f'https://api.dolphin-anty-ru.online/extensions', json={ + "ids": ids + }) + try: + return r.json() + except: + raise RuntimeError(r.text) + def create_profile(self, data): r = self.s.post( 'https://dolphin-anty-api.com/browser_profiles', json=data) diff --git a/selenium_dolphin/selenium_dolphin.py b/pyanty/pyanty.py similarity index 85% rename from selenium_dolphin/selenium_dolphin.py rename to pyanty/pyanty.py index 0100ef6..b36f29e 100644 --- a/selenium_dolphin/selenium_dolphin.py +++ b/pyanty/pyanty.py @@ -5,10 +5,21 @@ import zipfile import shutil import platform + from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options -from pyppeteer import connect + +try: + from pyppeteer import connect +except: + print('Warning! To work with pyppeteer.\n You need install it with: pip install pyppeteer') + +try: + from playwright.async_api import async_playwright +except: + print('Warning! To work with playwright.\n You need install it with: pip install playwright') + from .utils import collect_garbage if sys.platform == 'win32': @@ -114,7 +125,7 @@ def select_driver_executable(system, architecture): return executable_name -def get_driver(options=Options(), port=9222): +def get_driver(port=9222): system = platform.system() architecture = platform.machine() driver_path = select_driver_executable(system, architecture) @@ -124,18 +135,31 @@ def get_driver(options=Options(), port=9222): unzip_driver_from_memory(driver_content) driver_path = select_driver_executable(system, architecture) + options = Options() options.add_experimental_option('debuggerAddress', f'127.0.0.1:{port}') driver = webdriver.Chrome(service=Service(driver_path), options=options) return driver -async def get_browser(ws_endpoint, port): - browser = await connect(browserWSEndpoint=f'ws://127.0.0.1:{port}{ws_endpoint}') - pages = await browser.pages() - page = pages[0] +async def get_browser(ws_endpoint, port, core='pyppeteer'): + if core == 'pyppeteer': + browser = await connect(browserWSEndpoint=f'ws://127.0.0.1:{port}{ws_endpoint}') + pages = await browser.pages() + page = pages[0] - await page.bringToFront() - return browser + await page.bringToFront() + return browser + + elif core == 'playwright': + p = await async_playwright().start() + browser = await p.chromium.connect_over_cdp(f'ws://127.0.0.1:{port}{ws_endpoint}') + context = browser.contexts[0] + page = context.pages[0] + + await page.bring_to_front() + return browser + else: + raise ValueError(f'{core} is unsupported!') if sys.platform == 'win32': diff --git a/selenium_dolphin/utils.py b/pyanty/utils.py similarity index 100% rename from selenium_dolphin/utils.py rename to pyanty/utils.py diff --git a/setup.py b/setup.py index da43663..bb98fba 100644 --- a/setup.py +++ b/setup.py @@ -4,21 +4,22 @@ with open('README.md', 'r', encoding='utf-8') as f: long_description = f.read() -install_requires = ['requests', 'selenium', 'pyppeteer'] +install_requires = ['requests', 'selenium'] + if sys.platform == 'win32': install_requires.append('pywinauto') setup( - name='selenium_dolphin', - version='1.0.6', + name='pyanty', + version='1.0.0', author='Maehdakvan', author_email='visitanimation@google.com', - description='A Python module for controlling Dolphin browser profiles using Selenium/Pyppeteer. It also has a Dolphin API for creating, editing, and deleting profiles.', + description='Python module for controlling Dolphin browser profiles using Selenium, Pyppeteer, and Playwright. Includes Dolphin API for profile management.', long_description=long_description, long_description_content_type='text/markdown', - url='https://github.com/DedInc/selenium_dolphin', + url='https://github.com/DedInc/pyanty', project_urls={ - 'Bug Tracker': 'https://github.com/DedInc/selenium_dolphin/issues', + 'Bug Tracker': 'https://github.com/DedInc/pyanty/issues', }, classifiers=[ 'Programming Language :: Python :: 3',