Psing login
Deprecated
Pricing
Pay per usage
Go to Store
Psing login
Deprecated
Psing login
0.0 (0)
Pricing
Pay per usage
0
Total users
1
Monthly users
1
Last modified
8 months ago
.actor/Dockerfile
# Use Apify base image with Python and PlaywrightFROM apify/actor-python-playwright
# Copy all source code to the default working directoryCOPY ./src /app
# Install Python dependenciesRUN pip install requests
# Run the actor scriptCMD ["python", "/app/main.py"]
.actor/actor.json
{ "name": "my-actor", "version": "0.1", "description": "This is my Apify actor for login automation.", "actorSpecification": 1, "input": "./input_schema.json", "main": "src/main.py"}
.actor/input_schema.json
{ "schemaVersion": 1, "title": "My Actor Input Schema", "type": "object", "properties": { "start_url": { "type": "string", "title": "Start URL", "description": "The URL to start the scraping process.", "editor": "textfield" }, "company_id": { "type": "string", "title": "Company ID", "description": "ID of the company.", "editor": "textfield" }, "username": { "type": "string", "title": "Username", "description": "Username for login.", "editor": "textfield" }, "password": { "type": "string", "title": "Password", "description": "Password for login.", "editor": "textfield" }, "patient_id": { "type": "string", "title": "Patient ID", "description": "ID of the patient.", "editor": "textfield" }, "type_id": { "type": "string", "title": "Type ID", "description": "ID for the appointment type.", "editor": "textfield" }, "user_id": { "type": "string", "title": "User ID", "description": "ID of the user making the appointment.", "editor": "textfield" }, "reason": { "type": "string", "title": "Reason", "description": "Reason for the appointment.", "editor": "textfield" }, "room": { "type": "string", "title": "Room", "description": "Room number for the appointment.", "editor": "textfield" }, "appointment_date": { "type": "string", "title": "Appointment Date", "description": "Date of the appointment.", "editor": "datepicker" }, "time": { "type": "string", "title": "Appointment Start Time", "description": "Start time of the appointment.", "editor": "textfield" }, "time_end": { "type": "string", "title": "Appointment End Time", "description": "End time of the appointment.", "editor": "textfield" }, "useRealEndTime": { "type": "boolean", "title": "Use Real End Time", "description": "Whether to use the real end time for the appointment.", "editor": "checkbox", "default": true } }, "required": ["start_url", "username", "password", "patient_id", "type_id", "user_id", "reason", "room", "appointment_date", "time", "time_end", "useRealEndTime"]}
src/__main__.py
1import asyncio2from .main import main3
4# Execute the Actor entry point5asyncio.run(main())
src/main.py
1import logging2import json3import asyncio4import requests5from playwright.async_api import async_playwright6from apify import Actor # Import the Actor module7
8logging.basicConfig(level=logging.INFO)9
10async def main():11 # Initialize the actor12 await Actor.init()13
14 # Load input parameters from Apify input15 actor_input = await Actor.get_input() or {}16
17 # Log the input data for debugging18 logging.info(f'Input data: {actor_input}')19 20 # Extract input parameters from the input JSON21 start_url = actor_input.get('start_url')22 company_id = actor_input.get('company_id')23 username = actor_input.get('username')24 password = actor_input.get('password')25 appointment_details = {26 'patient_id': actor_input.get('patient_id'),27 'type_id': actor_input.get('type_id'),28 'user_id': actor_input.get('user_id'),29 'reason': actor_input.get('reason'),30 'room': actor_input.get('room'),31 'appointment_date': actor_input.get('appointment_date'),32 'time': actor_input.get('time'),33 'time_end': actor_input.get('time_end'),34 'useRealEndTime': actor_input.get('useRealEndTime')35 }36
37 # Log extracted appointment details38 logging.info(f'Appointment Details: {appointment_details}')39
40 # Ensure all input fields have values, raise an error if any critical field is missing41 if not all([start_url, company_id, username, password, appointment_details['patient_id'], 42 appointment_details['type_id'], appointment_details['user_id'], 43 appointment_details['reason'], appointment_details['room'], 44 appointment_details['appointment_date'], appointment_details['time'], 45 appointment_details['time_end']]):46 logging.error("Missing required input fields!")47 return48
49 async with async_playwright() as p:50 browser = await p.chromium.launch(headless=True)51 context = await browser.new_context()52 page = await context.new_page()53
54 # Initialize variables to hold request headers55 sec_ch_ua = None56 sec_ch_ua_mobile = None57
58 # Capture request headers when a request is made59 def extract_headers(headers):60 nonlocal sec_ch_ua, sec_ch_ua_mobile61 sec_ch_ua = headers.get('sec-ch-ua')62 sec_ch_ua_mobile = headers.get('sec-ch-ua-mobile')63
64 page.on('request', lambda request: extract_headers(request.headers))65
66 logging.info(f'Navigating to {start_url}...')67 await page.goto(start_url)68
69 # Fill in the login form70 await page.fill('#company_id', company_id)71 await page.fill('#username', username)72 await page.fill('#password', password)73 await page.click('#btnLogin')74
75 # Wait for navigation to the dashboard76 await page.wait_for_url('**/dashboard', timeout=15000)77 logging.info('Login successful! On the dashboard page.')78
79 # Extract cookies80 cookies = await context.cookies()81 logging.info(f'Cookies: {cookies}')82 cookie_string = "; ".join([f"{cookie['name']}={cookie['value']}" for cookie in cookies])83 logging.info(f'Cookie String: {cookie_string}')84
85 # Extract XSRF token86 xsrf_token = next((cookie['value'] for cookie in cookies if cookie['name'] == 'XSRF-TOKEN'), None)87 logging.info(f'XSRF Token: {xsrf_token}')88
89 # Extract user agent90 user_agent = await page.evaluate("() => navigator.userAgent")91 logging.info(f'User Agent: {user_agent}')92
93 # Log sec-ch-ua and sec-ch-ua-mobile94 logging.info(f'SEC-CH-UA: {sec_ch_ua}')95 logging.info(f'SEC-CH-UA-Mobile: {sec_ch_ua_mobile}')96
97 # Prepare the request headers dynamically98 request_url = 'https://us.idexxneo.com/appointments/create'99 headers = {100 'accept': 'application/json, text/plain, */*',101 'accept-encoding': 'gzip, deflate, br, zstd',102 'accept-language': 'en-GB,en;q=0.9',103 'cookie': cookie_string,104 'origin': 'https://us.idexxneo.com',105 'referer': 'https://us.idexxneo.com/schedule/appointments/new?date=' + appointment_details['appointment_date'] + '&time=' + appointment_details['time'],106 'sec-ch-ua': sec_ch_ua if sec_ch_ua else '',107 'sec-ch-ua-mobile': sec_ch_ua_mobile if sec_ch_ua_mobile else '',108 'sec-fetch-dest': 'empty',109 'sec-fetch-mode': 'cors',110 'sec-fetch-site': 'same-origin',111 'sec-gpc': '1',112 'user-agent': user_agent,113 'x-neo-core-version': '87.0.0',114 'x-xsrf-token': xsrf_token115 }116
117 # Adjust form data to use 'files' for multipart data118 files = {119 'patient_id': (None, appointment_details['patient_id']),120 'type_id': (None, appointment_details['type_id']),121 'user_id': (None, appointment_details['user_id']),122 'reason': (None, appointment_details['reason']),123 'room': (None, appointment_details['room']),124 'appointment_date': (None, appointment_details['appointment_date']),125 'time': (None, appointment_details['time']),126 'time_end': (None, appointment_details['time_end']),127 'useRealEndTime': (None, str(appointment_details['useRealEndTime']).lower())128 }129
130 # Send the POST request131 response = requests.post(request_url, headers=headers, files=files)132
133 # Print the response134 logging.info(f'Status Code: {response.status_code}')135 logging.info(f'Response: {response.text}')136
137 await browser.close()138
139if __name__ == '__main__':140 asyncio.run(main())
.dockerignore
.git.mise.toml.nvim.luastorage
# The rest is copied from https://github.com/github/gitignore/blob/main/Python.gitignore
# Byte-compiled / optimized / DLL files__pycache__/*.py[cod]*$py.class
# C extensions*.so
# Distribution / packaging.Pythonbuild/develop-eggs/dist/downloads/eggs/.eggs/lib/lib64/parts/sdist/var/wheels/share/python-wheels/*.egg-info/.installed.cfg*.eggMANIFEST
# PyInstaller# Usually these files are written by a python script from a template# before PyInstaller builds the exe, so as to inject date/other infos into it.*.manifest*.spec
# Installer logspip-log.txtpip-delete-this-directory.txt
# Unit test / coverage reportshtmlcov/.tox/.nox/.coverage.coverage.*.cachenosetests.xmlcoverage.xml*.cover*.py,cover.hypothesis/.pytest_cache/cover/
# Translations*.mo*.pot
# Django stuff:*.loglocal_settings.pydb.sqlite3db.sqlite3-journal
# Flask stuff:instance/.webassets-cache
# Scrapy stuff:.scrapy
# Sphinx documentationdocs/_build/
# PyBuilder.pybuilder/target/
# Jupyter Notebook.ipynb_checkpoints
# IPythonprofile_default/ipython_config.py
# pyenv# For a library or package, you might want to ignore these files since the code is# intended to run in multiple environments; otherwise, check them in:.python-version
# pdm# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.#pdm.lock# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it# in version control.# https://pdm.fming.dev/latest/usage/project/#working-with-version-control.pdm.toml.pdm-python.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm__pypackages__/
# Celery stuffcelerybeat-schedulecelerybeat.pid
# SageMath parsed files*.sage.py
# Environments.env.venvenv/venv/ENV/env.bak/venv.bak/
# Spyder project settings.spyderproject.spyproject
# Rope project settings.ropeproject
# mkdocs documentation/site
# mypy.mypy_cache/.dmypy.jsondmypy.json
# Pyre type checker.pyre/
# pytype static type analyzer.pytype/
# Cython debug symbolscython_debug/
# PyCharm# JetBrains specific template is maintained in a separate JetBrains.gitignore that can# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore# and can be added to the global gitignore or merged into this file. For a more nuclear# option (not recommended) you can uncomment the following to ignore the entire idea folder..idea/
.gitignore
.mise.toml.nvim.luastorage
# The rest is copied from https://github.com/github/gitignore/blob/main/Python.gitignore
# Byte-compiled / optimized / DLL files__pycache__/*.py[cod]*$py.class
# C extensions*.so
# Distribution / packaging.Pythonbuild/develop-eggs/dist/downloads/eggs/.eggs/lib/lib64/parts/sdist/var/wheels/share/python-wheels/*.egg-info/.installed.cfg*.eggMANIFEST
# PyInstaller# Usually these files are written by a python script from a template# before PyInstaller builds the exe, so as to inject date/other infos into it.*.manifest*.spec
# Installer logspip-log.txtpip-delete-this-directory.txt
# Unit test / coverage reportshtmlcov/.tox/.nox/.coverage.coverage.*.cachenosetests.xmlcoverage.xml*.cover*.py,cover.hypothesis/.pytest_cache/cover/
# Translations*.mo*.pot
# Django stuff:*.loglocal_settings.pydb.sqlite3db.sqlite3-journal
# Flask stuff:instance/.webassets-cache
# Scrapy stuff:.scrapy
# Sphinx documentationdocs/_build/
# PyBuilder.pybuilder/target/
# Jupyter Notebook.ipynb_checkpoints
# IPythonprofile_default/ipython_config.py
# pyenv# For a library or package, you might want to ignore these files since the code is# intended to run in multiple environments; otherwise, check them in:.python-version
# pdm# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.#pdm.lock# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it# in version control.# https://pdm.fming.dev/latest/usage/project/#working-with-version-control.pdm.toml.pdm-python.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm__pypackages__/
# Celery stuffcelerybeat-schedulecelerybeat.pid
# SageMath parsed files*.sage.py
# Environments.env.venvenv/venv/ENV/env.bak/venv.bak/
# Spyder project settings.spyderproject.spyproject
# Rope project settings.ropeproject
# mkdocs documentation/site
# mypy.mypy_cache/.dmypy.jsondmypy.json
# Pyre type checker.pyre/
# pytype static type analyzer.pytype/
# Cython debug symbolscython_debug/
# PyCharm# JetBrains specific template is maintained in a separate JetBrains.gitignore that can# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore# and can be added to the global gitignore or merged into this file. For a more nuclear# option (not recommended) you can uncomment the following to ignore the entire idea folder..idea/
real.py
1from apify import Actor2from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext3
4async def main() -> None:5 """Main entry point for the Apify Actor."""6 async with Actor:7 actor_input = await Actor.get_input() or {}8 start_urls = [url.get('url') for url in actor_input.get('start_urls', [{'url': 'https://us.idexxneo.com/login?'}])]9
10 if not start_urls:11 Actor.log.info('No start URLs specified in Actor input, exiting...')12 await Actor.exit()13
14 crawler = PlaywrightCrawler(15 max_requests_per_crawl=1, # We only need to handle one request for the login16 headless=True,17 )18
19 @crawler.router.default_handler20 async def request_handler(context: PlaywrightCrawlingContext) -> None:21 url = context.request.url22 Actor.log.info(f'Navigating to {url}...')23
24 # Navigate to the login page25 await context.page.goto(url)26
27 # Perform login actions28 await context.page.fill('//*[@id="company_id"]', '7880')29 await context.page.fill('//*[@id="username"]', 'PSingh')30 await context.page.fill('//*[@id="password"]', 'Temppass1234!')31
32 # Click the login button33 await context.page.click('//*[@id="btnLogin"]')34
35 # Wait for the page to load after login36 await context.page.wait_for_load_state('networkidle') # Wait until there are no more network connections for at least 500 ms37
38 # After logging in, you can extract data or navigate further39 Actor.log.info('Login successful!')40
41 # Example: Extracting data after login (you can customize this)42 data = {43 'url': context.request.url,44 'title': await context.page.title(),45 }46 await context.push_data(data)47
48 await crawler.run(start_urls)49
50if __name__ == '__main__':51 import asyncio52 asyncio.run(main())
requirements.txt
1# Feel free to add your Python dependencies below. For formatting guidelines, see:2# https://pip.pypa.io/en/latest/reference/requirements-file-format/3
4apify == 2.0.05crawlee[playwright]