![MedicareLINK (Sunfire) to csv avatar](https://images.apifyusercontent.com/Y1aIDmHL2tJnxMJJrZt1beoA6-lR9sxIbow2W8AqDoI/rs:fill:250:250/aHR0cHM6Ly9hcGlmeS1pbWFnZS11cGxvYWRzLXByb2QuczMudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20vSFZyelhUZlg5djg0bWlOd3Mvc0VGb0hvWkZLdUxWVzVQZFQtVW50aXRsZWRfZGVzaWduXyUyODIlMjkucG5n.webp)
MedicareLINK (Sunfire) to csv
DeprecatedView all Actors![MedicareLINK (Sunfire) to csv](https://images.apifyusercontent.com/Y1aIDmHL2tJnxMJJrZt1beoA6-lR9sxIbow2W8AqDoI/rs:fill:250:250/aHR0cHM6Ly9hcGlmeS1pbWFnZS11cGxvYWRzLXByb2QuczMudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20vSFZyelhUZlg5djg0bWlOd3Mvc0VGb0hvWkZLdUxWVzVQZFQtVW50aXRsZWRfZGVzaWduXyUyODIlMjkucG5n.webp)
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![MedicareLINK (Sunfire) to csv](https://images.apifyusercontent.com/Y1aIDmHL2tJnxMJJrZt1beoA6-lR9sxIbow2W8AqDoI/rs:fill:250:250/aHR0cHM6Ly9hcGlmeS1pbWFnZS11cGxvYWRzLXByb2QuczMudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20vSFZyelhUZlg5djg0bWlOd3Mvc0VGb0hvWkZLdUxWVzVQZFQtVW50aXRsZWRfZGVzaWduXyUyODIlMjkucG5n.webp)
MedicareLINK (Sunfire) to csv
medicare_tools/medicarecenter-data-extractor
Extract your enrollments in MedicareLINK (Sunfire) into a csv file.
.actor/Dockerfile
1# First, specify the base Docker image.
2# You can see the Docker images from Apify at https://hub.docker.com/r/apify/.
3# You can also use any other image from Docker Hub.
4FROM apify/actor-python-selenium:3.11
5
6# Second, copy just requirements.txt into the Actor image,
7# since it should be the only file that affects the dependency install in the next step,
8# in order to speed up the build
9COPY requirements.txt ./
10
11# Install the packages specified in requirements.txt,
12# Print the installed Python version, pip version
13# and all installed packages with their versions for debugging
14RUN echo "Python version:" \
15 && python --version \
16 && echo "Pip version:" \
17 && pip --version \
18 && echo "Installing dependencies:" \
19 && pip install -r requirements.txt \
20 && echo "All installed Python packages:" \
21 && pip freeze
22
23# Next, copy the remaining files and directories with the source code.
24# Since we do this after installing the dependencies, quick build will be really fast
25# for most source file changes.
26COPY . ./
27
28# Specify how to launch the source code of your Actor.
29# By default, the "python3 -m src" command is run
30CMD ["python3", "-m", "src"]
.actor/actor.json
1{
2 "actorSpecification": 1,
3 "name": "medicare-center-actor",
4 "title": "Medicare Center Data Extraction",
5 "description": "Extracts client data from Medicare Center using credentials.",
6 "version": "0.1",
7 "meta": {
8 "templateId": "python-selenium"
9 },
10 "input": "./input_schema.json",
11 "dockerfile": "./Dockerfile",
12 "storages": {
13 "dataset": {
14 "actorSpecification": 1,
15 "title": "Medicare Client Data",
16 "views": {
17 "clientData": {
18 "title": "Medicare Client Data",
19 "transformation": {
20 "fields": [
21 "firstName",
22 "lastName",
23 "PCP",
24 "monthlyPremium",
25 "effectiveDate",
26 "DOB",
27 "gender",
28 "address",
29 "ethnicity",
30 "race",
31 "language",
32 "MBI",
33 "electionPeriod",
34 "Part_A_effective_date",
35 "Part_B_effective_date",
36 "sepCode",
37 "enrollmentCode",
38 "agentName",
39 "writingId"
40 ]
41 },
42 "display": {
43 "component": "table",
44 "properties": {
45 "firstName": {
46 "label": "First Name",
47 "format": "text"
48 },
49 "lastName": {
50 "label": "Last Name",
51 "format": "text"
52 },
53 "PCP": {
54 "label": "Primary Care Physician/Plan Name",
55 "format": "text"
56 },
57 "monthlyPremium": {
58 "label": "Monthly Premium",
59 "format": "text"
60 },
61 "effectiveDate": {
62 "label": "Effective Date",
63 "format": "text"
64 },
65 "DOB": {
66 "label": "Date of Birth",
67 "format": "text"
68 },
69 "gender": {
70 "label": "Gender",
71 "format": "text"
72 },
73 "address": {
74 "label": "Address",
75 "format": "text"
76 },
77 "ethnicity": {
78 "label": "Ethnicity",
79 "format": "text"
80 },
81 "race": {
82 "label": "Race",
83 "format": "text"
84 },
85 "language": {
86 "label": "Preferred Language",
87 "format": "text"
88 },
89 "MBI": {
90 "label": "Medicare Beneficiary Identifier",
91 "format": "text"
92 },
93 "electionPeriod": {
94 "label": "Election Period",
95 "format": "text"
96 },
97 "Part_A_effective_date": {
98 "label": "Part A Effective Date",
99 "format": "text"
100 },
101 "Part_B_effective_date": {
102 "label": "Part B Effective Date",
103 "format": "text"
104 },
105 "sepCode": {
106 "label": "SEP Code",
107 "format": "text"
108 },
109 "enrollmentCode": {
110 "label": "Enrollment Code",
111 "format": "text"
112 },
113 "agentName": {
114 "label": "Agent Name",
115 "format": "text"
116 },
117 "writingId": {
118 "label": "Writing ID",
119 "format": "text"
120 }
121 }
122 }
123 }
124 }
125 }
126 }
127}
.actor/input_schema.json
1{
2 "title": "Medicare Center Actor Input",
3 "type": "object",
4 "schemaVersion": 1,
5 "properties": {
6 "npi_number": {
7 "title": "NPN Number",
8 "type": "string",
9 "description": "Enter the NPN number used for login.",
10 "editor": "textfield"
11 },
12 "password": {
13 "title": "Password",
14 "type": "string",
15 "description": "Enter the password for login.",
16 "isSecret": true,
17 "editor": "textfield"
18 },
19 "start_date":{
20 "title":"Enrollments from",
21 "type":"string",
22 "description":"Enter the Starting Date",
23 "editor": "datepicker"
24 },
25 "end_date":{
26 "title":"To",
27 "type":"string",
28 "description":"Enter the Ending Date",
29 "editor":"datepicker"
30 }
31 },
32 "required": ["npi_number", "password"]
33}
src/__init__.py
src/__main__.py
1import asyncio
2import logging
3
4from apify.log import ActorLogFormatter
5
6from .main import main
7
8handler = logging.StreamHandler()
9handler.setFormatter(ActorLogFormatter())
10
11apify_client_logger = logging.getLogger('apify_client')
12apify_client_logger.setLevel(logging.INFO)
13apify_client_logger.addHandler(handler)
14
15apify_logger = logging.getLogger('apify')
16apify_logger.setLevel(logging.DEBUG)
17apify_logger.addHandler(handler)
18
19asyncio.run(main())
src/main.py
1from urllib.parse import urljoin
2from selenium import webdriver
3from selenium.webdriver.chrome.options import Options as ChromeOptions
4from selenium.webdriver.common.by import By
5from apify import Actor
6import time
7import random
8from selenium.webdriver.support.ui import Select
9from selenium.webdriver.common.keys import Keys
10from selenium.webdriver.common.by import By
11import requests
12from bs4 import BeautifulSoup as bs
13import csv
14import pandas as pd
15from tqdm import tqdm
16from datetime import datetime, timedelta
17import dateutil.relativedelta
18
19# To run this Actor locally, you need to have the Selenium Chromedriver installed.
20# https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/
21# When running on the Apify platform, it is already included in the Actor's Docker image.
22
23async def login(browser, npi_number, password):
24 # browser.open("https://www.medicarecenter.com/welcome")
25 browser.get("https://identity.medicarecenter.com/login?ReturnUrl=https%3A%2F%2Fae-api.medicarecenter.com%2Fae-identity-service%2Fconnect%2Fauthorize%2Fcallback%3Fresponse_type%3Dcode%26scope%3Dopenid%2520profile%2520email%26client_id%3DSunfire-Client%26redirect_uri%3Dhttps%253A%252F%252Fwww.sunfirematrix.com%252Fapi%252Fpartner%252Fsso%252Fint%26state%3D")
26 time.sleep(random.uniform(4, 5))
27 # for login
28 try:
29 browser.find_element(By.CSS_SELECTOR, 'button[name="actionButton"]').click()
30 time.sleep(random.uniform(4, 6))
31 except:
32 pass
33 # send npi
34 browser.find_element(By.CSS_SELECTOR, 'input[id="login-username"]').send_keys(npi_number)
35 # send password
36 browser.find_element(By.CSS_SELECTOR, 'input[id="login-password"]').send_keys(password)
37 # click login
38 browser.find_element(By.CSS_SELECTOR, 'button[type="submit"]').click()
39 time.sleep(random.uniform(8, 10))
40
41async def open_report(browser):
42 try:
43 browser.find_element(By.CSS_SELECTOR, 'a[data-test="dashboardReporting"]').click()
44 except:
45 try:
46 browser.find_element(By.CSS_SELECTOR, 'a[data-test="dashboardReporting"]').click()
47 except:
48 pass
49 time.sleep(random.uniform(7, 8))
50 timeframe = Select(browser.find_element(By.CSS_SELECTOR, 'select[id="timeFrame"]'))
51 timeframe.select_by_value("custom")
52 today = datetime.today().strftime("%m/%d/%Y")
53 # make two months ago
54 two_months_ago = datetime.today() - pd.DateOffset(months=2)
55 two_months_ago = two_months_ago.strftime("%m/%d/%Y")
56 startDate = browser.find_element(By.CSS_SELECTOR, 'input[name="startDate"]')
57 startDate.clear()
58 startDate.send_keys(two_months_ago)
59 startDate.send_keys(Keys.ENTER)
60 # send end date. mm/dd/yyyy
61 endDate = browser.find_element(By.CSS_SELECTOR, 'input[name="endDate"]')
62 endDate.clear()
63 endDate.send_keys(today)
64 endDate.send_keys(Keys.ENTER)
65 browser.find_element(By.XPATH, '//button[text()="Run"]').click()
66 time.sleep(random.uniform(4, 6))
67
68async def get_auth(cookies):
69 headers = {
70 'authority': 'www.sunfirematrix.com',
71 'accept': '*/*',
72 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
73 'authorization': cookies['rh'],
74 'content-type': 'application/json',
75 'referer': 'https://www.sunfirematrix.com/app/agent/int/',
76 'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
77 'sec-ch-ua-mobile': '?0',
78 'sec-ch-ua-platform': '"Windows"',
79 'sec-fetch-dest': 'empty',
80 'sec-fetch-mode': 'cors',
81 'sec-fetch-site': 'same-origin',
82 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
83 }
84
85 response = requests.get('https://www.sunfirematrix.com/api/partner/info', cookies=cookies, headers=headers)
86 info = response.json()
87 auth = info['clientPartnerId']
88 return auth
89
90
91async def codes(cookies, auth, npi_number, start_date, end_date):
92 headers = {
93 'authority': 'www.sunfirematrix.com',
94 'accept': '*/*',
95 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
96 'authorization': cookies['rh'],
97 'content-type': 'application/json',
98 'referer': 'https://www.sunfirematrix.com/app/agent/int/',
99 'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
100 'sec-ch-ua-mobile': '?0',
101 'sec-ch-ua-platform': '"Windows"',
102 'sec-fetch-dest': 'empty',
103 'sec-fetch-mode': 'cors',
104 'sec-fetch-site': 'same-origin',
105 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
106 }
107 today = datetime.today().strftime("%Y-%m-%d")
108 # make two months ago
109 two_months_ago = datetime.today() - pd.DateOffset(months=2)
110 two_months_ago = two_months_ago.strftime("%Y-%m-%d")
111
112 # make two months batch from start_date and end_date
113 # loop through the batch and get codes
114
115 start_date = datetime.strptime(start_date, '%Y-%m-%d')
116 end_date = datetime.strptime(end_date, '%Y-%m-%d')
117 codes = []
118 while start_date < end_date:
119 two_months_later = start_date + dateutil.relativedelta.relativedelta(months=2)
120 response = requests.get(
121 f'https://www.sunfirematrix.com/v2/enroll/list/agent/{auth}/{npi_number}@sunfire.integritymarketinggroup.com/{start_date}T18%3A00%3A00.000Z/{two_months_later}T18%3A00%3A00.000Z',
122 cookies=cookies,
123 headers=headers,
124 )
125 enrollmentCode = response.json()
126 enrollmentCode = [a['enrollmentCode'] for a in enrollmentCode]
127 codes.extend(enrollmentCode)
128 Actor.log.info(f"Got {len(enrollmentCode)} codes from {start_date.isoformat()} to {two_months_later.isoformat()}")
129 # process the response here
130 start_date = two_months_later
131 # response = requests.get(
132 # f'https://www.sunfirematrix.com/v2/enroll/list/agent/{auth}/{npi_number}@sunfire.integritymarketinggroup.com/{two_months_ago}T18%3A00%3A00.000Z/{today}T18%3A00%3A00.000Z',
133 # cookies=cookies,
134 # headers=headers,
135 # )
136
137 return codes
138
139
140async def get_codes(browser, npi_number, start_date, end_date):
141 cookies = browser.get_cookies()
142 cookies = {cookie["name"]: cookie["value"] for cookie in cookies}
143 auth = await get_auth(cookies)
144 enrollmentCode = await codes(cookies, auth, npi_number, start_date, end_date)
145 return enrollmentCode
146
147
148async def process(data):
149 client_data = data
150 form_data = client_data['formData']
151 firstName = form_data['firstName']
152 lastName = form_data['lastName']
153 try:
154 planName = form_data['plan']['displayName']
155 except:
156 planName = ''
157 try:
158 monthlyPremium = form_data['plan']['fmtPremium']
159 except:
160 monthlyPremium = ''
161 try:
162 effectiveDate = form_data['effectiveDate']
163 effectiveDate = effectiveDate['month'] + '-' + effectiveDate['day'] + '-' + effectiveDate['year']
164 except:
165 effectiveDate = ''
166 dob = form_data['dob']
167 dob = dob['month'] + '-' + dob['day'] + '-' + dob['year']
168 gender = form_data['gender']
169 # address = form_data['home']
170 address_fields = ['line1', 'line2', 'city', 'countyName', 'state', 'zip']
171 address = form_data.get('home', {})
172 address_str = ', '.join([address.get(field, '') for field in address_fields])
173 # check i
174 # address = address['line1'] + ', ' + address['line2'] + ', ' + address['city'] + ', ' + address['countyName'] +', '+ address['state'] + ', ' + address['zip']
175 raceEthnicitySpecify = form_data['raceEthnicitySpecify']
176 try:
177 ethnicity = raceEthnicitySpecify['ethnicity']
178 except:
179 ethnicity = ''
180 try:
181 race = raceEthnicitySpecify['race']
182 except:
183 race = ''
184 try:
185 language = form_data['language']
186 except:
187 language = ''
188 medicareNumber = form_data['medicareNumber']
189 try:
190 Part_A_effective_date = form_data['partADate']
191 Part_A_effective_date = Part_A_effective_date['month'] + '-' + Part_A_effective_date['day'] + '-' + Part_A_effective_date['year']
192 except:
193 Part_A_effective_date = ''
194
195 try:
196 Part_B_effective_date = form_data['partBDate']
197 Part_B_effective_date = Part_B_effective_date['month'] + '-' + Part_B_effective_date['day'] + '-' + Part_B_effective_date['year']
198 except:
199 Part_B_effective_date = ''
200
201 electionPeriod = form_data['electionPeriod']
202 try:
203 sepCode = form_data['sepCode']
204 except:
205 sepCode = 'N/A'
206 try:
207 planName = form_data['pcp']['name']
208 except:
209 planName = 'N/A'
210 enrollmentCode = form_data['enrollmentCode']
211 agentName = form_data['agentModel']['firstName'] + ' ' + form_data['agentModel']['lastName']
212 writingId = form_data['agentModel']['writingId']
213
214
215 client_info = {
216 "firstName": firstName,
217 "lastName": lastName,
218 "PCP": planName,
219 "monthlyPremium": monthlyPremium,
220 "effectiveDate": effectiveDate,
221 "DOB": dob,
222 "gender": gender,
223 "address": address_str,
224 "ethnicity": ethnicity,
225 "race": race,
226 "language": language,
227 "MBI": medicareNumber,
228 "electionPeriod": electionPeriod,
229 "Part_A_effective_date": Part_A_effective_date,
230 "Part_B_effective_date": Part_B_effective_date,
231 "sepCode": sepCode,
232 "enrollmentCode": enrollmentCode,
233 "agentName": agentName,
234 "writingId": writingId
235 }
236 # Actor.push_data(client_info)
237 # with open(f'{npi_numer}_client_info.json', 'a', encoding='utf-8') as f:
238 # json.dump(client_info, f, ensure_ascii=False, indent=4)
239 # # add comma
240 # f.write(',\n')
241 return client_info
242 # print(client_info)
243
244async def get_report(enrollmentCode, cookies, npi_number):
245 headers = {
246 'authority': 'www.sunfirematrix.com',
247 'accept': '*/*',
248 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
249 'authorization': cookies['rh'],
250 'content-type': 'application/json',
251 'referer': 'https://www.sunfirematrix.com/app/agent/int/?scope=openid%20profile%20email&session_state=c8-66PcTpUvG7cD247EYXmocEQ2M_Sm5nXKeoc5CQLs.86DD30C6A324B3E309C9DFF6E83101D7',
252 'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
253 'sec-ch-ua-mobile': '?0',
254 'sec-ch-ua-platform': '"Windows"',
255 'sec-fetch-dest': 'empty',
256 'sec-fetch-mode': 'cors',
257 'sec-fetch-site': 'same-origin',
258 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
259 }
260
261 response = requests.get(
262 f'https://www.sunfirematrix.com/api/form/mc/load/pdf/{npi_number}%40sunfire.integritymarketinggroup.com/{enrollmentCode}',
263 cookies=cookies,
264 headers=headers,
265 )
266 client_info = await process(response.json())
267 return client_info
268
269
270
271async def main():
272 async with Actor:
273 # Read the Actor input
274 actor_input = await Actor.get_input() or {}
275 npi_number = actor_input.get("npi_number")
276 password = actor_input.get("password")
277 start_date = actor_input.get("start_date")
278 end_date = actor_input.get("end_date")
279
280
281 # Launch a new Selenium Chrome WebDriver
282 Actor.log.info('Launching Chrome WebDriver...')
283 chrome_options = ChromeOptions()
284 if Actor.config.headless:
285 chrome_options.add_argument('--headless')
286 chrome_options.add_argument('--no-sandbox')
287 chrome_options.add_argument('--disable-dev-shm-usage')
288 chrome_options.add_argument('--window-size=1920,1080')
289 browser = webdriver.Chrome(options=chrome_options)
290 # ruh the login function
291 await login(browser, npi_number, password)
292 Actor.log.info("Logged In!")
293 # open report
294 await open_report(browser)
295 Actor.log.info("Report Opened!")
296 # get auth
297 enrollmentCode = await get_codes(browser, npi_number, start_date, end_date)
298 Actor.log.info("Got Enrollment Codes!")
299 cookies = browser.get_cookies()
300 cookies = {cookie["name"]: cookie["value"] for cookie in cookies}
301 # client_info = []
302 for code in tqdm(enrollmentCode):
303 Actor.log.info("Getting Data....")
304 client_info = await get_report(code, cookies, npi_number)
305 await Actor.push_data(client_info)
306 # client_info.append(await get_report(code, cookies, npi_number))
307 Actor.log.info("Completed.")
308 browser.quit()
.dockerignore
1# configurations
2.idea
3
4# crawlee and apify storage folders
5apify_storage
6crawlee_storage
7storage
8
9# installed files
10.venv
11
12# git folder
13.git
.editorconfig
1root = true
2
3[*]
4indent_style = space
5indent_size = 4
6charset = utf-8
7trim_trailing_whitespace = true
8insert_final_newline = true
9end_of_line = lf
.gitignore
1# This file tells Git which files shouldn't be added to source control
2
3.idea
4.DS_Store
5
6apify_storage
7storage
8
9.venv/
10.env/
11__pypackages__
12dist/
13build/
14*.egg-info/
15*.egg
16
17__pycache__
18
19.mypy_cache
20.dmypy.json
21dmypy.json
22.pytest_cache
23
24.scrapy
25*.log
requirements.txt
1# Add your dependencies here.
2# See https://pip.pypa.io/en/latest/reference/requirements-file-format/
3# for how to format them
4apify ~= 1.2.0
5selenium ~= 4.14.0
6seleniumbase
7tqdm
8bs4
9pandas
Developer
Maintained by Community
Categories