抖音短视频爬取实战

需求

爬取用户的抖音号、粉丝数、关注数、点赞数html

目的:

某公司作生鲜电商平台,这个公司平台想在流量平台上投放广告,发现抖音这个大平台,python

抖音拥有不错的用户流量,经过数据分析预测在抖音投放公司广告,看他是否会对公司利益带来收益,这样就要分析抖音数据,抖音的用户画像,判断用户群体与公司的匹配度。android

那么分析昵称,粉丝书,关注书,和公司有什么关系,经过分析能够知道谁的粉丝忽然就增多了,谁的点赞数增多,那么这个时候就能够和广告合做,拍广告或者作营销宣传,或者根据点赞趋势,能够知道用户喜欢的视频,,这样就能够想办法把公司产品融入到用户喜欢的视频中,公关公司根据数据,找到网红黑马,进行营销包装。web

 

 

三 粉丝数据接口

使用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中间人代理的方式抓取数据包,并保存咱们须要的数据。json

 

粉丝请求urlbootstrap

https://aweme.snssdk.com/aweme/v1/user/follower/list/

 

 

编写mitproxy处理响应体数据,代码以下api

 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文件,验证,获取的数据为粉丝列表响应数据。app

 

 

数据清洗过程

 

 

入库

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 最好使用真实的移动设备.
相关文章
相关标签/搜索