zoukankan      html  css  js  c++  java
  • 使用程序批量获取微信号

    业务场景

    工作需要将微信号中的所有好友微信号保存下来,因为涉及到多个微信号且每个微信好友上千,使用人工方式需要耗费大量精力,因而考虑使用程序模拟点击的方式来获取。

    基本思路

    使用手机登陆微信电脑版,然后通过程序模拟点击鼠标来复制信息。复制的信息即时保存到Excel中
    定位关键点
    需要解决的第一个问题是定位关键点,比如好友列表位置、比如顶部位置、底部位置、微信ID位置等等。可以通过pyautogui所带的locateOnScreen功能实现,也就是对比图片位置,因此程序运行之前需要先截图以下图片:
    定位图
    上图中,各个图片的功能依次为:
    A.png:用来定位第一个用户位置

    botttom.png:定位底部用户的位置

    contact.png/contact2.png:定位联系人图标位置,初始时点击该按钮

    dis.png/dis2.png:定位地区关键词位置,用来复制信息

    male.png/female.png:用来判断性别

    from.png/from2.png:用来判断好友来源方式

    sep.png:用来定位签名位置

    top.png:用来定位顶部位置

    wx-id.png/wx-cn-id.png:用来定位微信号位置

    其中,有两张图片的是为了兼容中英文不同模式,实际使用中只需要截图自己微信语言的图片就行。

    模拟点击、移动、复制、粘贴
    模拟点击、移动、选择使用的是pyautogui库里的函数:

    import pyautogui as pag
    pag.moveTo(x,y,time) # 移动
    pag.click() # 点击
    pag.dragTo(x,y,time) # 按下左键拖动
    pag.hotkey('ctrl', 'c') # 复制
    

    获取剪贴板内容使用的是clipboard的功能:

    clipboard.paste()
    

    接下来就是循环点击滚动直到程序到达最底部。结果会通过pandas的DataFrame保存到Excel。

    代码

    将程序完整封装,代码如下:

    # -*- coding:utf-8 -*-
    
    # 引入依赖库
    import pyautogui as pag
    import clipboard as cb
    import pandas as pd
    import os
    import sys
    
    
    def locate():
        """定位关键点"""
        tbox = pag.locateOnScreen("data/top.png")
        cbox = pag.locateOnScreen("data/contact.png") if pag.locateOnScreen("data/contact.png") else pag.locateOnScreen(
            "data/contact2.png")
        bbox = pag.locateOnScreen("data/bottom.png")
        abox = pag.locateOnScreen("data/A.png")
    
        return tbox, cbox, bbox, abox
    
    
    def cal_pos(cbox, bbox, abox):
        """计算点击位置"""
        # 联系人图标位置
        cc = pag.center(cbox)
        # 第一个联系人位置
        if abox is None:
            print("Guess contact from contact icon.")
            acx = cc[0] + 40
            acy = cc[1] - 50
        else:
            acx, acy = pag.center(abox)
        fc = (acx + 20, acy + 50)
        # 底部点击位置
        bc = pag.center(bbox)
        return cc, fc, bc
    
    
    def is_bottom(cur_y, bom_y):
        """判断是否到达底部"""
        return cur_y > (bom_y + 80)
    
    
    def gender():
        """获取性别"""
        if pag.locateOnScreen("data/female.png"):
            return 'female'
        elif pag.locateOnScreen("data/male.png"):
            return 'male'
        else:
            return ""
    
    
    def nick_name_and_signature(tc, drag_speed):
        """获取微信昵称和签名"""
        box = pag.locateOnScreen("data/sep.png")
        rx, ry = pag.center(box)
        tcx, tcy = tc[0], tc[1]
        pag.moveTo(rx, ry, 0.1)
        pag.dragTo(tcx + 50, tcy + 50, drag_speed)
        text = copy()
    
        pag.click()
        if text:
            li = text.split("
    ")
            if len(li) > 1:
                return li[0], li[1]
            else:
                return text, ""
        else:
            return "", ""
    
    
    def copy():
        """复制内容:非重复性拷贝"""
        ori_text = str(cb.paste()) if cb.paste() else ""
        pag.hotkey('ctrl', 'c')
        text = str(cb.paste()) if cb.paste() else ""
        if text != ori_text:
            return text
        else:
            return ""
    
    
    def district(drag_speed):
        """获取地区"""
        box = pag.locateOnScreen("data/dis.png") if pag.locateOnScreen("data/dis.png") else pag.locateOnScreen(
            "data/dis2.png")
        if box:
            cx, cy = pag.center(box)
            pag.moveTo(cx, cy, 0.1)
            pag.dragTo(cx + 400, cy + 20, drag_speed)
            text = copy()
            pag.click()
            if text:
                return text
            else:
                return ""
        else:
            return ""
    
    
    def from_(drag_speed):
        """好友来源"""
        box = pag.locateOnScreen("data/from.png") if pag.locateOnScreen("data/from.png") else pag.locateOnScreen(
            "data/from2.png")
        if box:
            cx, cy = pag.center(box)
            pag.moveTo(cx, cy, 0.1)
            pag.dragTo(cx + 400, cy + 20, drag_speed)
            pag.hotkey("ctrl", "c")
            text = cb.paste()
            pag.click()
            if text:
                return text
            else:
                return ""
        else:
            return ""
    
    
    def wx_id(drag_speed):
        """获取微信id"""
        box = pag.locateOnScreen("data/wx-id.png") if pag.locateOnScreen("data/wx-id.png") else pag.locateOnScreen(
            "data/wx-cn-id.png")
        if box:
            cx, cy = pag.center(box)
            pag.moveTo(cx, cy, 0.1)
            pag.dragTo(cx + 400, cy + 20, drag_speed)
            pag.hotkey("ctrl", "c")
            text = cb.paste()
            pag.click()
            if text:
                return text
            else:
                return ""
        else:
            return ""
    
    
    def click(tbox, cbox, bbox, abox, gap, drag_speed, out, is_all):
        """模拟点击"""
        cc, fc, bc = cal_pos(cbox, bbox, abox)
        # 点击联系人图标
        pag.click(cc)
        # 循环点击用户列表
        btm_y = bc[1]
        # 当前工作位置
        curr_x = fc[0]
        curr_y = fc[1]
        # 循环滚动点击
        cnt = 0
        IDs = []  # 记录ID列表
        scroll_flag = True  # 滚动标记
        same_list = []  # 记录入库值
        Info = {"WechatID": [],
                "From": [],
                "District": [],
                "Gender": [],
                "NickName": [],
                "Signature": [], }  # 存储用户信息
        while not is_bottom(curr_y, btm_y):
            pag.moveTo(curr_x, curr_y, 0.1)
            pag.click()
            _id = wx_id(drag_speed)
            if _id != "":
                IDs.append(_id)
                Info["WechatID"].append(_id)  # id
                if is_all:
                    _from = from_(drag_speed)  # 来源
                    Info["From"].append(_from)
                    dis = district(drag_speed)  # 地区
                    Info["District"].append(dis)
                    g = gender()  # 性别
                    Info["Gender"].append(g)
                    tc = pag.center(tbox)
                    nick_name, signature = nick_name_and_signature(tc, drag_speed)  # 昵称、签名
                    Info["NickName"].append(nick_name)
                    Info["Signature"].append(signature)
                else:
                    Info["From"].append("")
                    Info["District"].append("")
                    Info["Gender"].append("")
                    Info["NickName"].append("")
                    Info["Signature"].append("")
                save(out, Info, "contacts")
                cnt += 1
                print("{} WechatID:{}".format(cnt, Info["WechatID"][-1]))
            else:  # 未找到信息,滚动
                print("Nothing found.")
                pag.moveTo(curr_x, curr_y, 0.1)
                pag.scroll(int(-1 * gap * 1.2))
                continue
            # 获取信息完毕,滚动
            if scroll_flag:
                if len(same_list) < 3:
                    same_list.append(_id)
                elif len(set(same_list)) == 1:
                    scroll_flag = False
                else:
                    same_list.pop(0)
                    same_list.append(_id)
            if scroll_flag:  # 滚动状态
                pag.moveTo(curr_x, curr_y, 0.1)
                pag.scroll(int(-1 * gap * 1.2))
            else:  # 结束滚动
                curr_y += gap
    
    
    def save(out, data, sheet):
        """保存结果"""
        writer = pd.ExcelWriter(out)
        df = pd.DataFrame(data)
        df2 = df.drop_duplicates(subset=None, keep='first', inplace=False)
        df2.to_excel(writer, sheet, index=False)
        writer.save()
        return True
    
    
    def main(out, is_all):
        """主程序执行入口"""
        # 执行文件判重,重复则序号增1
        file_name, rear = os.path.splitext(out)
        cnt = 1
        while os.path.isfile(out):
            out = file_name + "_" + str(cnt) + rear
            cnt += 1
        print("Locating...")
        tbox, cbox, bbox, abox = locate()  # 定位
        if tbox is None or cbox is None or bbox is None:
            print("tbox:{} cbox:{} bbox:{} abox:{} .
    Could not locate box position.Try again.".format(tbox,
                                                                                                       cbox,
                                                                                                       bbox,
                                                                                                       abox))
            return
        click(tbox, cbox, bbox, abox, 100, 0.4, out, is_all)  # 开始运行
        print("All done.")
    
    
    if __name__ == "__main__":
        out = "contacts.xlsx"  # 保存地址
        out = os.path.abspath(out)
        args = sys.argv
        if len(args) < 2:
            main(out, False)
        elif args[1] == "all":
            main(out, True)
        else:
            main(out, False)
    
    

    程序用法

    python auto_click.py all
    

    all参数代表程序会去获取所有可获取的信息,包括来源、昵称、签名、地区等。如果没有这个参数那么程序只会获取微信号,速度会更快一些。

    注意:程序运行之后不能移动鼠标,需要提前结束程序的话将鼠标移动到左上角悬停几秒即可。

    您的浏览器不支持html5视频播放

    结果示意:
    结果示意

    获得帮助

    作者博客地址:http://www.yooongchun.com

  • 相关阅读:
    sql server 数据类型转换
    sql server replace 的使用方法
    sql sever 触发器的概念和使用
    转,sql 50道练习题
    sql server 计算属性,计算字段的用法与解析
    sql server 的模糊查询的用法
    sql server 游标的基本用法
    sql server if exists用法
    sql server in和exists 的区别
    Sql日期时间格式转换大全
  • 原文地址:https://www.cnblogs.com/yczha/p/13160186.html
Copyright © 2011-2022 走看看