我的网站开发技术经验总结 我的网站开发技术经验总结
首页

fangdown

我的网站开发技术经验总结
首页
  • 认识ESM
  • chrome-talend插件,类似postman
  • sequelize 使用及技巧
  • UML工具Power Designer建表
  • sequelize相关操作文档
  • 解决抖音获取签名及并发的问题
  • 记一次解决抖音分享页混淆字体,字体图标转UID解决方案
  • 获取抖音用户作品列表信息
  • 获取抖音用户作品列表信息-进阶
    • 概要
    • 问题
    • 优化点
    • 坑
    • 相关
    • 代码
  • 获取抖音用户作品列表信息-进阶3
  • 如何根据抖音号获取用户信息
  • 获取用户最新视频
  • 模块化-import和require的区别
  • eslint规范
  • js容错处理
  • js-数组分组,执行promise
  • reduce使用遇到的问题
  • 正则匹配html的元素内容
  • taro 小程序 弹窗层禁止底部滚动
  • 公众号签名问题
  • CentOS7中MariaDB重置密码
  • nginx多域名配置
  • node访问接口,得到乱码的结果,原因-Accept-Encoding
  • node写文件到json中
  • node抓取html内容
  • Node.js使用ES6语法
  • express 使用cors中间件解决跨域
  • node + express + session + redis 进行持久化缓存
  • node中读取文件夹,获取文件名称
  • pm2常用命令
  • 使用pm2管理后台node服务
  • typescript puppeteer支持window及document属性
  • node读取json文件
  • node中使用redis缓存
  • node + github的webhook完成自动部署
  • vuepress-blog的性能优化-CDN
  • CENTOS7下安装REDIS
  • promise then和catch的学习和使用
  • promise在循环中的串行并行用法
  • puppeteer常用知识
  • centos部署安装puppeteer
  • python的学习和使用
  • Taro+TypeScript - Mobx实践
  • 爬虫系列 --- 反爬机制和破解方法汇总
  • 安全-html转码
  • taro中使用animation动画
  • charles 使用
  • Mac下VSCode设置iTerm2终端样式
  • centos一步步完成站点部署
  • 云闪付做地铁的思路
  • 准备技能
  • 备案pc项目介绍
  • 备案小程序项目介绍
  • 小程序二维码扫码功能
  • 小程序域名组件开发
  • 小程序添加水印
  • 规则引擎优化
  • 记一次hooks代替redux的经历
  • 通过nodejs+koa+stream进行服务端图片代理
  • nodeJs接入log4j日志
  • nodejs+typescript项目中添加全局global属性
  • create-react-app 安装 bizcharts 项目崩溃
  • 使用MutationObserver监控dom的变化
  • 服务器重启后启动相关服务
  • moment国际化的问题
  • 项目经验
fangdown
2019-11-18
目录

获取抖音用户作品列表信息-进阶

# 概要

继上一篇用puppeteer获取用户作品列表的方式,做了一些优化方案

# 问题

  1. 上一篇文章描述的方案,有一个日期范围的缺点,20条记录产生的跨度比较大,不是很精确,需优化
  2. 通过模拟浏览的方式, 有一点耗时,不过没有后遗症

# 优化点

  1. 日期范围的问题, 根据接口返回内容格式,有一个min_cursor, max_cursor,最小和最大游标,利用这个特性只访问2条记录,一条记录一个。那就很明确了该作品的日期。

  2. 采取了拦截请求url获取签名等重要参数(很难伪造),

const page = await browser.newPage();
await page.setRequestInterception(true);
  1. 获取到参数后拼接请求参数,递归查询
const loopList = async (param: IList): Promise<any> => {
  await sleep(500);
  const res = await getList(param);
  if (res.aweme_list && res.aweme_list.length) {
    const list = res.aweme_list;
    list[0].timestamp = res.min_cursor;
    if (list[1]) list[1].timestamp = res.max_cursor;
    result.push(...list);
    // 必须有retrun
    return loopList({ ...param, max_cursor: res.max_cursor });
  } else {
    return new Promise(resolve => {
      resolve(result);
    });
  }
};
  1. 拿到结果后可以存入文件中,也可以调用接口保存

# 坑

在第二步拿到签名信息的时候,去发起接口请求,发现接口返回是空, 想想应该是user-agent的问题,于是随便增加了一个user-Agent,还是不行,再深入一想,会不会签名和生成的浏览器有关呢,于是把无头浏览器的user-Agent放入接口中。正常返回了!!! 抖音的接口加密做的还是很好的!!

# 相关

  • 获取抖音用户作品列表信息 (opens new window)
  • 获取抖音用户作品列表信息-进阶3 (opens new window)

# 代码


// 获取抖音用户作品列表~
import { getList, IList } from '../services/douyin-share';
import { sleep } from '../utils/star';
import { saveAuthorVideo } from '../services/douyin-share';

const path = require('path');
const fs = require('fs');
const puppeteer = require('puppeteer');
const querystring = require('querystring');

const apiUrl = 'https://www.iesdouyin.com/web/api/v2/aweme/post';
const result = [] as Record<string, any>;
let index = 0; // 数组下标

// 获取_signature, dytk参数
const getRequestParam = (id: string) => {
  return new Promise(async resolve => {
    const browser = await puppeteer.launch({
      headless: false,
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });
    const page = await browser.newPage();
    await page.setRequestInterception(true);
    // 拦截请求获取请求参数
    page.on('request', (interceptedRequest: any) => {
      const requestUrl = interceptedRequest.url();
      if (requestUrl.indexOf(apiUrl) > -1) {
        const qs = querystring.parse(requestUrl.split('?')[1]);
        const {
          user_id,
          sec_uid,
          count,
          max_cursor,
          aid,
          _signature,
          dytk,
        } = qs;
        resolve({
          user_id,
          sec_uid,
          count,
          max_cursor,
          aid,
          _signature,
          dytk,
        });
      } else {
        interceptedRequest.continue();
      }
    });
    // 进入页面
    await page.goto(`https://www.iesdouyin.com/share/user/${id}`);
    const title = await page.$eval('.nickname', (el: any) => el.innerHTML);
    console.log(title);
    await page.waitFor(5000);
    browser.close();
    resolve();
  });
};

const loopList = async (param: IList): Promise<any> => {
  await sleep(500);
  const res = await getList(param);
  if (res.aweme_list && res.aweme_list.length) {
    const list = res.aweme_list;
    list[0].timestamp = res.min_cursor;
    if (list[1]) list[1].timestamp = res.max_cursor;
    result.push(...list);
    // 必须有retrun
    return loopList({ ...param, max_cursor: res.max_cursor });
  } else {
    return new Promise(resolve => {
      resolve(result);
    });
  }
};
// 递归执行保存方法 执行完成返回promise
export const doSaveVideoTask = async (arr: string[]): Promise<any> => {
  const param = (await getRequestParam(arr[index])) as IList;
  param.count = '20';
  param.max_cursor = `0`;
  const res = await loopList(param);
  const data = res.map((item: Record<string, any>) => {
    const video_src = `https://www.iesdouyin.com/share/video/${item.aweme_id}/?region=CN&mid=&u_code=&titleType=title&utm_source=copy_link&utm_campaign=client_share&utm_medium=android&app=aweme`;
    return {
      awemeId: item.aweme_id,
      awemeType: item.aweme_type,
      cover: item.video.cover && item.video.cover.url_list[0],
      desc: item.desc,
      duration: item.video.duration,
      dynamicCover:
        item.video.dynamic_cover && item.video.dynamic_cover.url_list[0],
      height: item.video.height,
      statistics: JSON.stringify(item.statistics),
      timestamp: item.timestamp,
      vid: item.video.vid,
      videoSrc: video_src,
      width: item.video.width,
    };
  });

  // 将作品信息写入文件
  let writerStream = fs.createWriteStream(
    path.join(__dirname, `../../douyin-data/douyin-${arr[index]}.json`)
  );
  writerStream.write(JSON.stringify(data, undefined, 2), 'UTF8');
  writerStream.end();
  try {
    await saveAuthorVideo(arr[index], data);
  } catch (e) {
    console.log(e);
  }
  if (index < arr.length - 1) {
    index++;
    return doSaveVideoTask(arr);
  } else {
    return new Promise(resolve => {
      resolve(`${arr.length}条数据已经保存完毕`);
      console.log('task is done');
    });
  }
};

#抖音
上次更新: 2021/12/19, 18:05:42
获取抖音用户作品列表信息
获取抖音用户作品列表信息-进阶3

← 获取抖音用户作品列表信息 获取抖音用户作品列表信息-进阶3→

最近更新
01
多分支修复撞车的问题
05-01
02
如何成为架构师
01-23
03
服务器部署全过程
11-23
更多文章>
Theme by Vdoing | Copyright © 2019-2026 fangdown | 粤ICP备19079809号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式