Psing login avatar

Psing login

Deprecated
Go to Store
This Actor is deprecated

This Actor is unavailable because the developer has decided to deprecate it. Would you like to try a similar Actor instead?

See alternative Actors
Psing login

Psing login

axxsh/psing-login

Psing login

.actor/Dockerfile

1# Use Apify base image with Python and Playwright
2FROM apify/actor-python-playwright
3
4# Copy all source code to the default working directory
5COPY ./src /app
6
7# Install Python dependencies
8RUN pip install requests
9
10# Run the actor script
11CMD ["python", "/app/main.py"]

.actor/actor.json

1{
2  "name": "my-actor",
3  "version": "0.1",
4  "description": "This is my Apify actor for login automation.",
5  "actorSpecification": 1,
6  "input": "./input_schema.json",
7  "main": "src/main.py"
8}

.actor/input_schema.json

1{
2    "schemaVersion": 1,
3    "title": "My Actor Input Schema",
4    "type": "object",
5    "properties": {
6        "start_url": {
7            "type": "string",
8            "title": "Start URL",
9            "description": "The URL to start the scraping process.",
10            "editor": "textfield" 
11        },
12        "company_id": {
13        "type": "string",
14        "title": "Company ID",
15        "description": "ID of the company.",
16        "editor": "textfield"
17        },
18        "username": {
19            "type": "string",
20            "title": "Username",
21            "description": "Username for login.",
22            "editor": "textfield"  
23        },
24        "password": {
25            "type": "string",
26            "title": "Password",
27            "description": "Password for login.",
28            "editor": "textfield"  
29        },
30        "patient_id": {
31            "type": "string",
32            "title": "Patient ID",
33            "description": "ID of the patient.",
34            "editor": "textfield"
35        },
36        "type_id": {
37            "type": "string",
38            "title": "Type ID",
39            "description": "ID for the appointment type.",
40            "editor": "textfield"
41        },
42        "user_id": {
43            "type": "string",
44            "title": "User ID",
45            "description": "ID of the user making the appointment.",
46            "editor": "textfield"
47        },
48        "reason": {
49            "type": "string",
50            "title": "Reason",
51            "description": "Reason for the appointment.",
52            "editor": "textfield"
53        },
54        "room": {
55            "type": "string",
56            "title": "Room",
57            "description": "Room number for the appointment.",
58            "editor": "textfield"
59        },
60        "appointment_date": {
61            "type": "string",
62            "title": "Appointment Date",
63            "description": "Date of the appointment.",
64            "editor": "datepicker"
65        },
66        "time": {
67            "type": "string",
68            "title": "Appointment Start Time",
69            "description": "Start time of the appointment.",
70            "editor": "textfield"
71        },
72        "time_end": {
73            "type": "string",
74            "title": "Appointment End Time",
75            "description": "End time of the appointment.",
76            "editor": "textfield"
77        },
78        "useRealEndTime": {
79            "type": "boolean",
80            "title": "Use Real End Time",
81            "description": "Whether to use the real end time for the appointment.",
82            "editor": "checkbox",
83            "default": true
84        }
85    },
86    "required": ["start_url", "username", "password", "patient_id", "type_id", "user_id", "reason", "room", "appointment_date", "time", "time_end", "useRealEndTime"]
87}

src/__main__.py

1import asyncio
2from .main import main
3
4# Execute the Actor entry point
5asyncio.run(main())

src/main.py

1import logging
2import json
3import asyncio
4import requests
5from playwright.async_api import async_playwright
6from apify import Actor  # Import the Actor module
7
8logging.basicConfig(level=logging.INFO)
9
10async def main():
11    # Initialize the actor
12    await Actor.init()
13
14    # Load input parameters from Apify input
15    actor_input = await Actor.get_input() or {}
16
17    # Log the input data for debugging
18    logging.info(f'Input data: {actor_input}')
19    
20    # Extract input parameters from the input JSON
21    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 details
38    logging.info(f'Appointment Details: {appointment_details}')
39
40    # Ensure all input fields have values, raise an error if any critical field is missing
41    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        return
48
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 headers
55        sec_ch_ua = None
56        sec_ch_ua_mobile = None
57
58        # Capture request headers when a request is made
59        def extract_headers(headers):
60            nonlocal sec_ch_ua, sec_ch_ua_mobile
61            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 form
70        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 dashboard
76        await page.wait_for_url('**/dashboard', timeout=15000)
77        logging.info('Login successful! On the dashboard page.')
78
79        # Extract cookies
80        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 token
86        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 agent
90        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-mobile
94        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 dynamically
98        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_token
115        }
116
117        # Adjust form data to use 'files' for multipart data
118        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 request
131        response = requests.post(request_url, headers=headers, files=files)
132
133        # Print the response
134        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

1.git
2.mise.toml
3.nvim.lua
4storage
5
6# The rest is copied from https://github.com/github/gitignore/blob/main/Python.gitignore
7
8# Byte-compiled / optimized / DLL files
9__pycache__/
10*.py[cod]
11*$py.class
12
13# C extensions
14*.so
15
16# Distribution / packaging
17.Python
18build/
19develop-eggs/
20dist/
21downloads/
22eggs/
23.eggs/
24lib/
25lib64/
26parts/
27sdist/
28var/
29wheels/
30share/python-wheels/
31*.egg-info/
32.installed.cfg
33*.egg
34MANIFEST
35
36# PyInstaller
37#  Usually these files are written by a python script from a template
38#  before PyInstaller builds the exe, so as to inject date/other infos into it.
39*.manifest
40*.spec
41
42# Installer logs
43pip-log.txt
44pip-delete-this-directory.txt
45
46# Unit test / coverage reports
47htmlcov/
48.tox/
49.nox/
50.coverage
51.coverage.*
52.cache
53nosetests.xml
54coverage.xml
55*.cover
56*.py,cover
57.hypothesis/
58.pytest_cache/
59cover/
60
61# Translations
62*.mo
63*.pot
64
65# Django stuff:
66*.log
67local_settings.py
68db.sqlite3
69db.sqlite3-journal
70
71# Flask stuff:
72instance/
73.webassets-cache
74
75# Scrapy stuff:
76.scrapy
77
78# Sphinx documentation
79docs/_build/
80
81# PyBuilder
82.pybuilder/
83target/
84
85# Jupyter Notebook
86.ipynb_checkpoints
87
88# IPython
89profile_default/
90ipython_config.py
91
92# pyenv
93#   For a library or package, you might want to ignore these files since the code is
94#   intended to run in multiple environments; otherwise, check them in:
95.python-version
96
97# pdm
98#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
99#pdm.lock
100#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
101#   in version control.
102#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
103.pdm.toml
104.pdm-python
105.pdm-build/
106
107# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
108__pypackages__/
109
110# Celery stuff
111celerybeat-schedule
112celerybeat.pid
113
114# SageMath parsed files
115*.sage.py
116
117# Environments
118.env
119.venv
120env/
121venv/
122ENV/
123env.bak/
124venv.bak/
125
126# Spyder project settings
127.spyderproject
128.spyproject
129
130# Rope project settings
131.ropeproject
132
133# mkdocs documentation
134/site
135
136# mypy
137.mypy_cache/
138.dmypy.json
139dmypy.json
140
141# Pyre type checker
142.pyre/
143
144# pytype static type analyzer
145.pytype/
146
147# Cython debug symbols
148cython_debug/
149
150# PyCharm
151#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
152#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
153#  and can be added to the global gitignore or merged into this file.  For a more nuclear
154#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
155.idea/

.gitignore

1.mise.toml
2.nvim.lua
3storage
4
5# The rest is copied from https://github.com/github/gitignore/blob/main/Python.gitignore
6
7# Byte-compiled / optimized / DLL files
8__pycache__/
9*.py[cod]
10*$py.class
11
12# C extensions
13*.so
14
15# Distribution / packaging
16.Python
17build/
18develop-eggs/
19dist/
20downloads/
21eggs/
22.eggs/
23lib/
24lib64/
25parts/
26sdist/
27var/
28wheels/
29share/python-wheels/
30*.egg-info/
31.installed.cfg
32*.egg
33MANIFEST
34
35# PyInstaller
36#  Usually these files are written by a python script from a template
37#  before PyInstaller builds the exe, so as to inject date/other infos into it.
38*.manifest
39*.spec
40
41# Installer logs
42pip-log.txt
43pip-delete-this-directory.txt
44
45# Unit test / coverage reports
46htmlcov/
47.tox/
48.nox/
49.coverage
50.coverage.*
51.cache
52nosetests.xml
53coverage.xml
54*.cover
55*.py,cover
56.hypothesis/
57.pytest_cache/
58cover/
59
60# Translations
61*.mo
62*.pot
63
64# Django stuff:
65*.log
66local_settings.py
67db.sqlite3
68db.sqlite3-journal
69
70# Flask stuff:
71instance/
72.webassets-cache
73
74# Scrapy stuff:
75.scrapy
76
77# Sphinx documentation
78docs/_build/
79
80# PyBuilder
81.pybuilder/
82target/
83
84# Jupyter Notebook
85.ipynb_checkpoints
86
87# IPython
88profile_default/
89ipython_config.py
90
91# pyenv
92#   For a library or package, you might want to ignore these files since the code is
93#   intended to run in multiple environments; otherwise, check them in:
94.python-version
95
96# pdm
97#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
98#pdm.lock
99#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
100#   in version control.
101#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
102.pdm.toml
103.pdm-python
104.pdm-build/
105
106# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
107__pypackages__/
108
109# Celery stuff
110celerybeat-schedule
111celerybeat.pid
112
113# SageMath parsed files
114*.sage.py
115
116# Environments
117.env
118.venv
119env/
120venv/
121ENV/
122env.bak/
123venv.bak/
124
125# Spyder project settings
126.spyderproject
127.spyproject
128
129# Rope project settings
130.ropeproject
131
132# mkdocs documentation
133/site
134
135# mypy
136.mypy_cache/
137.dmypy.json
138dmypy.json
139
140# Pyre type checker
141.pyre/
142
143# pytype static type analyzer
144.pytype/
145
146# Cython debug symbols
147cython_debug/
148
149# PyCharm
150#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
151#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
152#  and can be added to the global gitignore or merged into this file.  For a more nuclear
153#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
154.idea/

real.py

1from apify import Actor
2from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext
3
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 login
16            headless=True,
17        )
18
19        @crawler.router.default_handler
20        async def request_handler(context: PlaywrightCrawlingContext) -> None:
21            url = context.request.url
22            Actor.log.info(f'Navigating to {url}...')
23
24            # Navigate to the login page
25            await context.page.goto(url)
26
27            # Perform login actions
28            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 button
33            await context.page.click('//*[@id="btnLogin"]')
34
35            # Wait for the page to load after login
36            await context.page.wait_for_load_state('networkidle')  # Wait until there are no more network connections for at least 500 ms
37
38            # After logging in, you can extract data or navigate further
39            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 asyncio
52    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.0
5crawlee[playwright]
Developer
Maintained by Community
Categories