-
Notifications
You must be signed in to change notification settings - Fork 114
/
whatsappbeacon.py
250 lines (199 loc) · 9.01 KB
/
whatsappbeacon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchWindowException
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import InvalidArgumentException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from utils.database import Database
from time import sleep
import os
import time
import math
import datetime
import argparse
from db_to_excel import Converter
import threading
import keyboard
'''
░█──░█ █──█ █▀▀█ ▀▀█▀▀ █▀▀ █▀▀█ █▀▀█ █▀▀█ ░█▀▀▀█ ░█▀▀▀█ ▀█▀ ░█▄─░█ ▀▀█▀▀
░█░█░█ █▀▀█ █▄▄█ ──█── ▀▀█ █▄▄█ █──█ █──█ ░█──░█ ─▀▀▀▄▄ ░█─ ░█░█░█ ─░█──
░█▄▀▄█ ▀──▀ ▀──▀ ──▀── ▀▀▀ ▀──▀ █▀▀▀ █▀▀▀ ░█▄▄▄█ ░█▄▄▄█ ▄█▄ ░█──▀█ ─░█──
░█▀▀█ ░█──░█ ───░█ ─█▀▀█ ░█▀▀▀█ ░█▀▀█ ░█▀▀▀ ░█▀▀█ ─█▀▀█ ░█▄─░█
░█▀▀▄ ░█▄▄▄█ ─▄─░█ ░█▄▄█ ─▀▀▀▄▄ ░█▄▄█ ░█▀▀▀ ░█▄▄▀ ░█▄▄█ ░█░█░█
░█▄▄█ ──░█── ░█▄▄█ ░█─░█ ░█▄▄▄█ ░█─── ░█▄▄▄ ░█─░█ ░█─░█ ░█──▀█
'''
def remove_idle(driver):
while True:
time.sleep(10)
try:
smiley = driver.find_element(by=By.XPATH, value='//span[@data-testid="smiley"]')
smiley.click()
except NoSuchElementException:
print('Error: could not find smiley element')
def study_user(driver, user, language, excel):
"""
Generates an excel file with user data and checks their online status.
Parameters:
driver (webdriver): Selenium webdriver instance.
user (str): The name of the user to study.
language (str): The language of the user's WhatsApp account.
excel (bool): Whether or not to generate an excel file.
Returns:
None
"""
# Create Excel File
if excel:
excel = Converter()
excel.db_to()
excel.db_to_excel()
print("\n Your Data Has Been Added to Excel File")
else:
pass
# First, go to their chat
try:
#We instantiate our Logs class, save current date and create a text file for the user
chat_icon = driver.find_element(by=By.CSS_SELECTOR, value = 'span[data-testid="chat"]')
chat_icon.click()
actions = ActionChains(driver)
actions.send_keys(user)
actions.perform()
sleep(1)
print('Trying to find: {}'.format(user))
span = "span[title='{}']".format(user)
element = driver.find_element(by=By.CSS_SELECTOR, value = span)
element.click()
print('Found and clicked!')
except NoSuchElementException:
print('{} is not found. Returning...(Maybe your contact is in the archive. Check it)'.format(user))
return
x_arg = str()
idle_thread = threading.Thread(target=remove_idle, args=(driver,), daemon=True)
idle_thread.start()
# Now, we continuously check for their online status:
if language == 'en' or language == 'de' or language == 'pt':
x_arg = '//span[@title=\'{}\']'.format('online')
elif language == 'es':
x_arg = '//span[@title=\'{}\']'.format('en línea')
elif language == 'fr':
x_arg = '//span[@title=\'{}\']'.format('en ligne')
elif language == 'cat':
x_arg = '//span[@title=\'{}\']'.format('en línia')
elif language == 'tr':
x_arg = '//span[@title=\'{}\']'.format('çevrimiçi')
print('Trying to find: {} in user {}'.format(x_arg, user))
previous_state = 'OFFLINE' # by default, we consider the user to be offline. The first time the user goes online,
first_online = time.time()
cumulative_session_time = 0
# it will be printed.
while True:
try:
element = driver.find_element(by=By.XPATH, value = x_arg)
if previous_state == 'OFFLINE':
input = ('[{}][ONLINE] {}'.format(
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
user))
print(input)
date = datetime.datetime.now().strftime('%Y-%m-%d')
hour = datetime.datetime.now().strftime('%H')
minute = datetime.datetime.now().strftime('%M')
second = datetime.datetime.now().strftime('%S')
type_connection = 'CONNECTION'
Database.insert_connection_data(user, date, hour, minute, second, type_connection)
first_online = time.time()
previous_state = 'ONLINE'
except NoSuchElementException:
if previous_state == 'ONLINE':
# calculate approximate real time of WhatsApp being online
total_online_time = time.time() - first_online # approximately what it takes onPause to send signal
if total_online_time < 0: # This means that the user was typing instead of going offline.
continue # Skip the rest of this iteration. Do nothing.
cumulative_session_time += total_online_time
input = ('[{}][DISCONNECTED] {} was online for {} seconds. Session total: {} seconds'.format(
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
user,
math.floor(total_online_time),
math.floor(cumulative_session_time)))
print(input)
date = datetime.datetime.now().strftime('%Y-%m-%d')
hour = datetime.datetime.now().strftime('%H')
minute = datetime.datetime.now().strftime('%M')
second = datetime.datetime.now().strftime('%S')
type_connection = "DISCONNECTION"
time_connected = total_online_time
Database.insert_disconnection_data(user, date, hour, minute, second, type_connection,round(time_connected))
previous_state = 'OFFLINE'
except NoSuchWindowException:
print('ERROR: Your WhatsApp window has been minimized or closed, try running the code again, shutting down...')
exit()
def whatsapp_load(driver) -> None:
"""
The find_element method is used by means of which we are going to search for XPath "wa-web-loading-screen"
which is an html element which is present exclusively when the web.whatsapp.com is loading
Args:
- Driver of the web browser
Returns:
None
"""
while True:
try:
loading = driver.find_element(by=By.XPATH, value='//div[@data-testid="wa-web-loading-screen"]')
loading.click()
print("\n Loaded")
break
except Exception as e:
print("Loading. Press F1 if stuck in this step...: {}".format(e), end=f"\r")
if keyboard.is_pressed('F1'):
break
while True:
try:
loading.click()
except Exception:
break
def whatsapp_login():
"""
Logs into WhatsApp Web using Selenium and returns the driver object.
Raises:
- InvalidArgumentException: If a Selenium navigator is already running in the background.
Returns:
- driver: A webdriver object with WhatsApp Web open and the user logged in.
"""
try:
print('In order to make this program to work, you will need to log-in once in WhatsApp. After that, your session will be saved until you revoke it.')
options = webdriver.ChromeOptions()
options.add_argument("user-data-dir=C:\\Path")
options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Chrome(options=options)
driver.get('https://web.whatsapp.com')
assert 'WhatsApp' in driver.title
# Detects when you can search for the user that was introduced (the page was fully loaded)
whatsapp_load(driver=driver)
return driver
except InvalidArgumentException:
print('ERROR: You may already have a Selenium navegator running in the background, close the window and run the code again, shutting down...')
exit()
def main():
"""
This function creates a table in the database and parses command line arguments.
It then logs into WhatsApp and studies the specified user in the specified language.
If the excel flag is set, it converts the database to an Excel file.
Args:
None
Returns:
None
"""
Database.create_table()
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--username', help='Username to track', required=True)
parser.add_argument('-l', '--language', help='Language to use', required=True, choices=['en', 'es', 'fr', 'pt', 'de', 'cat','tr'])
parser.add_argument('-e','--excel',help="Db to Excel Converter",required=False,action='store_true')
parser.add_argument('-s', '--split', help="change the prefix with which the spaces of the --username flag will be separated", required=False, default="-")
args = parser.parse_args()
user_name = " ".join(args.username.split(args.split))
driver = whatsapp_login()
study_user(driver, user_name, args.language,args.excel)
if __name__ == '__main__':
main()