def run(self, profile_path="/data/firefox_cache"): """ Faz a coleta dos metadados de grupos de Whatsapp de acordo com os parâmetros fornecidos na criação do objeto de coleta. Parâmetros ------------ profile_path : str Caminho para um profile alternativo do navegador utilizado na coleta. """ today = datetime.date.today().strftime('%Y-%m-%d') all_groups_filename = '/data/all_grupos_%s.json' % (today) with open(all_groups_filename, 'w') as json_file: print('Collecting metadata for groups at %s' % (today)) if not os.path.exists(profile_path): os.makedirs(profile_path) driver = WhatsAPIDriver(loadstyles=True, profile=profile_path, client="remote", command_executor=os.environ["SELENIUM"]) try: print("Waiting for WhatsApp Web Login") driver.wait_for_login() print("Saving session") driver.save_firefox_profile(remove_old=False) print("Bot started") pathlib.Path("/data/grupos").mkdir(parents=True, exist_ok=True) print('>>>>>>>>>>> Loading chat ids') chats = driver.get_all_chats() for chat in (chats): # Does not collect direct messages, only group chats if not chat._js_obj['isGroup']: continue gid = chat.id gid = gid.split('@')[0] s_name = self._process_string(chat.name) # Skip group if it is on blacklist (can be name or groupID) if (s_name in self.group_blacklist or gid in self.group_blacklist): continue group = dict() _id = chat.id creator = _id.split('-')[0] timestamp = _id.split('-')[-1].split('@')[0] date = convert_data_from_timestamp(float(timestamp)) str_date = date.strftime('%Y-%m-%d %H:%M:%S') name = chat.name.strip().replace('\t', ' ') kind = chat._js_obj["kind"] participants = list() for member in driver.group_get_participants(_id): user = dict() user['name'] = member.verified_name user['short_name'] = member.short_name user['nome_formatado'] = member.formatted_name user['number'] = member.id user['isBusiness'] = member.is_business user['profile_pic'] = member.profile_pic participants.append(user) group['group_id'] = _id group['creator'] = creator group['kind'] = kind group['creation'] = dict() group['creation']['creation_date'] = str_date group['creation']['creation_timestamp'] = timestamp group['title'] = name group['members'] = participants path = '/data/grupos/' filename = '%sgrupos_%s.json' % (path, _id.split('@')[0].strip()) print(group) with open(filename, 'w') as json_file: json.dump(group, json_file) print('', file=json_file) with open(all_groups_filename, 'a') as json_file: json.dump(group, json_file) print('', file=json_file) driver.close() except Exception as e: print(e) driver.close() raise Exception(e)
def run(self, profile_path="/data/firefox_cache"): """ Faz a coleta das mensagens de grupos de Whatsapp de acordo com os parâmetros fornecidos na criação do objeto de coleta. Parâmetros ------------ profile_path : str Caminho para um profile alternativo do navegador utilizado na coleta. """ if not os.path.exists(profile_path): os.makedirs(profile_path) driver = WhatsAPIDriver(loadstyles=True, profile=profile_path, client="remote", command_executor=os.environ["SELENIUM"]) pathlib.Path("/data/mensagens").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/image").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/audio").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/video").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/mensagens_grupo").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/notificacoes").mkdir(parents=True, exist_ok=True) pathlib.Path("/data/mids").mkdir(parents=True, exist_ok=True) min_date = self.start_date max_date = self.end_date include_notf = self.collect_notifications looping = True if (self.collection_mode == 'period') and (min_date < '2020-01-01'): raise Exception("Can't start collection without a start and end" " date.") while looping: if self.collection_mode == 'continuous': looping = True else: looping = False try: print("Waiting for WhatsApp Web Login") driver.wait_for_login() print("Saving session") driver.save_firefox_profile(remove_old=False) print("Bot started") print('>>>>>>>>>>> Loading previous saved Messages') messagesID = self._get_load_messages() notificationsID = self._get_load_notifications() today_date = datetime.date.today().strftime("%Y-%m-%d") date_format = "%Y-%m-%d" file_name = "/data/mensagens/mensagens_" + today_date + ".json" start_date = min_date print('>>>>>>>>>>>>Getting Groups Messages...', end=' ') chats = driver.get_all_chats() count = 0 all_chats = list(chats) print(' DONE! %d chats loaded!' % (len(all_chats))) random.shuffle(all_chats) for chat in (all_chats): # Does not collect direct messages, only group chats if not chat._js_obj['isGroup']: continue gid = chat.id gid = gid.split('@')[0] s_name = self._process_string(chat.name) # Skip group if it is on blacklist (can be name or groupID) if (s_name in self.group_blacklist or gid in self.group_blacklist): continue # PRINT CHAT INFORMATION members = chat._js_obj['groupMetadata']['participants'] timestamp = gid.split('-')[-1] date = convert_data_from_timestamp(float(timestamp)) str_date = date.strftime('%Y-%m-%d %H:%M:%S') chat_print = "<Group chat - {name}: {id}, {participants} " \ "participants - at {time}!!>".format( name=s_name, id=gid, participants=len(members), time=str_date) print('>>>>>Loading messages from', chat_print) if gid not in messagesID: messagesID[gid] = dict() messagesID[gid]['messages'] = set() messagesID[gid]['date'] = '2000-01-01' # PROCESS PREVIOUS LOADED MESSAGES ID AND LAST DATE if self.collection_mode == 'continuous': if messagesID[gid]['date'] > max_date: continue if messagesID[gid]['date'] > min_date: start_date = messagesID[gid]['date'] till_date = datetime.datetime.strptime(start_date, date_format) else: start_date = min_date till_date = datetime.datetime.strptime(start_date, date_format) # LOAD MESSAGES FROM WHATSAPP SINCE MIN_DATE messages = chat.load_earlier_messages_till(till_date) messages = driver.get_all_message_ids_in_chat( chat, include_notifications=include_notf) elif self.collection_mode == 'period': till_date = datetime.datetime.strptime(start_date, date_format) # LOAD MESSAGES FROM WHATSAPP SINCE MIN_DATE messages = chat.load_earlier_messages_till(till_date) messages = driver.get_all_message_ids_in_chat( chat, include_notifications=include_notf) elif self.collection_mode == 'unread': # LOAD UNREAD MESSAGES FROM WHATSAPP messages = chat.get_unread_messages( include_me=False, include_notifications=include_notf) print('>>>>>Total messages %d' % (len(messages))) count += 1 for msg in messages: count += 1 gid = gid.split('@')[0] mid = msg if self._is_notification(mid): if gid not in notificationsID.keys(): notificationsID[gid] = set() if mid.strip() in notificationsID[gid]: continue j = driver.get_message_by_id(mid) self._save_notification_(j, gid) continue if mid.strip() in messagesID[gid]['messages']: print('Message: %d >>> %s from %s was CHECKED' % (count, mid, gid)) continue else: try: j = driver.get_message_by_id(mid) except Exception as e: print('Error getting a message >>', e) continue if not j: continue sender = j.sender.id sender = sender.replace(' ', '').strip() sender = sender.split('@')[0] if (sender in self.user_blacklist or '+' + sender in self.user_blacklist): continue try: date = self._get_date_from_message(j) except Exception: continue if (date > max_date) and (self.collection_mode == 'period'): break if (date < start_date): continue # Update day if today_date != date: today_date = date file_name = "/data/mensagens/mensagens_" + today_date + ".json" if self.collect_images: try: self._get_image_from_message(j) except Exception as ei: print('!!!!Error getting image!!!! ', ei) if self.collect_videos: try: self._get_video_from_message(j) except Exception as ev: print('!!!!Error getting video!!!! ', ev) if self.collect_audios: try: self._get_audio_from_message(j) except Exception as ea: print('!!!!Error getting audio!!!! ', ea) if self.collect_messages: self._save_message(j, s_name, gid, mid, file_name) driver.close() except Exception as e: print(e) driver.close() raise Exception(e) if looping: print('Waiting code to start again...') time.sleep(3600)
# Deactivating reload with db_conn.cursor() as cur: cur.execute(deactivate_reload, ( process_note, reload_contact_row_id, )) db_conn.commit() logging.info("Reloading deactivated for " + str(reload_contact_row_sender)) chat.send_seen() else: logging.debug("Nothing to reload, continue") except Exception as e: logging.exception(e) if 'driver' in locals() and driver is not None: driver.close() logging.info('Selenium driver connection closed') if 'db_conn' in locals() and db_conn is not None: db_conn.close() logging.info('Database connection closed') raise finally: if 'driver' in locals() and driver is not None: driver.close() logging.info('Selenium driver connection closed') if 'db_conn' in locals() and db_conn is not None: db_conn.close() logging.info('Database connection closed')
class WPChannelBot(): def __init__(self): self.model = WPChannelBotModel() self.data = self.model.get_all() self.convs = self.model.get_convs() self.convs_state = self.model.get_convs_state() self.simple_steps = True self.log_file = "log/chatbot.log" self.cmd_wait_from = None self.cmd_wait = False self.profile = "profile" self.driver = None def start(self): print("Iniciando bot...") self.driver = WhatsAPIDriver(profile=self.profile) time.sleep(3) if not self.driver.get_status() == "LoggedIn": print("Carregando QRCode") self.driver.get_qr("qrcode.png") print("Escaneie o QRCode no arquivo qrcode.png") self.driver.wait_for_login() print("Bot iniciado") self.driver.save_firefox_profile() while True: time.sleep(1) for contact in self.driver.get_unread(include_me=False, include_notifications=True, use_unread_count=True): if len(contact.messages) == 1: for message in contact.messages: if isinstance(message, Message): self.new_message(message.content, contact) self.driver.chat_send_seen(contact.chat.id) time.sleep(3) else: contact.chat.send_message( "Fico confuso com muitas mensagens :S Por favor, envie uma de cada vez e espere eu responder tá?" ) contact.chat.send_message(CHANNEL_ASK_KEYWORD) def new_message(self, message, contact): if not self._is_cmd(message): if self.cmd_wait and contact.chat.id == self.cmd_wait_from: self._cmd_envio(message, contact.chat) elif not contact.chat.id in self.convs: self._proc_etapa(contact.chat.id, message, contact.chat, 2) else: for conv in self.convs_state: if conv['id'] == contact.chat.id: e = self._proc_etapa(contact.chat.id, message, contact.chat, conv['etapa']) conv['etapa'] = e self.model.conv_update(contact.chat.id, e) else: print("ADMINISTRADOR") self._run_cmd(message, contact.chat) def shutdown(self): print("Desconectando...") self.driver.close() time.sleep(3) print("Desconectado") def _already_user(self, id, chat): if isinstance(self.model.get(id), dict): chat.send_message( "Olá, você já está cadastrado neste canal. Assim que tiver novidade você vai receber!" ) return True else: return False def _is_keyword(self, content, chat): if content.lower() == CHANNEL_KEYWORD: return True else: chat.send_message(CHANNEL_ASK_KEYWORD) return False def _proc_etapa(self, id, content, chat, etapa): if etapa == 2: if not self._already_user(id, chat) and self._is_keyword( content, chat): # Efetua registros self.convs.append(id) self.convs_state.append({"id": id, "etapa": 4}) self.model.conv_add(id, 4) # Introdução do canal - Solicita nome chat.send_message(CHANNEL_INTRO) chat.send_message(CHANNEL_MSGS[0]) self._to_log("Iniciando cadastro: %s" % id) elif etapa == 4: # Armazena nome - Solicita cidade if self.simple_steps: self.data.append({"id": id, "nome": content}) # Salva no banco de dados self.model.add(id, content) chat.send_message((CHANNEL_MSGS[3] % content)) self._remove_convs(id) self._to_log("Finalizado cadastro: %s - %s" % (id, content)) else: self.data.append({ "id": id, "nome": content, "cidade": "", "bairro": "" }) chat.send_message(CHANNEL_MSGS[1]) # Salva no banco de dados self.model.add(id, content) self._to_log("Registrado nome: %s - %s" % (id, content)) return 6 elif etapa == 6: # Implementar veficação de validade de cidade # Verifica cidade - volta ao 5 : armazena cidade - solicita bairro ou passo for obj in self.data: if obj["id"] == id: obj["cidade"] = content self.model.update(id=id, cidade=content) chat.send_message(CHANNEL_MSGS[2]) self._to_log("Registrado cidade: %s - %s" % (id, content)) return 7 elif etapa == 7: # Implementar veficação de validade de bairro if content == "passo": # Finaliza caso não seja informado bairro chat.send_message((CHANNEL_MSGS[3] % self._get_conv_nome(id))) self._remove_convs(id) self._to_log("Finalizado cadastro: %s - %s" % (id, content)) else: # Armazena bairro - Finaliza cadastro for obj in self.data: if obj["id"] == id: obj["bairro"] = content self.model.update(id=id, bairro=content) chat.send_message( (CHANNEL_MSGS[3] % self._get_conv_nome(id))) self._remove_convs(id) self._to_log("Finalizado cadastro: %s - %s" % (id, content)) def _to_log(self, log): file = open(self.log_file, "a") file.write("\n>> %s " % log) file.close() return def _get_conv_nome(self, id): for obj in self.data: if obj["id"] == id: return obj["nome"] def _remove_convs(self, id): self.convs.remove(id) for conv in self.convs_state: if conv["id"] == id: self.convs_state.remove(conv) self.model.conv_delete(id) def _is_cmd(self, content): if content[:4] == "/cmd": return True else: return False def _run_cmd(self, content, chat): cmd = content[5:] if not self.model.check_admin(chat.id) == False: if cmd == "usuarios": self._cmd_usuarios(chat) elif cmd == "envio": self.cmd_wait = True self.cmd_wait_from = chat.id chat.send_message( "*ENVIE A SEGUIR A MENSAGEM A SER ENVIADA PARA O CANAL*") else: chat.send_message("*COMANDO NÃO RECONHECIDO*") elif self.model.check_admin(id=None, all=True) == False and cmd[:5] == "admin": print("Cadastrando novo admin") self.model.add_admin(chat.id, content[11:]) chat.send_message("*ADMINISTRADOR CADASTRADO*") else: chat.send_message(CHANNEL_ASK_KEYWORD) def _cmd_usuarios(self, chat): response = "*USUÁRIOS CADASTRADOS*\n\n" i = 0 users = self.model.get_all() for user in users: i += 1 response += "\n%d) %s - %s" % (i, user['id'], user['nome']) chat.send_message(response) def _cmd_envio(self, content, chat): i = 0 users = self.model.get_all() for user in users: i += 1 self.driver.send_message_to_id(user['id'], content) self.cmd_wait_from = None self.cmd_wait = False chat.send_message("*MENSAGEM ENVIADA PARA %d USUÁRIOS DO CANAL*" % i)