274 lines
11 KiB
Python
274 lines
11 KiB
Python
|
|
import base64
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
from DrissionPage import ChromiumPage
|
|||
|
|
from DrissionPage import ChromiumOptions
|
|||
|
|
from PIL import Image,ImageDraw
|
|||
|
|
|
|||
|
|
import random
|
|||
|
|
from DrissionPage.common import Actions
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
class batch_check_anchor:
|
|||
|
|
|
|||
|
|
def __init__(self,username,password, callback):
|
|||
|
|
# 在初始化时进行一系列的自动化操作,登录->关闭窗口->点击邀约主播
|
|||
|
|
start_time=time.time()
|
|||
|
|
false=False
|
|||
|
|
true=True
|
|||
|
|
co = ChromiumOptions()
|
|||
|
|
# co.incognito()
|
|||
|
|
# 设置不加载图片、静音
|
|||
|
|
co.mute(True)
|
|||
|
|
co.headless(False)
|
|||
|
|
co.auto_port(True)
|
|||
|
|
self.page = ChromiumPage(co)
|
|||
|
|
self.page.set.window.max()
|
|||
|
|
#self.page.set.cookies.clear()
|
|||
|
|
self.page.get('https://live-backstage.tiktok.com/portal/overview')
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
loginele=self.page.ele("@data-id=login")
|
|||
|
|
|
|||
|
|
cookie = self.page.ele("全部允许")
|
|||
|
|
if cookie:
|
|||
|
|
|
|||
|
|
p = self.page.ele('@user-config-ele-id=tiktok-cookie-banner-config').shadow_root
|
|||
|
|
b = p.eles('tag:button')
|
|||
|
|
if b:
|
|||
|
|
b[-1].click()
|
|||
|
|
|
|||
|
|
if loginele:
|
|||
|
|
#
|
|||
|
|
# self.page.set.window.show()
|
|||
|
|
# 点击登录按钮
|
|||
|
|
self.page.ele("@data-id=login").click()
|
|||
|
|
time.sleep(random.random())
|
|||
|
|
# 输入账号
|
|||
|
|
self.page.ele("@class=semi-input semi-input-default").input(username,clear=True)
|
|||
|
|
time.sleep(random.random())
|
|||
|
|
# 输入密码
|
|||
|
|
self.page.ele("@class=semi-input semi-input-default semi-input-sibling-modebtn").input(password,clear=True)
|
|||
|
|
# 点击进行登录
|
|||
|
|
time.sleep(random.random())
|
|||
|
|
self.page.ele("@data-id=login-primary-button").click()
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
while True:
|
|||
|
|
try:
|
|||
|
|
loginele=self.page.ele("@data-id=login",timeout=1)
|
|||
|
|
if not loginele:
|
|||
|
|
print('后台登录成功')
|
|||
|
|
# self.page.set.window.hide()
|
|||
|
|
if callback:
|
|||
|
|
callback()
|
|||
|
|
break
|
|||
|
|
time.sleep(0.2)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
ele=self.page.ele('@class=semi-button semi-button-tertiary semi-button-size-small semi-button-borderless semi-modal-close semi-button-with-icon semi-button-with-icon-only')
|
|||
|
|
|
|||
|
|
print("3s 点击 关闭页面")
|
|||
|
|
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
|
|||
|
|
page = self.page.ele("@data-id=guide-ok")
|
|||
|
|
if page:
|
|||
|
|
page.click()
|
|||
|
|
|
|||
|
|
invite_btn = self.page.ele("@class=semi-button semi-button-primary semi-button-with-icon",timeout=1)
|
|||
|
|
|
|||
|
|
if not invite_btn:
|
|||
|
|
btn = self.page.ele("@data-id=know")
|
|||
|
|
if btn:
|
|||
|
|
btn.click()
|
|||
|
|
check_btn = self.page.ele("@data-id=workplace-switch-button")
|
|||
|
|
if check_btn:
|
|||
|
|
check_btn.click()
|
|||
|
|
while true:
|
|||
|
|
time.sleep(0.2)
|
|||
|
|
ele=self.page.ele('@data-id=add-host-btn')
|
|||
|
|
try:
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
inputele=self.page.eles('@class=semi-input-textarea semi-input-textarea-autosize')[1]
|
|||
|
|
if inputele:
|
|||
|
|
break
|
|||
|
|
except:
|
|||
|
|
ele=self.page.ele('@class=semi-button semi-button-tertiary semi-button-size-small semi-button-borderless semi-modal-close semi-button-with-icon semi-button-with-icon-only')
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
|
|||
|
|
end_time=time.time()
|
|||
|
|
self.get_anchor("测试")
|
|||
|
|
print('初始化完成 耗时:',end_time-start_time)
|
|||
|
|
|
|||
|
|
def get_ip(self):
|
|||
|
|
# 提取代理API接口,获取1个代理IP
|
|||
|
|
api_url = "https://dps.kdlapi.com/api/getdps/?secret_id=ohs2d9r6kqdtt2tau900&signature=gktsvou9sd0nq7o09q3ridg70aal97b1&num=1&pt=1&sep=1"
|
|||
|
|
|
|||
|
|
# 获取API接口返回的代理IP
|
|||
|
|
proxy_ip = requests.get(api_url).text
|
|||
|
|
|
|||
|
|
# 用户名密码认证(私密代理/独享代理)
|
|||
|
|
username = "d2400186192"
|
|||
|
|
password = "5yv1r337"
|
|||
|
|
proxies = {
|
|||
|
|
"http": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": proxy_ip},
|
|||
|
|
"https": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": proxy_ip}
|
|||
|
|
}
|
|||
|
|
return proxies
|
|||
|
|
|
|||
|
|
# 法国 德国
|
|||
|
|
|
|||
|
|
# 处理tiktok的验证码
|
|||
|
|
def deal_identifying_code(self,b):
|
|||
|
|
url = "http://api.jfbym.com/api/YmServer/customApi"
|
|||
|
|
data = {
|
|||
|
|
## 关于参数,一般来说有3个;不同类型id可能有不同的参数个数和参数名,找客服获取
|
|||
|
|
"token": "w7hWcZPPOgQG2WTg4os5vD2WnYZ38g9bLWnmBxGUHY4",
|
|||
|
|
"type": "30101",
|
|||
|
|
"image": b,
|
|||
|
|
}
|
|||
|
|
_headers = {
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
response = requests.request("POST", url, headers=_headers, json=data, proxies=self.get_ip()).json()
|
|||
|
|
print(response)
|
|||
|
|
return response['data']['data']
|
|||
|
|
|
|||
|
|
# text:传入邀约
|
|||
|
|
def get_anchor(self,text):
|
|||
|
|
start_time=time.time()
|
|||
|
|
while True:
|
|||
|
|
try:
|
|||
|
|
inputele=self.page.eles('@class=semi-input-textarea semi-input-textarea-autosize')[1]
|
|||
|
|
if inputele:
|
|||
|
|
inputele.click()
|
|||
|
|
inputele.input(text,clear=True)
|
|||
|
|
print("点击了测试")
|
|||
|
|
self.page.listen.start('https://live-backstage.tiktok.com/creators/live/union_platform_api/agency/union_invite/batch_check_anchor/')
|
|||
|
|
|
|||
|
|
|
|||
|
|
print("监听url")
|
|||
|
|
while True:
|
|||
|
|
nextele=self.page.eles('@data-id=invite-host-next')[0]
|
|||
|
|
if nextele:
|
|||
|
|
time.sleep(0.5)
|
|||
|
|
print("点击下一步")
|
|||
|
|
nextele.click()
|
|||
|
|
backele=self.page.ele('@data-id=invite-host-back')
|
|||
|
|
if backele:
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
max_retries = 3 # 定义最大重试次数
|
|||
|
|
failure_count = 0 # 初始化失败计数器
|
|||
|
|
|
|||
|
|
while True:
|
|||
|
|
checkele=self.page.ele('@class=TUXButton-content')
|
|||
|
|
|
|||
|
|
if failure_count >= max_retries:
|
|||
|
|
print("验证失败超过3次,终止流程")
|
|||
|
|
break #
|
|||
|
|
|
|||
|
|
if checkele:
|
|||
|
|
|
|||
|
|
# self.page.set.window.show()
|
|||
|
|
print(f"第{failure_count + 1}次尝试处理验证码")
|
|||
|
|
# 发现验证码截图保存到本地
|
|||
|
|
failure_count += 1
|
|||
|
|
# 定位元素
|
|||
|
|
element = self.page.ele(
|
|||
|
|
"@class=cap-rounded-lg cap-cursor-pointer cap-w-full cap-h-auto")
|
|||
|
|
# 截取该元素并保存
|
|||
|
|
element.get_screenshot("tiktok_identifying_code.png")
|
|||
|
|
|
|||
|
|
# time.sleep(random.random())
|
|||
|
|
with open('tiktok_identifying_code.png', 'rb') as f:
|
|||
|
|
b = base64.b64encode(f.read()).decode() ## 图片二进制流base64字符串
|
|||
|
|
|
|||
|
|
# 处理验证码
|
|||
|
|
result = self.deal_identifying_code(b)
|
|||
|
|
print(result, type(result))
|
|||
|
|
|
|||
|
|
# 获取x,y的坐标
|
|||
|
|
a = 1
|
|||
|
|
for i in result.split('|'):
|
|||
|
|
a += 1
|
|||
|
|
x = int(int(i.split(',')[0]) * (348 / 552))
|
|||
|
|
y = int(int(i.split(',')[1]) * (217 / 344))
|
|||
|
|
ac = Actions(self.page)
|
|||
|
|
|
|||
|
|
ac.move_to(ele_or_loc=element, offset_x=0, offset_y=0).move(x, y).click()
|
|||
|
|
# print(x,y)
|
|||
|
|
# img = Image.open("tiktok_identifying_code.png")
|
|||
|
|
# draw = ImageDraw.Draw(img)
|
|||
|
|
# draw.ellipse([(x - 5, y - 5), (x + 5, y + 5)], fill='red') # 用红圈标记点击位置
|
|||
|
|
# img.save(f"marked_identifying_code{a}.png")
|
|||
|
|
self.page.ele(
|
|||
|
|
"@class=TUXButton TUXButton--default TUXButton--medium TUXButton--primary cap-my-8 cap-w-full").click()
|
|||
|
|
back_btn = self.page.ele("@data-id=invite-host-back")
|
|||
|
|
if back_btn:
|
|||
|
|
back_btn.click()
|
|||
|
|
continue
|
|||
|
|
# else:
|
|||
|
|
|
|||
|
|
# break
|
|||
|
|
backele=self.page.ele('@data-id=invite-host-back')
|
|||
|
|
if backele:
|
|||
|
|
break
|
|||
|
|
# time.sleep(0.2)
|
|||
|
|
print('重复点击1')
|
|||
|
|
# self.page.set.window.show()
|
|||
|
|
res=self.page.listen.wait(1)
|
|||
|
|
self.page.listen.stop()
|
|||
|
|
while True:
|
|||
|
|
backele=self.page.ele('@data-id=invite-host-back')
|
|||
|
|
backele.click()
|
|||
|
|
nextele=self.page.eles('@data-id=invite-host-next')[0]
|
|||
|
|
if nextele:
|
|||
|
|
break
|
|||
|
|
# time.sleep(0.2)
|
|||
|
|
print('重复点击2')
|
|||
|
|
# self.page.set.window.show()
|
|||
|
|
break
|
|||
|
|
except Exception as e:
|
|||
|
|
print('报错的原因',e)
|
|||
|
|
|
|||
|
|
self.page.refresh()
|
|||
|
|
|
|||
|
|
ele=self.page.ele('@class=semi-button semi-button-tertiary semi-button-size-small semi-button-borderless semi-modal-close semi-button-with-icon semi-button-with-icon-only')
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
else:
|
|||
|
|
check_btn = self.page.ele("@data-id=workplace-switch-button")
|
|||
|
|
if check_btn:
|
|||
|
|
check_btn.click()
|
|||
|
|
|
|||
|
|
|
|||
|
|
while True:
|
|||
|
|
ele=self.page.ele('@data-id=add-host-btn')
|
|||
|
|
try:
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
inputele=self.page.eles('@class=semi-input-textarea semi-input-textarea-autosize')[1]
|
|||
|
|
if inputele:
|
|||
|
|
break
|
|||
|
|
except:
|
|||
|
|
ele=self.page.ele('@class=semi-button semi-button-tertiary semi-button-size-small semi-button-borderless semi-modal-close semi-button-with-icon semi-button-with-icon-only',timeout=1)
|
|||
|
|
if ele:
|
|||
|
|
ele.click()
|
|||
|
|
|
|||
|
|
end_time=time.time()
|
|||
|
|
print('耗时:',end_time-start_time)
|
|||
|
|
return res.response.body
|
|||
|
|
|
|||
|
|
|