微信群牛皮癣,就是指用户在群里发小广告,没有下限。他们是微信群主最讨厌的一群人。熟悉早期的读者可以知道,我有一个技术交流群,但是建群以来,一直被小广告困扰。他们伪装成正常人潜入群,然后不停地用广告轰炸,严重扰乱了群内的技术交流氛围。或者二话不说骚扰每一个群友。虽然不清楚是什么原因可以驱使他们做出如此不折不扣的努力,成为最强的微信群牛皮癣(也许是金钱能力),但在经历了太多的骚扰之后,我开始思考是否可以用Python来消灭他们。其实一开始第一轮的想法很简单。总共有两个步骤。首先,这些人被成功识别,然后用Python踢出去。但是这两个步骤,每一步都不容易,先说说第一步如何准确识别这些用户,网上没有数据也没有很好的识别标准,只能动脑筋去完成特征识别。经过几个月对近百个发送广告的用户样本的训练,我的“人工智能”基本可以判断一个异常用户至少满足以下三项:明星女孩对于没有发过朋友圈背景图的特殊符号或表情包,通过后除了申请入群外,不会有其他回复。根据历史数据,满足第1条和第3条的用户大概率是小广告爱好者。那么接下来要做的就是用Python写代码在微信中找到这些人。总结了这个规律后,我乐观的认为实现这个需求并不难,因为我几年前就用Python研究过微信的朋友。不管是wxpy还是itchat,操作起来应该都不复杂,但是事实证明我还是太小不知道什么时候,虽然这些库还能安装使用,但是微信已经基本禁止大部分人登录了到网页版的微信,所以当我用多个微信号扫描二维码登录微信密码后,无一例外会提示1203Foryouraccount安全,该微信号不再允许登录网页版微信。您可以在电脑上使用Windows版微信或Mac版微信登录。这个很头疼,我无法手动查看我成千上万的微信好友,所以我开始思考是否有其他解决方案。第二轮如果你经常写Python爬虫,那么你就会知道,在某些情况下,Selenium比起用Requests来应对一些恶心的反爬措施,操作起来更方便。于是在发现使用微信API的想法无效后,我把目光转向了一个比较笨的方法——pynputpynput是一个第三方库,使用Python来控制和监控电脑鼠标和键盘。我大概明白我要做什么,但是我不能直接用API获取数据,所以我就跟Selenium一样,模拟点击每个好友来实现我想要的操作。简单说一下这个库,因为依赖库不多,所以安装起来非常简单,pipinstallpynput就可以了,使用起来也很简单。对于鼠标操作,只依赖于坐标。查看演示👇就像上面的GIF演示一样,先导入pynput并实例化一个鼠标控制器,然后把微信在状态栏的位置提交给mouse.position,这样鼠标就会移动到这个位置,然后用mouse.press来模拟鼠标点击自动打开微信。那么问题来了,如何获取我想要的位置的坐标呢?你不能一点一点地尝试!pynput除了可以使用Controller来控制鼠标外,还可以监控鼠标。比如用下面的代码记录程序启动后鼠标每次点击的位置👇frompynputimportmousedefon_move(x,y):print('鼠标移动到{0}'.format((x,y)))defon_click(x,y,button,pressed):print('{0}在坐标{1}'.format('鼠标在'ifpressedelse'上点击鼠标释放',(x,y)))ifnotpressed:returnFalsewhileTrue:withmouse.Listener(on_moveon_move=on_move,on_clickon_click=on_click)aslistener:listener.join()那么接下来的任务就简单了,我们只需要保持微信窗口不动,记录下各个按键位置的坐标即可(微信图标位置,群聊窗口位置,个人群成员头像位置),比如我们要判断上面提到的第一个规则,即获取每个群成员的微信号,设置好后,可以模拟如下操作:点击微信小程序,点击想要的群聊,然后点击每个群成员的头像移动到位置关于微信ID。双击微信号复制微信号,判断是否为初始微信号。上述过程中值得一提的是最后一步是复制。我们可以在pynput中使用键盘控制器。双击选择对应微信号后,使用如下代码模拟键盘输入Command+C完成复制操作frompynput.keyboardimportKeyfrompynput.keyboardimportControllerasController1keyboard=Controller1()withkeyboard.pressed(Key.cmd):keyboard.press('c')keyboard.release('c')但是paste不需要使用pynput通过模拟command+c粘贴到另一个编辑器中的复杂过程,我们可以使用第一个三方库pyperclip可以将复制的文本进行转换通过下面两行代码importpyperclippyperc直接变成一个字符串lip.paste()将群成员的微信号转成字符串后,无论是判断字符串的长度还是使用正则表达式等方法,我们都可以轻松判断出该群成员的微信号是否为初始微信signal,实现规则1的判断,下面的代码和动态图是从pynput.mouseimportButton,Controllerimporttimefrompynput.keyboardimportKeyfrompynput.keyboardimportControllerasController1importpyperclipmouse=Controller()#ClickonWeChatmouseimportButton,Controllerimporttimefrompynput.keyboardimportKey的完整过程(1046.14453125,4.546875)time.sleep(2)mouse.press(Button.left)mouse.release(Button.left)#点击头像mouse.position=(1194.140625,441.05859375)time.sleep(1)mouse.press(Button.left)mouse.release(Button.left)#点击选中文字mouse.position=(965.60546875,284.0390625)time.sleep(1)mouse.click(Button.left,2)keyboard=Controller1()withkeyboard.pressed(Key.cmd):keyboard.press('c')keyboard.release('c')time.sleep(1)wechatid=pyperclip.paste()print(f"Wechatid{wechatid}涉嫌广告号"iflen(wechatid)>20elsef"微信ID{wechatid}不是广告号")可以看到早期的微信成功排除广告号,那么只需要记录每两个群成员之间的坐标距离,然后循环模拟滚动或者下拉即可实现以上过程,即可判断所有微信号组内成员按照规则1,找出异常的成员分别判断可以看到,最终发现了6个疑似广告的微信账号,然后通过其他规则人工判断最终将2个用户判定为高危广告用户并移除。最后写到,通过以上操作,虽然成功踢出了两个疑似广告账号,但总体还是败了。因为你是否真的踢??对了人,还是很难判断的。如果你踢错了人,那么粉丝就是-1。同时你也可以发现,用Python准确找到群里的牛皮癣是非常困难的。使用pynput最多可以补全微信名,微信ID和头像(使用图片识别API),但更多隐藏在朋友圈中的信息难以提取和挖掘。同时,pynput也有和selenium一样的缺点,就是模拟真人操作,速度较慢,而且它的定位方式只支持坐标,所以也需要保证微信窗口不能被操作过程中移动,否则之前记录的所有元素都将无效。建议开发者可以升级更多的定位方式。