最近实在亏的太多心情很浮躁,而且近期一直有朋友问我怎么刷量的。就想着大概写点东西总结一下,先开个坑写一下怎么用浏览器自动化刷号。相关的教程网上很多,对程序员而言这个也不算什么难事儿,我主要会结合真实的例子讲一下怎么把流程跑通。
工具选择
我假定大家都对撸空投有基本认识,手动或者写脚本操作过。
基于撸空投场景,最常见的几个问题
1、浏览器插件(主要是钱包插件)操作
2、twitter、discord、gmail等等账号认证授权
3、各种验证码
上面的问题基于纯代码也是能搞定的。但有时候操作流程又臭又长,要拼接处理很多参数,部分项目还会有一些加密混淆需要去分析。所以很容易想到使用浏览器自动化代替人来执行。
关于自动化工具最常见的就是selenium(我研究生论文就是用它搞得),但是后来我问了下AI,他推荐了DrissionPage。
我试了一下功能比较强大语法也很简洁(给大佬递茶),对浏览器插件的支持也很不错。唯一问题就是AI对他的支持不是很好,遇到可能需要自己去查API没法直接问AI。
后面就基于Mac + DrissionPage + web3py + pyautogui实现。
本次以小狐狸钱包为例,实现导入切换删除钱包功能,如果用其他钱包应该也差不多。
from DrissionPage import WebPage, ChromiumOptions
import os, time, random, pyautogui
from DrissionPage.common import Actions
import sys,requests
from DrissionPage.common import Keys
import threading
import json
class wallet:
def __init__(self, address, private, mem=''):
self.address = address
self.private = private
self.mem = mem
#不带浏览器信息,采用导入metamask的方式,适用于只需要钱包信息的场景
def get_chromium_options( arguments: list) -> ChromiumOptions:
options = ChromiumOptions()
# options.set_argument('--auto-open-devtools-for-tabs', 'true') # we don't need this anymore
# options.set_paths(browser_path=browser_path)
for argument in arguments:
options.set_argument(argument)
return options
def createPage():
global page # 声明为全局变量
arguments = [
"-no-first-run",
"-force-color-profile=srgb",
"-metrics-recording-only",
# "-password-store=basic",
"-use-mock-keychain",
"-export-tagged-pdf",
"-no-default-browser-check",
"-disable-background-mode",
"-enable-features=NetworkService,NetworkServiceInProcess,LoadCryptoTokenExtension,PermuteTLSExtensions",
# "-disable-features=FlashDeprecationWarning,EnablePasswordsAccountStorage",
"-deny-permission-prompts",
"--start-maximized",
# "-disable-gpu",
# "-accept-lang=en-US",
# "--no-sandbox",
]
co = get_chromium_options(arguments)
# co.add_extension('/Users/jhw/Desktop/12.1.3_0')
# 创建页面对象
page = WebPage(chromium_options=co)
time.sleep(1)
page.set.window.full()
def openMetamask():
# 因为插件会保存,所以跳过导入助记词,直接用私钥导入
# 可以先跑一遍导入,后续直接用搜索就行了
#打开插件
page.get('chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/home.html')
success = page.wait.ele_displayed('x://*[@id="password"]', timeout=5)
if success:
#输入密码
input = page.ele('x://*[@id="password"]')
input.input('11111111')
btn = page.ele('x://*[@id="app-content"]/div/div[2]/div/div/button')
btn.click()
time.sleep(5)
def importWallet(wal:wallet):
btn = page.ele('x://*[@id="app-content"]/div/div[2]/div/div[2]/button')
btn.click()
time.sleep(1)
page.wait.ele_displayed('@data-testid=multichain-account-menu-popover-action-button', timeout=20)
addBtn = page.ele('@data-testid=multichain-account-menu-popover-action-button')
addBtn.click()
importX = 'x:/html/body/div[3]/div[3]/div/section/div/div[2]/button'
page.wait.ele_displayed(importX, timeout=20)
importBtn = page.ele(importX)
importBtn.click()
page.wait.ele_displayed('x://*[@id="private-key-box"]', timeout=20)
inputBox = page.ele('x://*[@id="private-key-box"]')
inputBox.input(wal.private)
confirmX = 'x:/html/body/div[3]/div[3]/div/section/div/div/div[2]/button[2]'
page.wait.ele_displayed(confirmX, timeout=20)
confirmBtn = page.ele(confirmX)
confirmBtn.click()
success = page.wait.ele_displayed('@text=启用', timeout=2)
page.actions.key_down(Keys.ESCAPE)
if success:
open = page.ele('@text=启用')
open.click()
def deleteWallet():
tab = None
for t in page.get_tabs():
if t.title == 'MetaMask':
tab = t
break
if tab == None:
print('找不到tab退出')
return
tab.set.activate()
success = False
retry_count = 0
bX = 'x://*[@id="app-content"]/div/div[2]/div/div[2]/button'
while not success and retry_count < 3:
success = tab.wait.ele_displayed(bX, timeout=5)
retry_count += 1
if success:
btn = tab.ele(bX)
btn.click()
else:
print('找不到按钮,退出')
return
time.sleep(1)
account2MoreOptX = '@aria-label=Account 2 期权'
success = tab.wait.ele_displayed(account2MoreOptX, timeout=3)
if success == False:
print("找不到第二个账号,直接退出")
tab.actions.key_down(Keys.ESCAPE)
return
account2MoreBtn = tab.ele(account2MoreOptX)
account2MoreBtn.click()
delX = '@data-testid=account-list-menu-remove'
tab.wait.ele_displayed(delX, timeout=5)
delBtn = tab.ele(delX)
delBtn.click()
confirmDelX = 'tx=删除'
tab.wait.ele_displayed(confirmDelX, timeout=10)
confirmDelBtn = tab.ele(confirmDelX)
confirmDelBtn.click()
time.sleep(1)
page:WebPage = None
if __name__ == '__main__':
walletList = [
wallet(address='0x1234567890abcdef1234567890abcdef12345678', private='private_key_1'),
wallet(address='0xabcdef1234567890abcdef1234567890abcdef12', private='private_key_2'),
wallet(address='0x7890abcdef1234567890abcdef1234567890abcd', private='private_key_3'),
]
createPage()
openMetamask()
deleteWallet()
for i, src_wal in enumerate(walletList):
print("当前主地址:" + src_wal.address)
importWallet(src_wal)
time.sleep(2)
deleteWallet()
time.sleep(2)
page.quit()
首先运行脚本打开浏览器,要自己下载小狐狸钱包,创建一个钱包完成配置。
也可以导入钱包
# co.add_extension('/Users/jhw/Desktop/12.1.3_0')
小狐狸经常更新,导入其实也不是很稳定。
完成设置后,关掉无头浏览器,再次启动脚本就可以开始运行了。
代码非常简单,就是打开小狐狸,导入钱包,删除钱包。
浏览器参数可以灵活调整,主要在于减少被验证码识别为bot的概率,我们暂时不涉及,每个参数的含义可以问AI。
打开小狐狸
page.get('chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/home.html')
这里我们需要把浏览器插件作为一个tab访问,所以直接打开插件地址(这个地址可以在小狐狸里点展开视图就可以看到)。
以输入密码为例,打开浏览器调试工具,定位元素到输入框找到对应的html元素,右键点击复制xpath。这样就得到了这个元素的xpath
//*[@id="password"]

利用xpath就可以定位到对应元素,执行操作
def openMetamask():
# 因为插件会保存,所以跳过导入助记词,直接用私钥导入
# 可以先跑一遍导入,后续直接用搜索就行了
#打开插件
page.get('chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/home.html')
success = page.wait.ele_displayed('x://*[@id="password"]', timeout=5)
if success:
#输入密码
input = page.ele('x://*[@id="password"]')
input.input('11111111')
btn = page.ele('x://*[@id="app-content"]/div/div[2]/div/div/button')
btn.click()
time.sleep(5)
DrissionPage支持各种方式的元素定位,具体可以参考官方文档。
了解了定位和操作元素后,后面就是同样的操作流程,定位元素,操作元素,等待响应
具体可以看视频
https://drive.google.com/file/d/1nwOq4oa6W5oza_htPfVVVSKLgx0XcMGL/view?usp=drive_link
注意由于小狐狸更新可能对应的元素xpath会有变化,所以如果某一步操作不生效,需要重新查看一下xpath更新一下代码,有时候小狐狸也会突然弹出一些广告啊、新功能啥的弹框遇到了就手动点掉就好了
这样操作小狐狸钱包的流程就完成了,剩下的就是开始交互项目了。
下一篇应该会写一下怎么绕过cloudflare验证。
