使用程序批量獲取微信號

業務場景

工作需要將微信號中的所有好友微信號保存下來,因爲涉及到多個微信號且每個微信好友上千,使用人工方式需要耗費大量精力,因而考慮使用程序模擬點擊的方式來獲取。

基本思路

使用手機登陸微信電腦版,然後通過程序模擬點擊鼠標來複制信息。複製的信息即時保存到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("\n")
        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:{} .\nCould 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章