共计 3174 个字符,预计需要花费 8 分钟才能阅读完成。
抖音 App 和服务端交互应用的是 HTTPS 协定,应用 Fiddler 很容易能够捕捉到数据,如下图所示。
不过想要本人模仿一个无效的申请可不是那么容易了,因为它应用了签名机制,在所有申请中都有 as 和 cp 两个签名参数,除非得悉签名算法否则咱们无奈结构出无效的申请。
这里咱们应用模仿操作抖音 App 的形式,让 App 帮咱们收回无效的申请,而后咱们拦挡服务器的 HTTP 应答数据,再从中提取咱们感兴趣的信息。
上面联合一个理论的案例介绍下整个过程,依据客户的需要,要采集一些指定用户加关后的零碎举荐“你可能感兴趣”的数据(如下图所示)用于商品营销。
点击“查看更多”能够看到更多的零碎举荐用户列表数据,如下图所示。
咱们按如下步骤模仿操作 App:
1. 启动抖音。
2. 点击搜寻按钮。
3. 输出搜寻关键词(抖音用户 ID),点击搜寻。
4. 找到匹配的用户,点击关注。
5. 点击零碎举荐“查看更多”,模仿屡次向上滑动屏幕,直至数据加载结束(屏幕呈现“临时没有更多了”)。
于此同时,咱们应用抓包脚本(能够应用 Fiddler 的 Customize Rules,也能够应用 Mitmproxy),捕捉并过滤 URL 中含有 /user/recommend/ 的 HTTP 应答数据,从 JSON 数据中提取零碎举荐的用户信息(如下图所示)。
模仿操作抖音 App 的脚本外围代码如下所示:
view plaincopy to clipboardprint?
from com.dtmilano.android.viewclient import ViewClient
def search_douyin_for_recommend_user(douyin_id):
# 采集指定抖音账号的关注举荐数据
# 连设施
serialno = None
if serialno:
os.system('adbconnect{}'.format(serialno or ''))
time.sleep(3)
device, serialno = ViewClient.connectToDeviceOrExit(serialno=serialno)
vc = ViewClient(device, serialno, autodump=False)
# 强制敞开抖音
log(u'强制敞开抖音.')
device.shell('am force-stop com.ss.android.ugc.aweme')
time.sleep(2)
# 启动抖音
log(u'启动抖音.')
device.shell('am start -n com.ss.android.ugc.aweme/.main.MainActivity')
time.sleep(5)
# 暂停视频播放
log(u'点击屏幕,暂停视频播放.')
device.touch(514, 1048)
# 点击搜寻按钮
vc.dump()
search_btn = vc.findViewById('com.ss.android.ugc.aweme:id/amj')
if search_btn:
log(u'点击搜寻按钮,跳转到搜寻页面.')
search_btn.touch()
vc.dump()
# 点击搜寻输入框
search_input = vc.findViewById('com.ss.android.ugc.aweme:id/ad_')
if search_input:
log(u'点击搜寻框,筹备输出关键词.')
search_input.touch()
# 输出抖音 ID
log(u'输出搜寻关键词: {}.'.format(douyin_id))
device.type(douyin_id.encode('UTF-8'))
# 点击搜寻按钮
search_btn = vc.findViewById('com.ss.android.ugc.aweme:id/cp8')
if search_btn:
log(u'提交搜寻.')
search_btn.touch()
time.sleep(2)
vc.dump()
## 切换到用户
# user_tab = vc.findViewWithText(u'用户')
# user_tab.touch()
# 找到匹配的
matches = []
def find_matches(view):
if view.getClass() == 'android.widget.TextView':
text = view.getText()
if douyin_id.lower() in text.lower():
# 找到匹配的了
log(u'找到匹配的: {}'.format(text))
matches.append(view)
else:
# print text
pass
vc.traverse(transform=lambda view: find_matches(view))
if matches:
# 有没有已关注按钮
btn = vc.findViewWithText(u'已关注')
if btn:
# 先勾销关注
log(u'之前关注过,先勾销关注.')
btn.touch()
time.sleep(1)
user_matched = matches[0]
log(u'点击进入个人主页.')
user_matched.touch()
time.sleep(1)
# 点关注
vc.dump()
follow_btn = vc.findViewById('com.ss.android.ugc.aweme:id/aei')
if follow_btn:
# 点击关注
log(u'点击关注')
follow_btn.touch()
time.sleep(1)
# 点击查看更多
vc.dump()
viewmore_btn = vc.findViewById('com.ss.android.ugc.aweme:id/bqn')
if viewmore_btn:
# 点击查看更多
log(u'点击查看更多零碎举荐')
viewmore_btn.touch()
time.sleep(1)
i = 0
while True:
# 上滑动
device.drag((345, 1762), (345, 550), duration=100)
log(u'上滑以加载更多')
i += 1
if i % 5 == 0:
# 拖动 10 次判断一下是否还有更多
vc.dump()
if vc.findViewWithText(u'临时没有更多了'):
log(u'临时没有更多了,"{}"的关注举荐数据采集结束.'.format(douyin_id))
# 采集胜利了
return True
failed_tip = vc.findViewWithText(u'加载失败,点击重试')
if failed_tip:
log(u'加载失败, 点击重试.')
failed_tip.touch()
else:
# 没有找到查看更多按钮
log(u'没有找到查看更多按钮')
else:
# 没有找到加关注按钮
log(u'没有找到加关注按钮')
else:
# 没有找到匹配的用户
log(u'没有找到匹配的用户')
else:
# 没有找到搜寻提交按钮
log(u'没有找到搜寻提交按钮.')
else:
# 没有找到搜寻输入框
log(u'没有找到搜寻输入框.')
else:
# 没有找到搜寻按钮
log(u'没有找到搜寻按钮.')
上述脚本的运行截图如下所示:
最初附上抓取到的局部示例数据:
——————————————————————————————————————————
TiToData:业余的短视频、直播数据接口服务平台。
更多信息请分割:TiToData
笼罩支流平台:抖音,快手,小红书,TikTok,YouTube
——————————————————————————————————————————
TiToData:业余的短视频、直播数据接口服务平台。
更多信息请分割:TiToData
笼罩支流平台:抖音,快手,小红书,TikTok,YouTube