043 抖音短视频爬取实战
需求
爬取用户的抖音号、粉丝数、关注数、点赞数
目的:
某公司做生鲜电商平台,这个公司平台想在流量平台上投放广告,发现抖音这个大平台,
抖音拥有不错的用户流量,通过数据分析预测在抖音投放公司广告,看他是否会对公司利益带来收益,这样就要分析抖音数据,抖音的用户画像,判断用户群体与公司的匹配度。
那么分析昵称,粉丝书,关注书,和公司有什么关系,通过分析可以知道谁的粉丝突然就增多了,谁的点赞数增多,那么这个时候就可以和广告合作,拍广告或者做营销宣传,或者根据点赞趋势,可以知道用户喜欢的视频,,这样就可以想办法把公司产品融入到用户喜欢的视频中,公关公司根据数据,找到网红黑马,进行营销包装。
三 粉丝数据接口
使用fiddler抓包
https://aweme.snssdk.com/aweme/v1/user/follower/list/?user_id=105178085411&max_time=1556944953&count=20&offset=0&source_type=1&address_book_access=1&gps_access=1&retry_type=no_retry&iid=70850033498&device_id=67587886667&ac=wifi&channel=tengxun_new&aid=1128&app_name=aweme&version_code=600&version_name=6.0.0&device_platform=android&ssmix=a&device_type=SM-G955F&device_brand=samsung&language=zh&os_api=22&os_version=5.1.1&uuid=354730011196544&openudid=1c45444f5846a419&manifest_version_code=600&resolution=720*1280&dpi=240&update_version_code=6002&_rticket=1556944951543&mcc_mnc=46007&ts=1556944953&as=a115515c29b3bc480d4611&cp=1c3bc6579cd1ca83e1%5DcKg&mas=01f0b2caf2e5cf4c82c18f011cc8e22af58c8c6c2c260c1c2cc646
mitmproxy中间人代理
发现请求头中的加密数据太多,我们换成了mitmproxy中间人代理的方式抓取数据包,并保存我们需要的数据。
粉丝请求url
https://aweme.snssdk.com/aweme/v1/user/follower/list/
编写mitproxy处理响应体数据,代码如下
def response(flow): if 'aweme/v1/user/follower/list/' in flow.request.url: with open('user.txt','w') as f: f.write(flow.response.text)
启动 mitmdump
mitmdump -s decode_douyin_fans.py -p 8889
手机端或者模拟器端,设置好代理,启动抖音刷粉丝页面,生成txt文件,验证,获取的数据为粉丝列表响应数据。
数据清洗过程
入库
mitmdump response拦截代码
import json from handle_db import mongo_info def response(flow): if 'aweme/v1/user/follower/list/' in flow.request.url: for user in json.loads(flow.response.text)['followers']: douyin_info={} douyin_info['share_id']=user['uid'] douyin_info['douyin_id']=user['short_id'] douyin_info['nickname']=user['nickname'] mongo_info.save_task(douyin_info) # print(douyin_info)
handle_db.py
数据库操作代码
import pymongo class Connect_mongo(object): def __init__(self): #连接数据库,如果没有数据,则创建数据库 self.client=pymongo.MongoClient(host='106.12.108.236',port=27017) self.db=self.client['douyindb'] def save_task(self,task): '保存粉丝信息' db_collection=self.db['douyin'] #找到就更新,没找到就新增 db_collection.update({'share_id':task['share_id']},task,True) def handle_get_task(self): #获取到数据,并删除数据库中的文档 return self.db['douyin'].find_one_and_delete({}) mongo_info=Connect_mongo()
appium实现抖音app自动滑动实现粉丝数据包的处理
1 测试是否连通,代码如下
from appium import webdriver #等待元素加载 from selenium.webdriver.support.ui import WebDriverWait #定义设备参数 cap={ "platformName": "Android", "platformVersion": "5.1.1", "deviceName": "127.0.0.1:62025", "appPackage": "com.ss.android.ugc.aweme", "appActivity": "com.ss.android.ugc.aweme.main.MainActivity", "noReset": True, 'unicodekeyboard':True, #使用unicode输入法 'resetkeyboard':True, #还原输入法 } driver =webdriver.Remote('http://localhost:4723/wd/hub',cap)
2 连通后使用uiautomator viewer,获取空间的id,xpath...表达式
注释事项:抓取截屏数据的时候,必须等待数据加载完毕,或者把视频暂停,否则报错
此过程使用了appium和uiautomator viewer交替定位元素.
最终appium代码,如下
import time from appium import webdriver #等待元素加载 from selenium.webdriver.support.ui import WebDriverWait #定义设备参数 cap={ "platformName": "Android", "platformVersion": "6.0.1", "deviceName": "758ca8ba", "appPackage": "com.ss.android.ugc.aweme", "appActivity": "com.ss.android.ugc.aweme.main.MainActivity", "noReset": True, 'unicodekeyboard':True, #使用unicode输入法 'resetkeyboard':True, #还原输入法 } driver =webdriver.Remote('http://localhost:4723/wd/hub',cap) def get_size(): #获取设备屏幕大小 x=driver.get_window_size()['width'] y=driver.get_window_size()['height'] return x,y #点击搜索框 try: if WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("com.ss.android.ugc.aweme:id/aqz")): driver.find_element_by_id("com.ss.android.ugc.aweme:id/aqz").click() except: pass #定位搜索框 try: if WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath( "//android.widget.EditText[@resource-id='com.ss.android.ugc.aweme:id/agq']")): driver.find_element_by_xpath( "//android.widget.EditText[@resource-id='com.ss.android.ugc.aweme:id/agq']").send_keys('191433445') except: pass #点击搜索 if WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath("//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/agt']")): driver.find_element_by_xpath("//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/agt']").click() #点击用户,进入个人主页 if WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout[2]/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.support.v7.widget.RecyclerView/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.ImageView[2]")): el4 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout[2]/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.support.v7.widget.RecyclerView/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout/android.widget.FrameLayout/android.widget.ImageView[2]") el4.click() # 点击粉丝 if WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath("//android.widget.TextView[@text='粉丝']")): driver.find_element_by_xpath("//android.widget.TextView[@text='粉丝']").click() # 等待页面刷新 time.sleep(3) #开始滑动 l =get_size() x1=int(l[0]*0.5) y1=int(l[1]*0.9) y2=int(l[1]*0.25) while True: if '没有更多了' in driver.page_source: break else: #初始位置x1,y1 结束位置为:x1,y2 driver.swipe(x1,y1,x1,y2) time.sleep(0.2)
电脑开wifi给手机用,使用mitmdump开代理,有点坑,ip找这里,我用的是网线!!!
代码执行顺序
1 启动弄mitmproxy
mitmdump -p 8889 -s decode_douyin_fans.py
2 启动appnium程序,把粉丝信息入库
python handle_appium_douyin.py
3 执行采集分享id对应用户的详细信息,并入库
python handle_share_web.py
多任务端
注意事项
查找模拟器对应端口,找到对应的设备.
没有粉丝处理
返回,清空,重新输入
封装兼容不同设备函数
启动多进程
伪装爬虫
抖音视频下载
网页源码中找到加密js
请求参数分析 max_cursor
网页中加的dytk
解密signature找寻流程
网页张找到js加密文件,全局搜索(点击右侧三个点,或者ctrl +f)
继续找
一层一层的找,找到所有的流程
找完之后,开始构建html文件和js文件
html 头部文件
html尾部文件(复制调用的js函数到脚部文件)
使用文件合并的方法,生成html文件
每次打开生成的html 自动生成signature 秘钥
js 破解思路:
使用开发者工具,全局搜索加密字段所在的文件,理清楚加密过程,即执行流程,自己构建html文件,模拟加密执行函数,无需自己写,只需要拷贝js代码.
项目总结
个人数据 --TTF 字体混淆
fontedit解析字体,找到映射关系表
映射表,正则替换
粉丝数据抓取
appium模拟滑动+mitmdump解析数据
使用了uiautomator viewer和appium结合进行元素定位,进行元素的操作,使用mitmdump中间人攻击技术,在请求分数数据的时候,把响应数据进行解析,入库.
视频抓取阶段
编写破解文件
注意:
1 ttf字体数据对应关系,如果关系更改了,爬虫就需要做响应的更改.
2 一般一个名人最多获取5000条粉丝数据
3 移动设备设置代理抓包后,如果无法联网或无法解析https数据时候,需要安装xpose框架+justtrustme组件进行屏蔽证书强校验.
4 在设置多设备、多进程数据抓取时候,需要设置appium服务器端的bootstrap端口,以及客户端的udid字段.
5 视频数据抓取,需要破解signature字段,并使用html文件,解析js,
拼接html文件,逆退出加密过程.
6 数据抓取需要加上代理,伪装爬虫.
7 最好使用真实的移动设备.