zoukankan      html  css  js  c++  java
  • 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 最好使用真实的移动设备.

    复制代码

     

     

  • 相关阅读:
    dva实用的学习笔记
    上传图片到七牛云
    Lodash学习笔记
    Ant Design Pro 脚手架+umiJS 实践总结
    SVN的安装和使用手册
    判断数据类型的5种方法
    常见react面试题汇总(适合中级前端)
    Es6 类class的关键 super、static、constructor、new.target
    ES2019 新特性简介
    通用正则实战200
  • 原文地址:https://www.cnblogs.com/abdm-989/p/15084952.html
Copyright © 2011-2022 走看看