def get_crawl_max_count(): config = MonitorConfig() crawl_max_count = config.get_value('appiumConfig', 'crawl_max_count') Logger.println(f"【crawl_max_count={crawl_max_count}】") if not crawl_max_count: return '100' return crawl_max_count
def batch_export_upload(full_dir): global upload_md5_pic_position upload_md5_pic_position = 0 global index start_time = int(time.time()) config = MonitorConfig() sleeptime = 3 * 60 value = config.get_value('appiumConfig', 'batch_pic_seconds') if value: sleeptime = int(value) Logger.println( f"【====================开始批量导出并上传图片batch_pic_seconds={sleeptime}=======================】") while True: time.sleep(5) time_start_time = int(time.time()) - start_time if sleeptime - time_start_time > 0: Logger.println( f"=================【{sleeptime - time_start_time}秒后执行第={index}个批量导出并上传图片任务===================】") if time_start_time >= sleeptime: index = index + 1 break time.sleep(5) PicClassfyUtil.classify_from(full_dir) excel_full_dir = FilePathUtil.get_lastmodify_file( FilePathUtil.get_full_dir("wxfriend", "excel", "pic")) main(excel_full_dir) if wx_stop.stopFlag: Logger.println(f"【===================批量导出并上传图片任务停止=================】") return batch_export_upload(full_dir)
def get_addfriend_inte_seconds(): config = MonitorConfig() addfriend_inte_seconds = config.get_value('appiumConfig', 'addfriend_inte_seconds') Logger.println(f"【get_addfriend_inte_seconds={addfriend_inte_seconds}】") if not addfriend_inte_seconds: return '3600' return addfriend_inte_seconds
def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.wx_content_md5 = self.config.get_value("wx_content", "md5_pic")
def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.last_record_phone = self.config.get_value("wx_content", "last_phone") self.max_count = int(WxConfig.get_add_friend_max_count()) self.addfriend_inte_seconds = int( WxConfig.get_addfriend_inte_seconds())
def open_dir(self): config = MonitorConfig() value = config.get_value('leidian', 'default_dir') dir_path = None if value: # 选择文件夹对话框: dir_path = QtWidgets.QFileDialog.getExistingDirectory( self, "选择目录", value) else: dir_path = QtWidgets.QFileDialog.getExistingDirectory( self, "选择目录", "C://Users//Administrator//Desktop") if dir_path: config.set_value('leidian', 'default_dir', dir_path) print(dir_path) return dir_path
def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig()
def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.md5_contents = [] full_dir = FilePathUtil.get_lastmodify_file( FilePathUtil.get_full_dir("wxfriend", "excel", "pic")) array = excel_util.excel2array(full_dir) if array: for item in array: self.md5_contents.append(item['content_md5'])
def getAppDownloadUrl(): config = MonitorConfig() app_download_url = config.get_value('appiumConfig', 'app_download_url') Logger.println(f"【app_download_url={app_download_url}】") return app_download_url
def setPhoneExcel(phone_excel): config = MonitorConfig() phone_excel = config.set_value('appiumConfig', 'phone_excel', phone_excel) return phone_excel
def getPhoneExcel(): config = MonitorConfig() phone_excel = config.get_value('appiumConfig', 'phone_excel') Logger.println(f"【手机号excel文件={phone_excel}】") return phone_excel
def getServerUrl(): config = MonitorConfig() driver_server = config.get_value('appiumConfig', 'driver_server') Logger.println(f"【服务器地址={driver_server}】") return driver_server
def set_get_addfriend_inte_seconds(addfriend_inte_seconds): config = MonitorConfig() config.set_value('appiumConfig', 'addfriend_inte_seconds', addfriend_inte_seconds)
class MainUi(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.init_ui() def editConfigDialog(self): ''' 配置 :return: ''' win = ConfigDialog() win.show() win.setMinimumSize(720, 60) # 设置窗口的属性为ApplicationModal模态,用户只有关闭弹窗后,才能关闭主界面 win.setWindowModality(Qt.ApplicationModal) win.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # 置顶 win.exec_() def openPicDir(self): startfile(FilePathUtil.get_full_dir('wxfriend', 'pic')) # def exportPhone(self): # full_dir = FilePathUtil.get_full_dir("wxfriend", "excel") # filepath = self.open_file(full_dir) # if filepath: # self.call_backlog("正在提取电话号码 ,请稍后...") # self.runthread6.set_data(filepath) # self.runthread6.start() def download(self): startfile(FilePathUtil.get_full_dir('dist', 'UpgradeHelper.exe')) self.close() def openPhoneDir(self): startfile(FilePathUtil.get_full_dir('wxfriend', 'excel', 'pic')) def init_ui(self): self.setMinimumSize(960, 760) self.main_widget = QtWidgets.QWidget() # 创建窗口主部件 self.main_layout = QtWidgets.QGridLayout() # 创建主部件的网格布局 self.main_widget.setLayout(self.main_layout) # 设置窗口主部件布局为网格布局 self.config = MonitorConfig() # 配置服务器地址 configAction = QAction(QIcon('exit.png'), '配置', self) configAction.setShortcut('Ctrl+Alt+S') configAction.setStatusTip('配置') configAction.triggered.connect(self.editConfigDialog) # 配置服务器地址 picAction = QAction(QIcon('exit.png'), '打开图片文件夹', self) picAction.setShortcut('Ctrl+O') picAction.setStatusTip('图片文件夹') picAction.triggered.connect(self.openPicDir) downloadAction = QAction(QIcon('exit.png'), '下载最新版本', self) downloadAction.setStatusTip('下载最新版本') downloadAction.triggered.connect(self.download) # exportAction = QAction(QIcon('exit.png'), '从"描述"字段中提取手机号', self) # exportAction.setStatusTip('从"描述"字段中提取手机号') # exportAction.triggered.connect(self.exportPhone) # 底部状态栏 self.statusBar().showMessage('状态栏') # 顶部菜单栏 menubar = self.menuBar() menubar.setNativeMenuBar(False) fileMenu = menubar.addMenu('配置') fileMenu.addAction(configAction) # exMenu = menubar.addMenu('提取手机号') # exMenu.addAction(exportAction) picMenu = menubar.addMenu('打开图片文件夹') picMenu.addAction(picAction) downloadMenu = menubar.addMenu('版本更新') downloadMenu.addAction(downloadAction) openAction = QAction(QIcon(IconConfig.SETTING_DIR), '打开手机号配置目录', self) openAction.setShortcut('Ctrl+O') openAction.triggered.connect(self.openPhoneDir) self.toolbar = self.addToolBar('打开手机号配置目录') self.toolbar.addAction(openAction) self.left_widget = QtWidgets.QWidget() # 创建左侧部件 self.left_widget.setObjectName('left_widget') self.left_layout = QtWidgets.QGridLayout() # 创建左侧部件的网格布局层 self.left_widget.setLayout(self.left_layout) # 设置左侧部件布局为网格 self.right_widget = QtWidgets.QWidget() # 创建右侧部件 self.right_widget.setObjectName('right_widget') self.right_layout = QtWidgets.QGridLayout() self.right_widget.setLayout(self.right_layout) # 设置右侧部件布局为网格 self.main_layout.addWidget(self.left_widget, 0, 0, 3, 2) # 左侧部件在第0行第0列,占8行3列 self.main_layout.addWidget(self.right_widget, 0, 2, 12, 10) # 右侧部件在第0行第3列,占8行9列 self.setCentralWidget(self.main_widget) # 设置窗口主部件 models = [ { 'label': '导出微信通讯录', 'objName': 'left_label' }, { 'label': '批量添加好友', 'objName': 'left_label' }, { 'label': '批量修改备注为手机号', 'objName': 'left_label' }, { 'label': '导出朋友圈信息', 'objName': 'left_label' }, { 'label': '导出含文本朋友圈信息', 'objName': 'left_label' }, { 'label': '导出图片到电脑', 'objName': 'left_label' }, { 'label': '按文本内容对图片分组', 'objName': 'left_label' }, { 'label': '上传文本到后台', 'objName': 'left_label' }, { 'label': '上传图片到后台', 'objName': 'left_label' }, { 'label': '开启导出图片并上传任务', 'objName': 'left_label' }, { 'label': '恢复输入法', 'objName': 'left_label' }, { 'label': '删除手机图片缓存', 'objName': 'left_label' }, { 'label': '抓取当天遗漏数据', 'objName': 'left_label' }, { 'label': '停止任务', 'objName': 'left_label' }, ] self.buttons = [] for index, model in enumerate(models): btn = QtWidgets.QPushButton(model['label']) btn.setObjectName(model['objName']) self.buttons.append(btn) for index, btn in enumerate(self.buttons): self.left_layout.addWidget(btn, index, 0, 1, 3) if index == 0: btn.clicked.connect(self.clickGetContacts) elif index == 1: btn.clicked.connect(self.clickAddFriend) elif index == 2: btn.clicked.connect(self.clickModifyName) elif index == 3: btn.clicked.connect(self.clickTextWithPicMoment) elif index == 4: btn.clicked.connect(self.clickTextMoment) elif index == 5: btn.clicked.connect(self.clickExportPic) elif index == 6: btn.clicked.connect(self.clickPicClassfy) elif index == 7: btn.clicked.connect(self.clickUploadText) elif index == 8: btn.clicked.connect(self.clickUploadPic) elif index == 9: btn.clicked.connect(self.clickBatchUploadLabel) elif index == 10: btn.clicked.connect(self.clickKeyboardLabel) elif index == 11: btn.clicked.connect(self.clickClearPics) elif index == 12: btn.clicked.connect(self.clickGetLostLabel) elif index == 13: btn.clicked.connect(self.clickStopLabel) self.left_widget.setStyleSheet(''' QPushButton#left_label{ padding:10px; font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; } ''') self.right_widget.setStyleSheet(''' QTextEdit#right_label{ font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; } ''') self.runthread = Runthread(EventConst.WX_CONTACT) self.runthread0 = Runthread(EventConst.MAIN_BULK_ADDFRIEND) self.runthread01 = Runthread(EventConst.MAIN_BULK_M_NAME) self.runthread1 = Runthread(EventConst.WX_MAIN_PIC) self.runthread2 = Runthread(EventConst.WX_MAIN) self.runthread3 = Runthread(EventConst.WX_EXPORT) self.runthread31 = Runthread(EventConst.WX_PICCLASSFY) self.runthread4 = Runthread(EventConst.WX_UPLOADER) self.runthread5 = Runthread(EventConst.WX_PICUPLOADER) self.runthread6 = Runthread(EventConst.WX_EXPORT_PHONE) self.runthread7 = Runthread(EventConst.WX_BATCH_UPLOAD) self.runthread8 = Runthread(EventConst.WX_CLEAR_PIC) self.runthread9 = Runthread(EventConst.WX_GET_LOST_PIC) self.stopRunner = StopRunthread() self.boardRunthread = KeyBoardRunthread() self.runthread.signals.connect(self.call_backlog) self.runthread0.signals.connect(self.call_backlog) self.runthread01.signals.connect(self.call_backlog) self.runthread1.signals.connect(self.call_backlog) self.runthread2.signals.connect(self.call_backlog) self.runthread3.signals.connect(self.call_backlog) self.runthread31.signals.connect(self.call_backlog) self.runthread4.signals.connect(self.call_backlog) self.runthread5.signals.connect(self.call_backlog) self.runthread6.signals.connect(self.call_backlog) self.runthread7.signals.connect(self.call_backlog) self.runthread8.signals.connect(self.call_backlog) self.runthread9.signals.connect(self.call_backlog) self.stopRunner.signals.connect(self.call_backlog) self.boardRunthread.signals.connect(self.call_backlog) self.right_label = QtWidgets.QTextEdit("") self.right_label.setPlaceholderText("日志输出区") self.right_label.setObjectName('right_label') self.right_layout.addWidget(self.right_label, 0, 0, 1, 3) # self.setWindowOpacity(0.9) # 设置窗口透明度 self.setWindowTitle('屋聚科技自动化运营工具V2.1') self.setWindowIcon(QIcon(IconConfig.LOGO_DIR)) # self.setAttribute(QtCore.Qt.WA_TranslucentBackground) # 设置窗口背景透明 # self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隐藏边框 self.main_layout.setSpacing(0) excel = WxConfig.getPhoneExcel() if excel: self.statusBar().showMessage(f'手机号文件地址:{excel}') else: self.statusBar().showMessage(f'请先点击配置菜单配置数据') value = self.config.get_value("wx_content", "select") if value == 'True': self.buttons[7].setEnabled(False) else: self.buttons[7].setEnabled(True) def call_backlog(self, text): self.right_label.append(f"{text}") def clickGetContacts(self): self.buttons[0].setEnabled(False) self.call_backlog("正在获取通讯录,请稍后...") self.runthread.start() def clickAddFriend(self): self.buttons[1].setEnabled(False) self.call_backlog("正在批量添加好友,请稍后...") self.runthread0.start() def clickModifyName(self): self.buttons[2].setEnabled(False) self.call_backlog("正在批量修改备注,请稍后...") self.runthread01.start() def clickTextWithPicMoment(self): self.call_backlog("正在导出朋友圈信息,请稍后...") self.buttons[3].setEnabled(False) self.runthread1.start() def clickTextMoment(self): self.buttons[4].setEnabled(False) self.call_backlog("导出文本朋友圈信息,请稍后...") self.runthread2.start() def clickExportPic(self): self.call_backlog("正在导出图片到电脑 ,请稍后...") self.runthread3.start() def clickPicClassfy(self): self.call_backlog("正在按文本内容对图片分组 ,请稍后...") full_dir = FilePathUtil.get_full_dir("wxfriend", "excel", "pic") filepath = self.open_file(full_dir) if filepath: self.call_backlog("正在按文本内容对图片分组 ,请稍后...") self.runthread31.set_data(filepath) self.runthread31.start() def open_file(self, dir): fileName, fileType = QtWidgets.QFileDialog.getOpenFileName( self, "选取文件", dir, "All Files(*);;Text Files(*.xls)") print(fileName, fileType) return fileName def open_dir(self): config = MonitorConfig() value = config.get_value('leidian', 'default_dir') dir_path = None if value: # 选择文件夹对话框: dir_path = QtWidgets.QFileDialog.getExistingDirectory( self, "选择目录", value) else: dir_path = QtWidgets.QFileDialog.getExistingDirectory( self, "选择目录", "C://Users//Administrator//Desktop") if dir_path: config.set_value('leidian', 'default_dir', dir_path) print(dir_path) return dir_path def clickUploadText(self): full_dir = FilePathUtil.get_full_dir("wxfriend", "excel", "pic") filepath = self.open_file(full_dir) if filepath: self.runthread4.set_data(filepath) self.call_backlog("正在上传文本到后台 ,请稍后...") self.runthread4.start() def clickUploadPic(self): full_dir = FilePathUtil.get_full_dir("wxfriend", "excel", "pic") filepath = self.open_file(full_dir) if filepath: self.runthread5.set_data(filepath) self.call_backlog("正在上传图片到后台 ,请稍后...") self.runthread5.start() def clickStopLabel(self): self.stopRunner.start() for btn in self.buttons: btn.setEnabled(True) def clickKeyboardLabel(self): self.boardRunthread.start() def clickBatchUploadLabel(self): filepath = self.open_dir() if filepath: self.runthread7.set_data(filepath) self.buttons[9].setEnabled(False) self.runthread7.start() def clickGetLostLabel(self): self.buttons[12].setEnabled(False) self.runthread9.start() def clickClearPics(self): result = QMessageBox.warning(self, '确定', '确认删除手机Weixin文件夹?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if result == QMessageBox.Yes: self.runthread8.start()
def setAppexeReplaceDir(appexe_replace_dir): config = MonitorConfig() appexe_replace_dir = config.set_value('appiumConfig', 'appexe_replace_dir', appexe_replace_dir) return appexe_replace_dir
def crawl(self): self.config = MonitorConfig() self.wx_content_md5 = self.config.get_value("wx_content", "md5_pic") self.md5_contents = [] self.enter() """ 爬取 :return: """ index = 0 isFirst = True contents = [] lastItem = None while True: self.crawl_max_count = int(WxConfig.get_crawl_max_count()) if index % self.crawl_max_count == 0: self.md5_contents.clear() Logger.println( f"【======={index},抓取数退出{self.crawl_max_count},本轮抓取已完成,开始滑动到顶部下拉刷新继续==========】" ) self.swipe_to_top() if wx_stop.stopFlag: break # 上滑 if not isFirst: self.swipe_up_slow() isFirst = False top_element = self.wait_find_element( By.XPATH, '//android.support.v7.widget.LinearLayoutCompat') if lastItem and top_element: self.scrollElement(lastItem, top_element) sleep(3) items = self.wait_find_elements( By.XPATH, '//android.widget.ListView/android.widget.RelativeLayout') if items is None: Logger.println(f"【============未获取到列表================】") continue for item in items: accessibility_id = self.find_element_by_accessibility_id( '头像', item) if accessibility_id: lastItem = item b_e_content = None last_pic_md5 = None last_md5_ = None advise = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'广告')]", item) if advise: Logger.println( f"【============检测到广告忽略进入下一条================】") continue message_text_container = self.config.get_value( "wx_content_ids", "message_text_container") content_element = self.find_element_by_id( message_text_container, item) if content_element: content_element.click() b_e_content = self.waitContentTextById( "com.tencent.mm:id/fpu") if b_e_content: Logger.println(f"【获取到详情页面全文内容={b_e_content}】") self.go_back() if b_e_content is None: message_text = self.config.get_value( "wx_content_ids", "message_text") b_e_content = self.getContentTextById(message_text, item) if b_e_content is None: Logger.println(f"【============该条说说没有文本,忽略===========】") continue nickName = self.getNickName(item) phone = self.get_phone_from_txt(b_e_content) md5_ = self.MD5(b_e_content) if len(b_e_content) > 3 and b_e_content[-3:] == '...': elment_datas = self.scan_all_text_elment(item) LogUtil.info_jsonformat(elment_datas) contition = (last_md5_ in self.wx_content_md5) and ( md5_ in self.wx_content_md5 ) if last_md5_ else md5_ in self.wx_content_md5 if contition: Logger.println( f"【crawl{index}已经抓取到上一次位置md5_=({md5_},last_md5_={last_md5_}).data={b_e_content}】" ) md5 = None if len(self.md5_contents) > 1: md5 = ','.join(self.md5_contents[0:2]) elif len(self.md5_contents) > 0: md5 = self.md5_contents[0] if md5: self.config.set_value("wx_content", "md5_pic", md5) Logger.println(f"【============开始滑动到顶部===========】") Logger.dingdingException(f"本轮抓取已完成,开始滑动到顶部下拉刷新继续") self.swipe_to_top() break if md5_ in self.today_md5_contents: last_md5_ = md5_ Logger.println(f"【============该条说说已经抓取过,忽略===========】") continue image0 = self.find_element_by_xpath("//*[@content-desc='图片']", item) if image0: Logger.println(f"【crawl({index}).开始点击图片】") image0.click() sleep(2) start = '0' end = '0' for index_img in range(9): image_detail = self.find_element_by_id( 'com.tencent.mm:id/c9h') if image_detail: text_content = self.wait_find_element( By.XPATH, "//*[contains(@content-desc,'当前')]" ).get_attribute('content-desc') Logger.println( f"【crawl.{index} text_content ={text_content}】" ) pic_md5 = self.MD5(text_content) if last_pic_md5 == pic_md5: Logger.println( f"【crawl({index}.{index_img}).前后图片一致退出】") if not end: sleep(2) end = time_util.get_time() data = { 'content_md5': md5_, 'nick_name': nickName, 'wx_number': "", 'content': b_e_content, 'phone': phone, 'start': start, 'end': end, 'crawl_time': time_util.now_to_date(), 'count': str(index_img) } if start != '0': contents.append(data) self.md5_contents.append(md5_) self.today_md5_contents.append(md5_) last_md5_ = md5_ self.go_back() break try: action1 = TouchAction(self.driver) action1.long_press(el=image_detail, duration=500).perform() saveBtn = self.wait_find_element( By.XPATH, "//*[contains(@text,'保存图片')]") if saveBtn: saveBtn.click() element = self.wait_find_element( By.XPATH, "//*[contains(@text,'图片已保存')]") attribute = element.get_attribute('text') Logger.println( f"【crawl.{index} text_content ={attribute}】" ) if attribute and ".jpg" in attribute: if index_img == 0: start = get_time_from_text( attribute) end = get_time_from_text(attribute) else: Logger.dingdingException(f"找不到保存按钮,保存图片失败") except Exception as e: Logger.dingdingException(f"保存图片失败{e}") Logger.println(f'保存图片失败 Exception{e}') self.go_back() continue last_pic_md5 = pic_md5 if index_img == 8: if not end: sleep(2) end = time_util.get_time() data = { 'content_md5': md5_, 'nick_name': nickName, 'wx_number': "", 'content': b_e_content, 'phone': phone, 'start': start, 'end': end, 'crawl_time': time_util.now_to_date(), 'count': str(index_img + 1) } if start != '0': Logger.println( f"【crawl({index}.{index_img}).已保存图片=mmexport{end}.jpg】" ) contents.append(data) self.md5_contents.append(md5_) self.today_md5_contents.append(md5_) last_md5_ = md5_ self.go_back() break self.swipeLeft() else: # 纯文本 data = { 'content_md5': md5_, 'nick_name': nickName, 'wx_number': "", 'content': b_e_content, 'phone': phone, 'start': "0", 'end': "0", 'crawl_time': time_util.now_to_date(), 'count': "0" } contents.append(data) if len(contents) > 0: value = self.config.get_value("wx_content", "select") if value == 'True': Logger.println(f"开始上传第{index}条数据") res = WxUploader.uploadItems(contents) # 有房源刷新的列表 if '20003' == res: contents[0]['content'] = "" date = time_util.now_to_date('%Y%m%d') full_dir = FilePathUtil.get_full_dir( "wxfriend", "excel", "text", date + "wx_pic_update_moments.xls") excel_util.write_excel_append(filename=full_dir, worksheet_name=date, items=contents) contents.clear() # 新房源列表 if len(contents) > 0: contents[0]['content'] = "" date = time_util.now_to_date('%Y%m%d') full_dir = FilePathUtil.get_full_dir( "wxfriend", "excel", "pic", date + "wx_pic_moments.xls") excel_util.write_excel_append(filename=full_dir, worksheet_name=date, items=contents) contents.clear() index += 1 else: Logger.println(f"【没有数据不处理】") md5 = None if len(self.md5_contents) > 1: md5 = ','.join(self.md5_contents[0:2]) elif len(self.md5_contents) > 0: md5 = self.md5_contents[0] if md5: self.config.set_value("wx_content", "md5_pic", md5)
def set_friend_max_count(addFriendMaxCount): config = MonitorConfig() config.set_value('appiumConfig', 'addFriendMaxCount', addFriendMaxCount)
def get_add_friend_max_count(): config = MonitorConfig() addFriendMaxCount = config.get_value('appiumConfig', 'addFriendMaxCount') Logger.println(f"【addFriendMaxCount={addFriendMaxCount}】") return addFriendMaxCount
class Moments(MomentsBase): def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.max_count = int(WxConfig.get_add_friend_max_count()) self.addfriend_inte_seconds = int( WxConfig.get_addfriend_inte_seconds()) self.config = MonitorConfig() self.last_record_phone = self.config.get_value( "wx_content", "add_friend_last_phone") def add(self, phone): sleep(self.get_sleep(6, 8)) # 输入电话号码 try: self.find_element_by_id('com.tencent.mm:id/bhn').send_keys(phone) except: pass sleep(self.get_sleep(5, 8)) try: self.find_element_by_id('com.tencent.mm:id/f8g').click() sleep(self.get_sleep(4, 6)) except: pass try: xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'用户不存在')]") if xpath: Logger.println(f"【main(用户不存在={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click() self.config.set_value("wx_content", "add_friend_last_phone", phone) sleep(self.get_sleep(1, 2)) return False xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'被搜账号状态异常')]") if xpath: Logger.println(f"【main(被搜账号异常无法显示={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click() self.config.set_value("wx_content", "add_friend_last_phone", phone) sleep(self.get_sleep(1, 2)) return False else: xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'操作过于频繁,请稍后再试')]" ) if xpath: Logger.println(f"【main(操作过于频繁,请稍后再试={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click( ) return True except Exception as e: Logger.println(f"【add().e={e}】") pass # 点击添加好友 try: addbtn = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'添加到通讯录')]") if addbtn: addbtn.click() sleep(self.get_sleep(5, 6)) send_btn = self.find_element_by_xpath( "//android.widget.Button[contains(@text,'发送')]") if send_btn: send_btn.click() self.config.set_value("wx_content", "add_friend_last_phone", phone) sleep(self.get_sleep(1, 2)) send_btn = self.find_element_by_xpath( "//android.widget.Button[contains(@text,'发送')]") if send_btn: self.driver.back() sleep(self.get_sleep(1, 2)) self.driver.back() else: Logger.println(f"【main(号码已添加无需添加={phone}】") self.driver.back() else: Logger.println(f"【main(号码已添加无需添加={phone}】") self.driver.back() except Exception as e: Logger.println(f"【add().e={e}】") pass def main(self): sleep(self.get_sleep(6, 10)) # 点击搜索按钮 self.find_element_by_id('com.tencent.mm:id/f8y').click() sleep(self.get_sleep(3, 5)) # full_dir = FilePathUtil.get_full_dir("wxfriend", "excel", "手机号列表.xls") full_dir = WxConfig.getPhoneExcel() if not full_dir: Logger.println(f"【main(请先配置手机号列表文件】") return array = excel_util.excel2array(full_dir) length = len(array) if not array: Logger.println(f"【main(请先配置手机号列表文件的sheet_name为手机号列表】") return # array = [{'手机': '18612205027'}] # array = [{'手机': '18612205027'}, {'手机': '15821902923'}] start_index = 0 for index, element in enumerate(array): if str(int(element["手机"])) == self.last_record_phone: start_index = index Logger.println( f"【main找到上次添加的手机位置={start_index + 1}={self.last_record_phone}】" ) break count = 0 if start_index + 1 > length: Logger.println(f"【已经是最后一条了】") return for index, item in enumerate(array[start_index + 1:length]): if wx_stop.stopFlag: break phone = str(int(item['手机'])) Logger.println(f"【main({index}).开始添加手机={phone}】") Logger.println(f"【main开始执行第{count}个任务】") if self.max_count > 1 and count > 1 and (count % self.max_count) == 0: start_time = int(time()) sleeptime = self.addfriend_inte_seconds Logger.println( f"【main(暂时停止任务开启休闲模式).{sleeptime}秒后执行第={count}个任务】") while True: rdsleep = self.get_sleep(5, 6) by_id = self.find_element_by_id('com.tencent.mm:id/bhn') if rdsleep == 5: if by_id: by_id.send_keys(f'已经休眠{int(time()) - start_time}s') else: if by_id: by_id.send_keys('') sleep(rdsleep) if int(time()) - start_time > sleeptime: break Logger.println(f"【main(退出休闲模式)继续执行第={count}个任务】") if wx_stop.stopFlag: break if self.add(phone): break count += 1 Logger.println(f"【main(花费时间).total_count={self.total_count}s】") # self.add('13120749104') def main_backgroud(self): thread = threading.Thread(target=self.main) thread.start()
def init_ui(self): self.setMinimumSize(960, 760) self.main_widget = QtWidgets.QWidget() # 创建窗口主部件 self.main_layout = QtWidgets.QGridLayout() # 创建主部件的网格布局 self.main_widget.setLayout(self.main_layout) # 设置窗口主部件布局为网格布局 self.config = MonitorConfig() # 配置服务器地址 configAction = QAction(QIcon('exit.png'), '配置', self) configAction.setShortcut('Ctrl+Alt+S') configAction.setStatusTip('配置') configAction.triggered.connect(self.editConfigDialog) # 配置服务器地址 picAction = QAction(QIcon('exit.png'), '打开图片文件夹', self) picAction.setShortcut('Ctrl+O') picAction.setStatusTip('图片文件夹') picAction.triggered.connect(self.openPicDir) downloadAction = QAction(QIcon('exit.png'), '下载最新版本', self) downloadAction.setStatusTip('下载最新版本') downloadAction.triggered.connect(self.download) # exportAction = QAction(QIcon('exit.png'), '从"描述"字段中提取手机号', self) # exportAction.setStatusTip('从"描述"字段中提取手机号') # exportAction.triggered.connect(self.exportPhone) # 底部状态栏 self.statusBar().showMessage('状态栏') # 顶部菜单栏 menubar = self.menuBar() menubar.setNativeMenuBar(False) fileMenu = menubar.addMenu('配置') fileMenu.addAction(configAction) # exMenu = menubar.addMenu('提取手机号') # exMenu.addAction(exportAction) picMenu = menubar.addMenu('打开图片文件夹') picMenu.addAction(picAction) downloadMenu = menubar.addMenu('版本更新') downloadMenu.addAction(downloadAction) openAction = QAction(QIcon(IconConfig.SETTING_DIR), '打开手机号配置目录', self) openAction.setShortcut('Ctrl+O') openAction.triggered.connect(self.openPhoneDir) self.toolbar = self.addToolBar('打开手机号配置目录') self.toolbar.addAction(openAction) self.left_widget = QtWidgets.QWidget() # 创建左侧部件 self.left_widget.setObjectName('left_widget') self.left_layout = QtWidgets.QGridLayout() # 创建左侧部件的网格布局层 self.left_widget.setLayout(self.left_layout) # 设置左侧部件布局为网格 self.right_widget = QtWidgets.QWidget() # 创建右侧部件 self.right_widget.setObjectName('right_widget') self.right_layout = QtWidgets.QGridLayout() self.right_widget.setLayout(self.right_layout) # 设置右侧部件布局为网格 self.main_layout.addWidget(self.left_widget, 0, 0, 3, 2) # 左侧部件在第0行第0列,占8行3列 self.main_layout.addWidget(self.right_widget, 0, 2, 12, 10) # 右侧部件在第0行第3列,占8行9列 self.setCentralWidget(self.main_widget) # 设置窗口主部件 models = [ { 'label': '导出微信通讯录', 'objName': 'left_label' }, { 'label': '批量添加好友', 'objName': 'left_label' }, { 'label': '批量修改备注为手机号', 'objName': 'left_label' }, { 'label': '导出朋友圈信息', 'objName': 'left_label' }, { 'label': '导出含文本朋友圈信息', 'objName': 'left_label' }, { 'label': '导出图片到电脑', 'objName': 'left_label' }, { 'label': '按文本内容对图片分组', 'objName': 'left_label' }, { 'label': '上传文本到后台', 'objName': 'left_label' }, { 'label': '上传图片到后台', 'objName': 'left_label' }, { 'label': '开启导出图片并上传任务', 'objName': 'left_label' }, { 'label': '恢复输入法', 'objName': 'left_label' }, { 'label': '删除手机图片缓存', 'objName': 'left_label' }, { 'label': '抓取当天遗漏数据', 'objName': 'left_label' }, { 'label': '停止任务', 'objName': 'left_label' }, ] self.buttons = [] for index, model in enumerate(models): btn = QtWidgets.QPushButton(model['label']) btn.setObjectName(model['objName']) self.buttons.append(btn) for index, btn in enumerate(self.buttons): self.left_layout.addWidget(btn, index, 0, 1, 3) if index == 0: btn.clicked.connect(self.clickGetContacts) elif index == 1: btn.clicked.connect(self.clickAddFriend) elif index == 2: btn.clicked.connect(self.clickModifyName) elif index == 3: btn.clicked.connect(self.clickTextWithPicMoment) elif index == 4: btn.clicked.connect(self.clickTextMoment) elif index == 5: btn.clicked.connect(self.clickExportPic) elif index == 6: btn.clicked.connect(self.clickPicClassfy) elif index == 7: btn.clicked.connect(self.clickUploadText) elif index == 8: btn.clicked.connect(self.clickUploadPic) elif index == 9: btn.clicked.connect(self.clickBatchUploadLabel) elif index == 10: btn.clicked.connect(self.clickKeyboardLabel) elif index == 11: btn.clicked.connect(self.clickClearPics) elif index == 12: btn.clicked.connect(self.clickGetLostLabel) elif index == 13: btn.clicked.connect(self.clickStopLabel) self.left_widget.setStyleSheet(''' QPushButton#left_label{ padding:10px; font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; } ''') self.right_widget.setStyleSheet(''' QTextEdit#right_label{ font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; } ''') self.runthread = Runthread(EventConst.WX_CONTACT) self.runthread0 = Runthread(EventConst.MAIN_BULK_ADDFRIEND) self.runthread01 = Runthread(EventConst.MAIN_BULK_M_NAME) self.runthread1 = Runthread(EventConst.WX_MAIN_PIC) self.runthread2 = Runthread(EventConst.WX_MAIN) self.runthread3 = Runthread(EventConst.WX_EXPORT) self.runthread31 = Runthread(EventConst.WX_PICCLASSFY) self.runthread4 = Runthread(EventConst.WX_UPLOADER) self.runthread5 = Runthread(EventConst.WX_PICUPLOADER) self.runthread6 = Runthread(EventConst.WX_EXPORT_PHONE) self.runthread7 = Runthread(EventConst.WX_BATCH_UPLOAD) self.runthread8 = Runthread(EventConst.WX_CLEAR_PIC) self.runthread9 = Runthread(EventConst.WX_GET_LOST_PIC) self.stopRunner = StopRunthread() self.boardRunthread = KeyBoardRunthread() self.runthread.signals.connect(self.call_backlog) self.runthread0.signals.connect(self.call_backlog) self.runthread01.signals.connect(self.call_backlog) self.runthread1.signals.connect(self.call_backlog) self.runthread2.signals.connect(self.call_backlog) self.runthread3.signals.connect(self.call_backlog) self.runthread31.signals.connect(self.call_backlog) self.runthread4.signals.connect(self.call_backlog) self.runthread5.signals.connect(self.call_backlog) self.runthread6.signals.connect(self.call_backlog) self.runthread7.signals.connect(self.call_backlog) self.runthread8.signals.connect(self.call_backlog) self.runthread9.signals.connect(self.call_backlog) self.stopRunner.signals.connect(self.call_backlog) self.boardRunthread.signals.connect(self.call_backlog) self.right_label = QtWidgets.QTextEdit("") self.right_label.setPlaceholderText("日志输出区") self.right_label.setObjectName('right_label') self.right_layout.addWidget(self.right_label, 0, 0, 1, 3) # self.setWindowOpacity(0.9) # 设置窗口透明度 self.setWindowTitle('屋聚科技自动化运营工具V2.1') self.setWindowIcon(QIcon(IconConfig.LOGO_DIR)) # self.setAttribute(QtCore.Qt.WA_TranslucentBackground) # 设置窗口背景透明 # self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隐藏边框 self.main_layout.setSpacing(0) excel = WxConfig.getPhoneExcel() if excel: self.statusBar().showMessage(f'手机号文件地址:{excel}') else: self.statusBar().showMessage(f'请先点击配置菜单配置数据') value = self.config.get_value("wx_content", "select") if value == 'True': self.buttons[7].setEnabled(False) else: self.buttons[7].setEnabled(True)
class Moments(MomentsBase): def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.wx_content_md5 = self.config.get_value("wx_content", "md5") def enter(self): """ 进入朋友圈 :return: """ sleep(self.WAIT_TIMEOUT) by_id = self.driver.find_element_by_id('com.tencent.mm:id/czl') el2 = by_id.find_element_by_xpath( '//android.widget.LinearLayout/android.widget.RelativeLayout[3]') el2.click() sleep(3) el3 = self.driver.find_element_by_id('com.tencent.mm:id/f43') el3.click() sleep(3) def crawl(self): """ 爬取 :return: """ index = 0 contents = [] finished = False md5_contents = [] while True: if wx_stop.stopFlag: break if index > 0: # 上滑 self.swipe_up() sleep(3) items = self.find_elements_by_id("com.tencent.mm:id/fn9") if items is None: continue if finished: break for item in items: b_e_content = None advise = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'广告')]", item) if advise: Logger.println( f"【============检测到广告忽略进入下一条================】") continue content_element = self.find_element_by_id( "com.tencent.mm:id/b_m", item) if content_element: content_element.click() sleep(2) b_e_content = self.getContentTextById( 'com.tencent.mm:id/fpu') if b_e_content: Logger.println(f"【获取到全文内容={b_e_content}】") self.driver.back() if b_e_content is None: b_e_content = self.getContentTextById( "com.tencent.mm:id/b_e", item) if b_e_content is None: if index == 0: index = +1 Logger.println(f"【该条说说没有文本,忽略】") continue nickName = self.getNickName(item) md5_ = self.MD5(b_e_content) phone = self.get_phone_from_txt(b_e_content) data = { 'content_md5': md5_, 'nick_name': nickName, 'content': b_e_content, 'phone': phone, 'crawl_time': time_util.now_to_date(), 'file_ids': '', } if md5_ in self.wx_content_md5: Logger.println( f"【crawl{index}已经抓取到上一次位置({md5_}).data={data}】") md5 = None if len(md5_contents) > 1: md5 = ','.join(md5_contents[0:2]) elif len(md5_contents) > 0: md5 = md5_contents[0] if md5: self.config.set_value("wx_content", "md5", md5) finished = True break if md5_ in md5_contents: continue else: md5_contents.append(md5_) Logger.println(f"【crawl({index}).data={data}】") contents.append(data) index = index + 1 if index % 5 == 0: date = time_util.now_to_date('%Y%m%d_%H') full_dir = FilePathUtil.get_full_dir( "wxfriend", "excel", "text", date + "wx_moments.xls") excel_util.write_excel(filename=full_dir, worksheet_name=date, items=contents) md5 = None if len(md5_contents) > 1: md5 = ','.join(md5_contents[0:2]) elif len(md5_contents) > 0: md5 = md5_contents[0] if md5: self.config.set_value("wx_content", "md5", md5) def main(self): """ 入口 :return: """ # 进入朋友圈 self.enter() # 爬取 self.crawl() def main_backgroud(self): thread = threading.Thread(target=self.main) thread.start()
def setAppDownloadUrl(app_download_url): config = MonitorConfig() phone_excel = config.set_value('appiumConfig', 'app_download_url', app_download_url) return phone_excel
def getAppexeReplaceDir(): config = MonitorConfig() appexe_replace_dir = config.get_value('appiumConfig', 'appexe_replace_dir') Logger.println(f"【appexe_replace_dir={appexe_replace_dir}】") return appexe_replace_dir
def __init__(self, parent=None): super(ConfigDialog, self).__init__(parent) layout = QFormLayout() self.config = MonitorConfig() self.label = QLabel("已连接设备名称:") self.le0 = QLineEdit() deviceId = WxConfig.getAppiumConfig()["deviceName"] self.le0.setPlaceholderText("未检测到设备") self.le0.setText(deviceId) layout.addRow(self.label, self.le0) self.label = QLabel("已连接安卓版本:") self.le1 = QLineEdit() platformVersion = WxConfig.getAppiumConfig()["platformVersion"] self.le1.setPlaceholderText("未检测到版本") self.le1.setText(platformVersion) layout.addRow(self.label, self.le1) self.label = QLabel("服务器地址:") self.le2 = QLineEdit() url = WxConfig.getServerUrl() self.le2.setText(url) layout.addRow(self.label, self.le2) self.label = QLabel("最大添加好友上限(人数):") self.le3 = QLineEdit() add_friend_max_count = WxConfig.get_add_friend_max_count() self.le3.setText(add_friend_max_count) layout.addRow(self.label, self.le3) self.label = QLabel("任务暂停后继续执行的时间间隔(秒):") self.le31 = QLineEdit() max_count = WxConfig.get_addfriend_inte_seconds() self.le31.setText(max_count) layout.addRow(self.label, self.le31) self.label = QLabel("每次抓取任务上线数量(条):") self.le32 = QLineEdit() crawl_max_count = WxConfig.get_crawl_max_count() self.le32.setText(crawl_max_count) layout.addRow(self.label, self.le32) self.label = QLabel("批量导出图片上传脚本时间间隔(秒):") self.le41 = QLineEdit() batch_pic_seconds = self.config.get_value('appiumConfig', 'batch_pic_seconds') self.le41.setText(batch_pic_seconds) layout.addRow(self.label, self.le41) self.addbtn = QPushButton("设置手机号文件地址") self.addbtn.clicked.connect( self.add_phone_excel) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.le4 = QLineEdit() phone_excel = WxConfig.getPhoneExcel() self.le4.setText(phone_excel) layout.addRow(self.addbtn, self.le4) self.label5 = QLabel("最新朋友圈图片md5值") self.le5 = QLineEdit() self.config = MonitorConfig() md5_pic = self.config.get_value("wx_content", "md5_pic") self.le5.setText(md5_pic) layout.addRow(self.label5, self.le5) self.label6 = QLabel("最新朋友圈文本md5值") self.le6 = QLineEdit() self.config = MonitorConfig() md5 = self.config.get_value("wx_content", "md5") self.le6.setText(md5) layout.addRow(self.label6, self.le6) self.label7 = QLabel("抓取文本时同时同步到云端") self.select_checkbox = QCheckBox("") value = self.config.get_value("wx_content", "select") if value == 'True': self.select_checkbox.setChecked(True) else: self.select_checkbox.setChecked(False) layout.addRow(self.label7, self.select_checkbox) self.label8 = QLabel("是否输出日志") self.log_checkbox = QCheckBox("") if Logger.debug: self.log_checkbox.setChecked(True) else: self.log_checkbox.setChecked(False) layout.addRow(self.label8, self.log_checkbox) self.cacelButton = QPushButton("重新检测") self.saveButton = QPushButton("保存") self.cacelButton.clicked.connect( self.reconnect) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.saveButton.clicked.connect( self.save) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.buttonBox = QDialogButtonBox(QtCore.Qt.Horizontal) self.buttonBox.addButton(self.saveButton, QDialogButtonBox.RejectRole) self.buttonBox.addButton(self.cacelButton, QDialogButtonBox.YesRole) layout.addRow(self.buttonBox) self.setLayout(layout) self.setWindowTitle("配置服务器地址") self.setWindowIcon(QIcon(IconConfig.LOGO_DIR))
def setServerUrl(server_url): config = MonitorConfig() config.set_value('appiumConfig', 'driver_server', server_url)
class Moments(MomentsBase): def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.wx_content_md5 = self.config.get_value("wx_content", "md5_pic") def enter(self): """ 进入朋友圈 :return: """ sleep(5) by_id = self.find_element_by_id('com.tencent.mm:id/czl') el2 = by_id.find_element_by_xpath( '//android.widget.LinearLayout/android.widget.RelativeLayout[3]') el2.click() sleep(3) el3 = self.driver.find_element_by_id('com.tencent.mm:id/f43') el3.click() def crawl(self): """ 爬取 :return: """ index = 0 md5_contents = [] contents = [] last_base_md5 = None finished = False while True: if wx_stop.stopFlag: break if index > 0: # 上滑 self.swipe_up() sleep(3) items = self.find_elements_by_id("com.tencent.mm:id/fn9") if items is None: continue if finished: break for item in items: b_e_content = None # 查找笔记 content_element = self.find_element_by_id( "com.tencent.mm:id/dm3", item) if content_element: content_element.click() sleep(2) b_e_content = self.getContentTextById( 'com.tencent.mm:id/fpu') if b_e_content: Logger.println(f"【获取到全文内容={b_e_content}】") self.driver.back() if b_e_content is None: b_e_content = self.getContentTextById( "com.tencent.mm:id/b_e", item) if b_e_content is None: if index == 0: index = +1 Logger.println(f"【该条说说没有文本,忽略】") continue nickName = self.getNickName(item) phone = "" md5_ = self.MD5(b_e_content) if md5_ in self.wx_content_md5: Logger.println( f"【crawl{index}已经抓取到上一次位置({md5_}).data={b_e_content}】") md5 = None if len(md5_contents) > 1: md5 = ','.join(md5_contents[0:2]) elif len(md5_contents) > 0: md5 = md5_contents[0] if md5: self.config.set_value("wx_content", "md5_pic", md5) finished = True break if md5_ in md5_contents: continue wx_number = "" image0 = self.find_element_by_xpath("//*[@content-desc='图片']", item) if image0: image0.click() sleep(1) start = '0' for index_img in range(9): image_detail = self.find_element_by_id( 'com.tencent.mm:id/c9h') if image_detail: base64 = self.get_screenshot_as_base64( image_detail) base_md5 = self.MD5(base64) if last_base_md5 == base_md5: end = time_util.get_time() data = { 'content_md5': md5_, 'nick_name': nickName, 'wx_number': wx_number, 'content': b_e_content, 'phone': phone, 'file_ids': '', 'start': start, 'end': end, 'count': str(index_img) } contents.append(data) self.driver.back() break if index_img == 0: start = time_util.get_time() # name = f"{i}_{base_md5}.png" # if self.save_screenshot(image_detail, md5_, name): try: action1 = TouchAction(self.driver) action1.long_press(el=image_detail, duration=500).perform() sleep(0.5) self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'保存图片')]" ).click() except: continue pass time = time_util.get_time() name = f'mmexport{time}.jpg' Logger.println( f"【crawl({index}.{index_img}).已保存图片={name}】") last_base_md5 = base_md5 is_oppo = self.desired_caps[ 'deviceName'] == '5e8caad5' if index_img == 8 or is_oppo: sleep(1) end = time_util.get_time() data = { 'content_md5': md5_, 'nick_name': nickName, 'wx_number': wx_number, 'content': b_e_content, 'phone': phone, 'file_ids': '', 'start': start, 'end': end, 'count': str(index_img + 1) } contents.append(data) self.driver.back() break sleep(1) self.swipeLeft() md5_contents.append(md5_) date = time_util.now_to_date('%Y%m%d_%H') full_dir = FilePathUtil.get_full_dir( "wxfriend", "excel", "pic", date + "wx_pic_moments.xls") excel_util.write_excel(filename=full_dir, worksheet_name=date, items=contents) index += 1 md5 = None if len(md5_contents) > 1: md5 = ','.join(md5_contents[0:2]) elif len(md5_contents) > 0: md5 = md5_contents[0] if md5: self.config.set_value("wx_content", "md5_pic", md5) def main(self): """ 入口 :return: """ # 进入朋友圈 self.enter() # 爬取 self.crawl() def main_backgroud(self): thread = threading.Thread(target=self.main) thread.start()
class Moments(MomentsBase): def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.last_record_phone = self.config.get_value("wx_content", "last_phone") self.max_count = int(WxConfig.get_add_friend_max_count()) self.addfriend_inte_seconds = int( WxConfig.get_addfriend_inte_seconds()) def modify_name(self, phone): sleep(self.get_sleep(6, 8)) # 输入电话号码 try: self.find_element_by_id('com.tencent.mm:id/bhn').send_keys(phone) except: pass sleep(self.get_sleep(5, 8)) try: self.find_element_by_id('com.tencent.mm:id/f8g').click() sleep(self.get_sleep(4, 6)) except: pass try: xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'用户不存在')]") if xpath: Logger.println(f"【main(用户不存在={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click() self.config.set_value("wx_content", "last_phone", phone) sleep(self.get_sleep(1, 2)) return False xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'被搜账号状态异常')]") if xpath: Logger.println(f"【main(被搜账号异常无法显示={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click() self.config.set_value("wx_content", "last_phone", phone) sleep(self.get_sleep(1, 2)) return False else: xpath = self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'操作过于频繁,请稍后再试')]" ) if xpath: Logger.println(f"【main(操作过于频繁,请稍后再试={phone}】") self.find_element_by_xpath( "//android.widget.Button[contains(@text,'确定')]").click( ) return True except Exception as e: Logger.println(f"【add().e={e}】") pass # 点击设置标签备注 # self.find_element_by_id('com.tencent.mm:id/f43').click() try: self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'设置备注和标签')]").click( ) except: try: self.find_element_by_xpath( "//android.widget.TextView[contains(@text,'标签')]").click() except: pass pass sleep(self.get_sleep(2, 3)) try: by_id = self.find_element_by_id('com.tencent.mm:id/b0a') if by_id is None: text = self.find_element_by_id('com.tencent.mm:id/b0j') if text: text.click() sleep(self.get_sleep(1, 2)) by_id = self.find_element_by_id('com.tencent.mm:id/b0a') if by_id: attribute = by_id.get_attribute('text') if attribute == phone: Logger.println(f"【main({phone}备注已经是手机号无需修改】") self.driver.back() sleep(self.get_sleep(1, 1)) self.driver.back() return False else: self.driver.keyevent(123) by_id.clear() by_id.send_keys(phone) pass sleep(self.get_sleep(1, 2)) # 点击保存 by_xpath = self.find_element_by_xpath("//*[contains(@text,'保存')]") if by_xpath: by_xpath.click() Logger.println(f"【add().phone={phone}】") self.config.set_value("wx_content", "last_phone", phone) else: element_by_xpath = self.find_element_by_xpath( "//*[contains(@text,'完成')]") if element_by_xpath: element_by_xpath.click() Logger.println(f"【add().phone={phone}】") self.config.set_value("wx_content", "last_phone", phone) except Exception as e: Logger.println(f"【add().e={e}】") sleep(self.get_sleep(1, 2)) self.driver.back() sleep(self.get_sleep(1, 2)) sleep(self.get_sleep(1, 2)) self.driver.back() def main(self): sleep(self.get_sleep(6, 10)) # 点击搜索按钮 self.find_element_by_id('com.tencent.mm:id/f8y').click() sleep(self.get_sleep(3, 5)) full_dir = FilePathUtil.get_full_dir("wxfriend", "excel", "手机号列表.xls") array = excel_util.excel2array(full_dir) length = len(array) if not array: Logger.println(f"【main(请先配置手机号列表文件的sheet_name为手机号列表】") return # array = [{'手机': '17602876095'}] # array = [{'手机': '13301616272'}, {'手机': '15821902923'}] start_index = 0 for index, element in enumerate(array): if str(int(element["手机"])) == self.last_record_phone: start_index = index Logger.println( f"【main找到上次添加的手机位置={start_index + 1}={self.last_record_phone}】" ) break count = 0 if start_index + 1 > length: Logger.println(f"【已经是最后一条了】") return for index, item in enumerate(array[start_index + 1:length]): if wx_stop.stopFlag: break phone = str(int(item['手机'])) Logger.println(f"【main开始执行{start_index + count + 1}.第{count}个任务】") if self.max_count > 1 and count > 1 and (count % self.max_count) == 0: start_time = int(time()) sleeptime = self.addfriend_inte_seconds Logger.println( f"【main(暂时停止任务开启休闲模式).{sleeptime}秒后执行第={count}个任务】") while True: rdsleep = self.get_sleep(5, 6) by_id = self.find_element_by_id('com.tencent.mm:id/bhn') if rdsleep == 5: if by_id: by_id.send_keys(f'已经休眠{int(time()) - start_time}s') else: if by_id: by_id.send_keys('') sleep(rdsleep) if int(time()) - start_time > sleeptime: break Logger.println(f"【main(退出休闲模式)继续执行第={count}个任务】") if wx_stop.stopFlag: break if self.modify_name(phone): break count += 1 Logger.println(f"【main(花费时间).total_count={self.total_count}s】") def main_backgroud(self): thread = threading.Thread(target=self.main) thread.start()
class Moments(MomentsBase): def __init__(self): """ 初始化 """ # 驱动配置 super().__init__() self.config = MonitorConfig() self.wx_content_md5 = self.config.get_value("wx_content", "md5_pic") def enter(self): """ 进入朋友圈 :return: """ sleep(self.WAIT_TIMEOUT) by_id = self.find_element_by_id('com.tencent.mm:id/czl') el2 = by_id.find_element_by_xpath( '//android.widget.LinearLayout/android.widget.RelativeLayout[3]') el2.click() sleep(3) el3 = self.driver.find_element_by_id('com.tencent.mm:id/f43') el3.click() def crawl(self): self.enter() """ 爬取 :return: """ index = 0 md5_contents = [] contents = [] finished = False while True: if wx_stop.stopFlag: break if index > 0: # 上滑 self.swipe_up() sleep(3) items = self.find_elements_by_id("com.tencent.mm:id/fn9") if items is None: continue if finished: break for item in items: self.scan_all_text_elment(item) b_e_content = None content_element = self.find_element_by_id( "com.tencent.mm:id/b_m", item) if content_element: content_element.click() sleep(2) b_e_content = self.getContentTextById( 'com.tencent.mm:id/fpu') if b_e_content: Logger.println(f"【获取到全文内容={b_e_content}】") self.driver.back() if b_e_content is None: b_e_content = self.getContentTextById( "com.tencent.mm:id/b_e", item) if b_e_content is None: if index == 0: index = +1 Logger.println(f"【该条说说没有文本,忽略】") continue nickName = self.getNickName(item) md5_ = self.MD5(b_e_content) if md5_ in self.wx_content_md5: Logger.println( f"【crawl{index}已经抓取到上一次位置({md5_}).data={b_e_content}】") finished = True break if md5_ in md5_contents: continue wx_number = "" phone = self.get_phone_from_txt(b_e_content) nick_name_element = self.getNickNameElement(item) if nick_name_element: try: nick_name_element.click() sleep(1) by_xpath_nickname = self.find_element_by_xpath( "//*[contains(@text,'昵称:')]") if by_xpath_nickname: nickName = by_xpath_nickname.get_attribute( "text").replace('昵称:', '').strip() by_xpath = self.find_element_by_xpath( "//*[contains(@text,'微信号:')]") if by_xpath: wx_number = by_xpath.get_attribute("text").replace( '微信号:', '').strip() Logger.println(f"【微信号={wx_number}】") xpath = self.find_element_by_xpath( "//*[contains(@text,'电话号码')]") if xpath: phone_parent = xpath.parent phone = self.getPhone(phone_parent) Logger.println(f"【phone={phone}】") sleep(1) self.driver.back() except Exception as e: Logger.println(f"【nick_name_element.click.e={e}】") pass contents.append({ 'content_md5': md5_, 'nick_name': nickName, 'wx_number': wx_number, 'phone': phone }) md5_contents.append(md5_) date = time_util.now_to_date('%Y%m%d') full_dir = FilePathUtil.get_full_dir( "wxfriend", "excel", "text", date + "wx_user_moments.xls") excel_util.write_excel_append(filename=full_dir, worksheet_name=date, items=contents) WxUploader.putItems(contents) contents.clear() index += 1 def main(self): """ 入口 :return: """ # 爬取 self.crawl() def main_backgroud(self): thread = threading.Thread(target=self.main) thread.start()
def set_crawl_max_count(crawl_max_count): config = MonitorConfig() config.set_value('appiumConfig', 'crawl_max_count', crawl_max_count)
class ConfigDialog(QDialog): def __init__(self, parent=None): super(ConfigDialog, self).__init__(parent) layout = QFormLayout() self.config = MonitorConfig() self.label = QLabel("已连接设备名称:") self.le0 = QLineEdit() deviceId = WxConfig.getAppiumConfig()["deviceName"] self.le0.setPlaceholderText("未检测到设备") self.le0.setText(deviceId) layout.addRow(self.label, self.le0) self.label = QLabel("已连接安卓版本:") self.le1 = QLineEdit() platformVersion = WxConfig.getAppiumConfig()["platformVersion"] self.le1.setPlaceholderText("未检测到版本") self.le1.setText(platformVersion) layout.addRow(self.label, self.le1) self.label = QLabel("服务器地址:") self.le2 = QLineEdit() url = WxConfig.getServerUrl() self.le2.setText(url) layout.addRow(self.label, self.le2) self.label = QLabel("最大添加好友上限(人数):") self.le3 = QLineEdit() add_friend_max_count = WxConfig.get_add_friend_max_count() self.le3.setText(add_friend_max_count) layout.addRow(self.label, self.le3) self.label = QLabel("任务暂停后继续执行的时间间隔(秒):") self.le31 = QLineEdit() max_count = WxConfig.get_addfriend_inte_seconds() self.le31.setText(max_count) layout.addRow(self.label, self.le31) self.label = QLabel("每次抓取任务上线数量(条):") self.le32 = QLineEdit() crawl_max_count = WxConfig.get_crawl_max_count() self.le32.setText(crawl_max_count) layout.addRow(self.label, self.le32) self.label = QLabel("批量导出图片上传脚本时间间隔(秒):") self.le41 = QLineEdit() batch_pic_seconds = self.config.get_value('appiumConfig', 'batch_pic_seconds') self.le41.setText(batch_pic_seconds) layout.addRow(self.label, self.le41) self.addbtn = QPushButton("设置手机号文件地址") self.addbtn.clicked.connect( self.add_phone_excel) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.le4 = QLineEdit() phone_excel = WxConfig.getPhoneExcel() self.le4.setText(phone_excel) layout.addRow(self.addbtn, self.le4) self.label5 = QLabel("最新朋友圈图片md5值") self.le5 = QLineEdit() self.config = MonitorConfig() md5_pic = self.config.get_value("wx_content", "md5_pic") self.le5.setText(md5_pic) layout.addRow(self.label5, self.le5) self.label6 = QLabel("最新朋友圈文本md5值") self.le6 = QLineEdit() self.config = MonitorConfig() md5 = self.config.get_value("wx_content", "md5") self.le6.setText(md5) layout.addRow(self.label6, self.le6) self.label7 = QLabel("抓取文本时同时同步到云端") self.select_checkbox = QCheckBox("") value = self.config.get_value("wx_content", "select") if value == 'True': self.select_checkbox.setChecked(True) else: self.select_checkbox.setChecked(False) layout.addRow(self.label7, self.select_checkbox) self.label8 = QLabel("是否输出日志") self.log_checkbox = QCheckBox("") if Logger.debug: self.log_checkbox.setChecked(True) else: self.log_checkbox.setChecked(False) layout.addRow(self.label8, self.log_checkbox) self.cacelButton = QPushButton("重新检测") self.saveButton = QPushButton("保存") self.cacelButton.clicked.connect( self.reconnect) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.saveButton.clicked.connect( self.save) # 当点击save按钮时,对话框将会消失,点击Cacel按钮时,则不会消失。 self.buttonBox = QDialogButtonBox(QtCore.Qt.Horizontal) self.buttonBox.addButton(self.saveButton, QDialogButtonBox.RejectRole) self.buttonBox.addButton(self.cacelButton, QDialogButtonBox.YesRole) layout.addRow(self.buttonBox) self.setLayout(layout) self.setWindowTitle("配置服务器地址") self.setWindowIcon(QIcon(IconConfig.LOGO_DIR)) def save(self): server_url = self.le2.text() self.config.set_value('appiumConfig', 'driver_server', server_url) max = self.le3.text() self.config.set_value('appiumConfig', 'addFriendMaxCount', max) addfriend_inte_seconds = self.le31.text() self.config.set_value('appiumConfig', 'addfriend_inte_seconds', addfriend_inte_seconds) crawl_max_count = self.le32.text() self.config.set_value('appiumConfig', 'crawl_max_count', crawl_max_count) md5_pic = self.le5.text() self.config.set_value("wx_content", "md5_pic", md5_pic) md5 = self.le6.text() self.config.set_value("wx_content", "md5", md5) select = self.select_checkbox.isChecked() self.config.set_value("wx_content", "select", str(select)) selectLog = self.log_checkbox.isChecked() Logger.debug = selectLog batch_pic_seconds = self.le41.text() self.config.set_value('appiumConfig', 'batch_pic_seconds', batch_pic_seconds) self.close() def reconnect(self): config = WxConfig.getAppiumConfig() deviceId = config["deviceName"] platformVersion = config["platformVersion"] self.le0.setText(deviceId) self.le1.setText(platformVersion) def open_file(self, dir): fileName, fileType = QtWidgets.QFileDialog.getOpenFileName( self, "选取文件", dir, "All Files(*);;Text Files(*.xls)") print(fileName, fileType) return fileName def add_phone_excel(self): full_dir = FilePathUtil.get_full_dir("wxfriend", "excel") filepath = self.open_file(full_dir) if filepath: WxConfig.setPhoneExcel(filepath) self.le4.setText(filepath)