身边人不断被抖音神曲洗脑,并且深夜狂刷小视频的同僚大有人在,不甘落伍,本人也下载下来一探究竟,果然满屏的漂亮小姐姐。但是自己动手一遍一遍下划实在费劲,结合github上的项目,心想是否可以用Python实现一个douyin_bot帮我完成这些事情,比如关注、点赞、下载小视频。
目录
需求分析
工作原理
使用方法
工作步骤
1、Appium自动化配置
2、Mitmproxy流量分析
3、连接腾讯人脸识别API
4、主要程序
结果展示
本人以honor magic手机为例,在设置中调试出开发者模式与电脑相连。在Appium操作界面,配置抖音APP的各项参数如图
其中appPackage和appActivity两个参数的配置见我之前的blog :Appium参数配置 。然后开始 Start Session
因为要做自动化测试,所以要模拟点击事件,因此需要记录屏幕主要控件所在的平面坐标 ,记录点赞、关注按钮的XY坐标。
Mitmproxy是手机抓包分析工具,具体使用方法参见上一批blog Mitmproxy抓包分析,在这篇文章里,已经分析出了抖音小视频的URL路径:
根据mitmdump展示的请求,前缀分别为
'http://v1-dy.ixigua.com/', 'http://v9-dy.ixigua.com/',
'http://v6-dy.ixigua.com' , 'http://v3-dy-z.ixigua.com/',
'http://v3-dy-x.ixigua.com/' , 'http://v3-dy-y.ixigua.com/',
'http://v7.pstatp.com/'
这七类前缀的URL正是我们目标抖音视频的URL 。
代码如下:
import requests
# 文件路径
path = '/Users/Macx/Desktop/python_demo/Douyin-Bot-master/video/'
num = 1
#使用mitmdump和python脚本拦截http请求和处理flow.request.url,用def response(flow)
def response(flow):
global num
# 经测试发现视频url前缀主要是7个
target_urls = ['http://v1-dy.ixigua.com/', 'http://v9-dy.ixigua.com/',
'http://v6-dy.ixigua.com' , 'http://v3-dy-z.ixigua.com/',
'http://v3-dy-x.ixigua.com/' , 'http://v3-dy-y.ixigua.com/',
'http://v7.pstatp.com/' ]
#依次从以上7个URL中选出一个进行迭代
for url in target_urls:
# 过滤掉不需要的url。如果拦截的http请求是以以上URL为开头
if flow.request.url.startswith(url):
# 设置视频名
filename = path + str(num) + '.mp4'
# 使用request获取视频url的内容
# stream=True作用是推迟下载响应体直到访问Response.content属性
res = requests.get(flow.request.url, stream=True)
# 将视频写入文件夹
with open(filename, 'ab') as f:
f.write(res.content)
f.flush()
print(filename + '下载完成')
num += 1
登陆腾讯AI开放平台创建应用
官网下载SDK ,并引入apiutil.py文件,参考官网
进行修改后:
#-*- coding: UTF-8 -*-
import hashlib
import urllib
from urllib import parse
import urllib.request
import base64
import json
import time
url_preffix='https://api.ai.qq.com/fcgi-bin/'
def setParams(array, key, value):
array[key] = value
def genSignString(parser):
uri_str = ''
for key in sorted(parser.keys()):
if key == 'app_key':
continue
uri_str += "%s=%s&" % (key, parse.quote(str(parser[key]), safe=''))
sign_str = uri_str + 'app_key=' + parser['app_key']
hash_md5 = hashlib.md5(sign_str.encode('utf-8'))
return hash_md5.hexdigest().upper()
class AiPlat(object):
def __init__(self, app_id, app_key):
self.app_id = app_id
self.app_key = app_key
self.data = {}
self.url_data = ''
def invoke(self, params):
self.url_data = urllib.parse.urlencode(params).encode("utf-8")
#利用urlopen()方法可以实现最基本请求的发起,但这几个简单的参数并不足以
#构建一个完整的请求,如果请求中需要加入headers(请求头)等信息,我们就可以利用
#更强大的Request类来构建一个请求
#如req = urllib.request.Request(url=url,data=data,method='POST')
#req.add_headers('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36')
req = urllib.request.Request(self.url, self.url_data)
try:
#rsp为针对请求获得的响应,为字典格式
rsp = urllib.request.urlopen(req)
str_rsp = rsp.read().decode('utf-8')
dict_rsp = json.loads(str_rsp)
return dict_rsp
except Exception as e:
print(e)
return {'ret': -1}
def face_detectface(self, image, mode):
self.url = url_preffix + 'face/face_detectface'
setParams(self.data, 'app_id', self.app_id)
setParams(self.data, 'app_key', self.app_key)
setParams(self.data, 'mode', mode)
setParams(self.data, 'time_stamp', int(time.time()))
setParams(self.data, 'nonce_str', int(time.time()))
image_data = base64.b64encode(image)
setParams(self.data, 'image', image_data.decode("utf-8"))
sign_str = genSignString(self.data)
setParams(self.data, 'sign', sign_str)
return self.invoke(self.data)
# -*- coding: utf-8 -*-
"""
使用Appium做自动化模拟测试
"""
import sys
import random
import time
from PIL import Image
if sys.version_info.major != 3:
print('Please run under Python3')
exit(1)
try:
from common import debug, config, screenshot, UnicodeStreamFilter
from common.auto_adb import auto_adb
from common import apiutil
from common.compression import resize_image
except Exception as ex:
print(ex)
print('请将脚本放在项目根目录中运行')
print('请检查项目根目录中的 common 文件夹是否存在')
exit(1)
VERSION = "0.0.1"
# 申请地址 http://ai.qq.com
AppID = '1107029674'
AppKey = 'fW0via1sILxB7K4o'
DEBUG_SWITCH = True
FACE_PATH = 'face/'
adb = auto_adb()
adb.test_device()
config = config.open_accordant_config()
# 审美标准
BEAUTY_THRESHOLD = 80
# 最小年龄
GIRL_MIN_AGE = 18
def yes_or_no():
"""
检查是否已经为启动程序做好了准备
"""
while True:
yes_or_no = str(input('请确保手机打开了 ADB 并连接了电脑,'
'然后打开手机软件,确定开始?[y/n]:'))
if yes_or_no == 'y':
break
elif yes_or_no == 'n':
print('谢谢使用', end='')
exit(0)
else:
print('请重新输入')
def _random_bias(num):
"""
random bias
:param num:
:return:
"""
print('num = ', num)
return random.randint(-num, num)
def next_page():
"""
翻到下一页
:return:
"""
#模拟滑动,从x1,y1经历durationg时间滑动到x2,y2
cmd = 'shell input swipe {x1} {y1} {x2} {y2} {duration}'.format(
x1=config['center_point']['x'],
y1=config['center_point']['y']+config['center_point']['ry'],
x2=config['center_point']['x'],
y2=config['center_point']['y']-config['center_point']['ry'],
duration=200
)
adb.run(cmd)
time.sleep(2.0)
def follow_user():
"""
关注用户
:return:
"""
#模拟点击
cmd = 'shell input tap {x} {y}'.format(
x=config['follow_bottom']['x'] + _random_bias(10),
y=config['follow_bottom']['y'] + _random_bias(10)
)
adb.run(cmd)
time.sleep(0.5)
def thumbs_up():
"""
点赞
:return:
"""
cmd = 'shell input tap {x} {y}'.format(
x=config['star_bottom']['x'] + _random_bias(10),
y=config['star_bottom']['y'] + _random_bias(10)
)
adb.run(cmd)
time.sleep(0.5)
def main():
"""
main
:return:
"""
print('程序版本号:{}'.format(VERSION))
print('激活窗口并按 CONTROL + C 组合键退出')
debug.dump_device_info()
screenshot.check_screenshot()
while True:
next_page()
time.sleep(0.5)
#通过以下方法获得截图autojump.png
screenshot.pull_screenshot()
#通过以下方法对截图进行压缩,得到optimized.png
resize_image('autojump.png', 'optimized.png', 1024*1024)
with open('optimized.png', 'rb') as bin_data:
image_data = bin_data.read()
#初始化AiPlat
ai_obj = apiutil.AiPlat(AppID, AppKey)
#调用AiPlat的face_detectface方法,生成字典形式的rsp,存放图片信息及图片
rsp = ai_obj.face_detectface(image_data, 0)
major_total = 0
minor_total = 0
#若调用成功。ret返回0,调用成功,非0失败
if rsp['ret'] == 0:
beauty = 0
for face in rsp['data']['face_list']:
print(face)
#标注脸部区域
face_area = (face['x'], face['y'], face['x']+face['width'], face['y']+face['height'])
print(face_area)
img = Image.open("optimized.png")
#对脸部进行切割
cropped_img = img.crop(face_area).convert('RGB')
cropped_img.save(FACE_PATH + face['face_id'] + '.png')
# 性别判断
if face['beauty'] > beauty and face['gender'] < 50:
beauty = face['beauty']
if face['age'] > GIRL_MIN_AGE:
major_total += 1
else:
minor_total += 1
# 是个美人儿~关注点赞走一波
if beauty > BEAUTY_THRESHOLD and major_total > minor_total:
print('发现漂亮妹子!!!')
thumbs_up()
follow_user()
else:
print(rsp)
continue
if __name__ == '__main__':
try:
# yes_or_no()
main()
except KeyboardInterrupt:
adb.run('kill-server')
print('谢谢使用')
exit(0)
下载的小视频:
至于自动点赞、关注什么的就不录制视频了,亲测可以,让程序飞一会儿》》》》》》