一.背景:
1.微信好友很多,但朋友圈活跃的却很少
为了减少发朋友圈对其他人的干扰,于是将不相干的人设置成仅聊天状态
2.获取好友列表,供分析
3.后续可以增加: 批量删除、更多的权限设置、好友分组、自动发朋友圈等
二.相关链接:
1.Python: https://repo.anaconda.com/archive/Anaconda3-2022.05-Windows-x86_64.exe
2.Appium:https://github.com/appium/appium-desktop/releases/download/1.8.0/appium-desktop-setup-1.8.0.exe
3.定位界面元素的工具:Android\Sdk\tools\bin\uiautomatorviewer.bat
三.流程:
四.实现代码:
# -*- coding: utf-8 -*-
"""
一.背景:
1.微信好友很多,但朋友圈活跃的却很少
为了减少发朋友圈对其他人的干扰,将不相干的人设置成仅聊天状态
2.获取朋友列表,供回顾使用
3.后续可以增加: 批量删除、更多的权限设置、好友分组、自动发朋友圈等
二.当前功能:自动设置朋友圈权限(平均速度:1.5秒/人)
三.操作步骤:
1.打开Appium
2.运行以下程序,会保存auth.csv文件
文件内容为:用户名,当前权限级别
3.修改auth.csv文件
0:表示仅聊天 1:表示可以查看朋友圈
3.再次运行本程序,会根据auth.csv的配置,重新设置朋友圈权限
四.启示:
1.微信为什么不开放批量编辑的功能呢
五.附加说明【关注】:
1.不同版本的微信,xpath匹配规则可能不一样,需相应调整
六.运行环境:
Appium: 1.8.0
Python: 3.9.7
Selenium: 3.141.0
"""
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import re
import logging
import codecs
import os
import csv
import re
import traceback
def load_auth_list():
'''加载权限配置文件'''
try:
csv_reader = csv.reader(open("auth.csv"))
auth_dict={}
for row in csv_reader:
name,auth_level=row
auth_dict[name.strip()]=auth_level.strip()
return auth_dict
except:
print("load_auth_list invalid")
return None
def remove_invisible_chars(s):
"""移除所有不可见字符,除\n外"""
return s.encode('gbk','ignore').decode('gbk')
def main(auth_dict):
'''主函数'''
PLATFORM = 'Android'
deviceName = 'HUAWEI_P7_L09'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
desired_caps = {
'platformName': 'Android',
'deviceName': 'P7CDU17C15003317',
'platformVersion': '9',
'appPackage': 'com.tencent.mm', # apk包名
'appActivity': 'com.tencent.mm.ui.LauncherUI', # apk的launcherActivity
'noReset': 'True', # 每次运行脚本不用重复输入密码启动微信
'unicodeKeyboard': 'True', # 使用unicodeKeyboard的编码方式来发送字符串
'resetKeyboard': 'False' # 将键盘给隐藏起来
}
logger = logging.getLogger("")
logger.setLevel(logging.ERROR)
desired_caps['chromeOptions'] = {'androidProcess': 'com.tencent.mm:tools'} #驱动H5自动化关键之一
driver = webdriver.Remote(driver_server, desired_caps)
wait = WebDriverWait(driver, 300)
#打开通讯录
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/f30"]' )))
items = driver.find_elements_by_id("com.tencent.mm:id/f30")
items[1].click()
#用户名去重
username_set=set()
#统计耗时
begin_time=time.time()
#保存当前的权限列表,用于后续编辑
fout=open("auth_out.csv",'w',newline='')
writer=csv.writer(fout)
#总用户数
total_count=0
empty_count=0
while True:
cur_time=time.time()
time_delay=cur_time-begin_time
#模拟滑屏
try:
driver.swipe(300,1537, 300,1132,duration=500)
except BaseException as e:
time.sleep(0.4)
continue
#获取朋友列表
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/hga"]' )))
items = driver.find_elements_by_id("com.tencent.mm:id/hga")
#统计新增的用户数
new_count=0
for item in items:
username=""
#忽略不显示不全的条目
try:
ypos=item.location['y']
if ypos>2100:
continue
except BaseException as e:
continue
#获取用户名
try:
username = item.get_attribute('text').strip()
username=remove_invisible_chars(username)
print(username)
except BaseException as e:
traceback.print_exc()
continue
#过滤重复项
if username in username_set:
continue
new_count+=1
total_count+=1
username_set.add(username)
if username in [u'你自己',u'文件传输助手',u'微信团队']:
continue
#过滤已处理过的
#if auth_dict and username in auth_dict:
# continue
#模拟点击用户,进入配置页面
item.click()
#获取"朋友权限"
autu_item=None
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/it7"]')))
try:
autu_item = driver.find_elements_by_id("com.tencent.mm:id/it9")[0]
except BaseException as e:
pass
if autu_item is None:
try:
autu_item = driver.find_elements_by_id("com.tencent.mm:id/it7")[1]
except BaseException as e:
pass
#点击"朋友权限"
autu_item.click()
#获取"设置朋友权限" 的二个选项
wait.until(EC.visibility_of_element_located((By.XPATH,"//*[@resource-id='com.tencent.mm:id/kfe']")))
auth_root = driver.find_elements(By.XPATH, "//*[@resource-id='com.tencent.mm:id/kfe']")[0]
auth_root = auth_root.find_elements(By.XPATH,'//*[@class="android.widget.TextView"]')
all_auth=auth_root[1]
just_talk=auth_root[2]
#根据权限列表的配置,设置目标权限
target_auth_level=-1
if auth_dict and username in auth_dict:
target_auth_level=auth_dict[username]
if target_auth_level=="0":
just_talk.click()
elif target_auth_level=="1":
all_auth.click()
else:
print("username:{} auth invalid:{}".format(username,target_auth_level))
else:
all_auth.click() #默认开启所有权限
#获取当前权限
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/fz"]')))
current_auth_level=-1
try:
if len(driver.find_elements_by_id("com.tencent.mm:id/kfb"))==1:
current_auth_level=0
except BaseException as e:
pass
try:
if len(driver.find_elements_by_id("com.tencent.mm:id/jvf"))==1:
current_auth_level=1
except BaseException as e:
pass
#获取"朋友权限"页面的退出框,并退出
exit2_item = driver.find_elements_by_id("com.tencent.mm:id/fz")[0]
exit2_item.click()
#获取退出框,并退出
wait.until(EC.visibility_of_element_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/fz"]')))
exit1_item = driver.find_elements_by_id("com.tencent.mm:id/fz")[0]
exit1_item.click()
print("count:{} time(min):{:.2f} usename:{} 目标权限:{} 当前权限:{}".format(total_count,time_delay/60,username,target_auth_level,current_auth_level))
#保存当前配置到csv文件,供后续编辑
writer.writerow([username,current_auth_level])
#没有新增(滑到底),则退出
if new_count==0:
empty_count+=1
else:
empty_count=0
if empty_count>3:
print("Finished")
break
#供调试用
#if total_count>6:
# break
#关闭csv文件
fout.close()
if __name__=="__main__":
auth_dict=load_auth_list()
main(auth_dict)