業務場景
工作需要將微信號中的所有好友微信號保存下來,因爲涉及到多個微信號且每個微信好友上千,使用人工方式需要耗費大量精力,因而考慮使用程序模擬點擊的方式來獲取。
基本思路
使用手機登陸微信電腦版,然後通過程序模擬點擊鼠標來複制信息。複製的信息即時保存到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