博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
爬虫篇——自动化采集抖音热门视频数据
阅读量:3905 次
发布时间:2019-05-23

本文共 9287 字,大约阅读时间需要 30 分钟。

目的:采集抖音热度较高的视频 (要自动化)

抖音的防爬技术做的特别好,据说是专门有反爬部门。所以通过编写代码直接去访问抖音接口,不能达到目的。只能模拟真实用户行为,来得到数据。

我主要的实现方法是:通过 在 安卓模拟器里 模拟用户滑动,通过网络代理拦截滑动过程中产生的数据

开发中用到的工具:

硬件:需要一台空闲的电脑,
软件:auto.js、安卓模拟器、、按键精灵、抓包工具

开发过程

1 确定要从抖音的哪个接口里采集数据

考虑 从首页推荐列表用户作品列表 取数据。

我用的fiddler抓包工具,

抓取 首页推荐列表 接口,发现数据格式为Protobuf,是一个传输速度更快、占用空间更小的数据格式,解析这样的格式需要配套的文件。所以我们无法解析,放弃 页推荐列表。

尝试从用户作品列表接口 抓包,发现是json格式,而且可以拿到视频信息。所以决定从用户作品列表 采集

在这里插入图片描述

2. 自动化工具 auto.js 模拟用户滑动抖音列表

为了确保 采集的视频热度要高,我们并不是所有的用户作品都采集。所以我们模拟的用户行为:在首页的推荐视频里滑动,滑到点赞量大于10万的视频,向左滑动,进入该视频作者的作品列表

首先要在电脑里 安装好 安卓模拟器,我用的是天天模拟器

在模拟器里 安装抖音 和 auto.js 应用,编写auto.js 自动化脚本,运行脚本。
在这里插入图片描述

var myDate = new Date();var hours = myDate.getHours();if (hours >= 0) {
console.log("去启动抖音"); launchApp("抖音"); sleep(7000) while (true) {
是否满足赞(); 左滑进入个人中心(); 判断是否出去(); 关闭崩溃应用(); toast("quit persion center ") 退出个人中心(); //Swipe(10, device.height / 2,device.width / 2, device.height / 2, 10, 300);//向右滑 sleep(2000); toast("hua dong cao zuo ") Swipe(device.width / 2, device.height / 1.5, device.width / 2, 10, 500); //向下滑 sleep(3000); 每10分钟重启(); 取消弹框(); 判断是否出去(); 关闭崩溃应用(); }}function 是否满足赞() {
log("是否满足赞") try {
//不满足1万的赞划走 while (isTrue()) {
Swipe(device.width / 2, device.height / 1.5, device.width / 2, 10, 500); //向下滑 toast("Dig not satisfied") sleep(1500); 退出个人中心(); } } catch (e) {
}}function isTrue() {
// var u = id("aen").find() // var e = u.length - 2 // var tv = u[e]; return false; var like = 0; try {
var b = id("com.ss.android.ugc.aweme:id/aer").find(); var a = b[1].desc() if (a && a.indexOf("喜欢") > -1) {
like = a.substring(a.indexOf("喜欢") + 2, a.indexOf(",按钮")); toastLog(like); } } catch (e) {
} if (like.indexOf("w") == -1) {
return true; } else {
return like.substr(0, like.indexOf("w")) < 5; }}function 左滑进入个人中心() {
log("左滑进入个人中心") toast("left swipe ") Swipe(device.width / 1.1, device.height / 2, 10, device.height / 2, 10, 800); //向左滑 //id("text1").className("android.widget.TextView").textMatches(/(.*作品.*)/).findOnce().click(); sleep(2000); //关注或加载更多(); sleep(2000);}function 每10分钟重启() {
log("每10分钟重启") var myDate = new Date(); if (myDate.getMinutes() % 10 == 0 && myDate.getSeconds() <= 30) {
//每10分钟重启一次 app.openAppSetting("com.ss.android.ugc.aweme"); // text(app.getAppName("com.ss.android.ugc.aweme")).waitFor(); sleep(2000) let is_sure = textMatches(/(.*强.*|.*停.*|.*结.*|.*行.*)/).findOne(); if (is_sure.enabled()) {
sleep(1000); textMatches(/(.*强.*|.*停.*|.*结.*|.*行.*)/).findOne().click(); sleep(1000); textMatches(/(.*确.*|.*定.*)/).findOne().click(); 清除缓存(); sleep(500); back(); back(); log("应用已被关闭"); sleep(1000); back(); sleep(1000) } else {
log("应用不能被正常关闭或不在后台运行"); back(); } }}function 清除缓存() {
log("清除缓存") sleep(20000) try {
click("内部存储空间"); click("正在计算"); sleep(2000) } catch (e) {
} try {
textMatches(/(.*清除缓存.*)/).findOnce().click(); } catch (e) {
}}//如果APP出现弹框,那么点击取消弹框function 取消弹框() {
log("取消弹框") try {
if (id("a7_").exists()) {
id("a7_").findOnce().click(); console.log("tankuan1") } if (id("eem").exists) {
console.log("tankuan2") id("eem").findOnce().parent().click() } if (id("ru").exists()) {
id("ru").findOnce().click() console.log("tankuan3") } if (id("bsv").exists()) {
console.log("tankuan4") id("bsv").findOnce().click(); } if (id("c4").exists()) {
console.log("tankuan5") id("c4").findOnce().click() } } catch (e) {
}}//判断APP是否已经退出,如果已经退出,那么重新启动APPfunction 判断是否出去() {
log("判断是否出去") if (!packageName("com.ss.android.ugc.aweme").exists()) {
back(); sleep(300); back(); sleep(300); back(); back(); toast("lack reload dou yin"); launchApp("抖音短视频"); sleep(15000); }}//处理app奔溃的弹框function 关闭崩溃应用() {
log("关闭崩溃应用") try {
if (textMatches(/(.*确.*|.*定.*)/).exists()) {
textMatches(/(.*确.*|.*定.*)/).findOnce().click(); sleep(1000); } if (textMatches(/(.*以后再说.*)/).exists()) {
textMatches(/(.*以后再说.*)/).findOnce().click(); sleep(1000); } if (textMatches(/(.*我知道了.*)/).exists()) {
textMatches(/(.*我知道了.*)/).findOnce().click(); sleep(1000); } } catch (e) {
}}function 退出个人中心() {
log("退出个人中心") if (id("com.ss.android.ugc.aweme:id/ko").exists()) {
id("com.ss.android.ugc.aweme:id/ko").findOnce().click(); } if (id("com.ss.android.ugc.aweme:id/a1l").exists()) {
id("com.ss.android.ugc.aweme:id/a1l").findOne().click() } if (id("com.ss.android.ugc.aweme:id/a1x").exists()) {
id("com.ss.android.ugc.aweme:id/a1x").findOne().click() } if (desc("返回").exists()) {
desc("返回").findOne().click(); }}function 关注或加载更多() {
try {
sleep(2000); /*toastLog("11"); var totallike = id("adx").findOnce().text(); toastLog("1.2"); var totalfans = id("aw6").findOnce().text(); var uniqueid = id("f7w").findOnce().text(); var authorname = id("cid").findOnce().text(); toastLog("222")*/ var loadMore = false; var totallike, totalfans, uniqueid, authorname var arr = className("android.widget.TextView").find(); for (var i in arr) {
var text try {
text = arr[i].text(); } catch (e) {
} if (text && text == "获赞") {
totallike = arr[i - 1].text(); } if (text && text == "粉丝") {
totalfans = arr[i - 1].text(); } if (text && text.indexOf("抖音号:") > -1) {
uniqueid = text; authorname = arr[i - 1].text(); } } if (!uniqueid) {
return } toastLog("id: " + uniqueid + " 集赞:" + totallike + " 粉丝:" + totalfans + " name:" + authorname) //总点赞数大于1000W 关注作者 if (authorname && totallike.indexOf("w") > -1) {
if (parseInt(totallike.substr(0, totallike.length - 1)) >= 1000) {
//关注作者 payAttention(totallike, totalfans, uniqueid, authorname); } } //总点赞数或粉丝数大于1亿 关注作者并抓取更多 if (authorname && totallike.indexOf("亿") > -1 || totalfans.indexOf("亿") > -1) {
//关注作者 loadMore = payAttention(totallike, totalfans, uniqueid, authorname); } //粉丝量大于500W 关注作者, 如果粉丝量大于1000W 抓取作者更多作品 if (authorname && totalfans.indexOf("w") > -1) {
var fansCount = parseInt(totalfans.substr(0, totalfans.length - 1)); if (fansCount >= 500 && fansCount < 1000) {
//关注作者 payAttention(totallike, totalfans, uniqueid, authorname); } else if (fansCount >= 1000) {
loadMore = payAttention(totallike, totalfans, uniqueid, authorname); } } if (loadMore) {
sleep(4000); log("into swipe action ") for (var i = 0; i < 4; i++) {
Swipe(device.width / 2, device.height / 1.5, device.width / 2, 10, 500); //向下滑 } } sleep(1000); } catch (e) {
toastLog("attention err : " + e) }}//关注作者 function payAttention(totallike, totalfans, uniqueid, authorname) {
http.get("http://testtest/schedule/adddouyinauthor?uniqueid=" + uniqueid + "&authorname=" + authorname + "&totallike=" + totallike + "&totalfans=" + totalfans, {
}, function(res, err) {
if (err) {
console.error(err); return false; } var data = res.body.json(); log("return result : " + data.result) //关注作者状态:1已关注 0已拉黑取消关注 if (data.result == 1) {
id("com.ss.android.ugc.aweme:id/d21").findOnce().click(); } else {
id("com.ss.android.ugc.aweme:id/avq").findOnce().click(); return false; } }); return true;}

3.启动网络代理服务项目 拦截想要的数据,并发送到自己的服务器 入库

在自己修改后部署到 安装模拟器的那台电脑上。

修改的核心代码:

在这里插入图片描述
代理项目部署后,在安卓模拟器上 设置代理及端口 (代理项目的部署相关详细的请参考GitHub学习)。

当全部 部署和设置完成后,启动auto.js的自动化脚本,开始刷抖音。在刷到用户中心后,代理服务器会拦截数据 然后发送到 我们线上的服务器,继而 再做数据解析 ,入库。

数据解析部分代码如下:

在这里插入图片描述

4.用按键精灵,自动启动auto.js里的脚本

自动化脚本在安卓模拟器中运行的时候,有时会造成模拟器卡死,如果一旦卡死,我们必须人工去重启,这很麻烦。为了确保所有都自动化, 所以我们 定时每5个小时重启一次电脑,在电脑启动时,自动开启安卓模拟器里的auto.js脚本 和 开启 网络代理服务项目。

这里是 通过编写按键精灵脚本 实现 以上的启动

在这里插入图片描述

|

|

以上就是我完成 自动化 采集抖音 的大概过程。其中编写相关脚本和 部署代理服务项目 花费了很多时间。

这里只描述了大概过程,有些详细细节 并没写到,比如:

采集的视频链接,只有1个小时的时效性。必须尽快下载到自己服务器
即使是模拟真实用户行为,但是频繁的刷抖音,也会被限制 如:刷不到热门视频。 所以要限制每天程序的执行时间

|

|
|

以上就是我的开发过程,我相信还有其他更高效的方法。

转载地址:http://uomen.baihongyu.com/

你可能感兴趣的文章
使用火焰图分析CPU性能回退问题
查看>>
openresty lua zlib整合安装 让lua支持解压服务端压缩过的数据
查看>>
Nginx与Gzip请求
查看>>
最佳日志实践(v2.0)
查看>>
logstash日志分析的配置和使用
查看>>
Nginx问题定位之监控进程异常退出
查看>>
https://imququ.com/post/content-encoding-header-in-http.html
查看>>
字符编码的前世今生
查看>>
视频笔记:Go 抓包、分析、注入 - John Leon
查看>>
linux下模拟丢包,延时命令总结
查看>>
java的字符流简单介绍
查看>>
初识java的xml
查看>>
通过DOM方式对xml文件进行解析
查看>>
哈希桶处理哈希冲突
查看>>
位图(BitMap)&& 布隆过滤器(BloomFilter)
查看>>
总结: 笔试中常见virtual函数问题
查看>>
vue中使用mock模拟后端数据
查看>>
常见的数据库有哪几种?
查看>>
Java后端的SQL语句
查看>>
注意:eclipse使用自己的编译器
查看>>