抖音分享url 获取,和签名算法分析见: https://www.yuque.com/dakuohao/initit/dqbv72

页面分析

  • 抖音的签名算法经常变,不适合使用api去爬取数据
  • 既然是js版的网页,可以使用google的无头浏览器headless bower技术,渲染页面,自动拿到数据,等于是模拟了一个浏览器的全部行为。
  • 该方式不好做反爬虫处理

    爬取过程

  1. 启动浏览器打开网址 https://www.iesdouyin.com/share/user/97241835037
  2. 渲染页面,然后请求用户信息数据,请求用户视频数据,请求用户喜欢的视频数据
  3. 这里选用户的视频数据接口,做个例子
  4. ajax请求https://www.iesdouyin.com/web/api/v2/aweme/post这个接口,得到的是json数据

image.png

响应数据分析

  1. {
  2. "status_code": 0, //状态码 0表示请求正常
  3. "aweme_list": [//视频列表
  4. {
  5. "aweme_id": "6708340636640218379", //视频id
  6. "desc": "一定要看到最后系列 #弹指变身术 #变身", //描述
  7. "cha_list": null,
  8. "video": {
  9. "play_addr": {//视频播放地址
  10. "uri": "v0200fe00000bkct20j6j2qrpmnl55tg",
  11. "url_list": [
  12. "https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200fe00000bkct20j6j2qrpmnl55tg&line=0&ratio=540p&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1",
  13. "https://api.amemv.com/aweme/v1/play/?video_id=v0200fe00000bkct20j6j2qrpmnl55tg&line=1&ratio=540p&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1"
  14. ]
  15. },
  16. "cover": {//动态图地址
  17. "uri": "2943900017ae4444916c5",
  18. "url_list": [
  19. "https://p9-dy.byteimg.com/aweme/300x400/2943900017ae4444916c5.jpeg",
  20. "https://p1-dy.byteimg.com/aweme/300x400/2943900017ae4444916c5.jpeg",
  21. "https://p3-dy.byteimg.com/aweme/300x400/2943900017ae4444916c5.jpeg"
  22. ]
  23. },
  24. "height": 1280,
  25. "width": 720,
  26. "dynamic_cover": {//1280*720动态图
  27. "uri": "2935e0004a520262ef032",
  28. "url_list": [
  29. "https://p9-dy.byteimg.com/obj/2935e0004a520262ef032",
  30. "https://p1-dy.byteimg.com/obj/2935e0004a520262ef032",
  31. "https://p3-dy.byteimg.com/obj/2935e0004a520262ef032"
  32. ]
  33. },
  34. "origin_cover": {//封面图 大图
  35. "uri": "large/29299000a5bd1adde07fb",
  36. "url_list": [
  37. "http://p9-dy.byteimg.com/large/29299000a5bd1adde07fb.jpeg",
  38. "http://p1-dy.byteimg.com/large/29299000a5bd1adde07fb.jpeg",
  39. "http://p3-dy.byteimg.com/large/29299000a5bd1adde07fb.jpeg"
  40. ]
  41. },
  42. "ratio": "540p",
  43. "download_addr": {//下载地址
  44. "uri": "v0200fe00000bkct20j6j2qrpmnl55tg",
  45. "url_list": [
  46. "https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200fe00000bkct20j6j2qrpmnl55tg&line=0&ratio=540p&watermark=1&media_type=4&vr_type=0&improve_bitrate=0&logo_name=aweme",
  47. "https://api.amemv.com/aweme/v1/play/?video_id=v0200fe00000bkct20j6j2qrpmnl55tg&line=1&ratio=540p&watermark=1&media_type=4&vr_type=0&improve_bitrate=0&logo_name=aweme"
  48. ]
  49. },
  50. "has_watermark": true,
  51. "bit_rate": null,
  52. "duration": 10700
  53. },
  54. "statistics": {
  55. "aweme_id": "6708340636640218379",
  56. "comment_count": 43,
  57. "digg_count": 1316,
  58. "play_count": 0,
  59. "share_count": 22,
  60. "forward_count": 0
  61. },
  62. "text_extra": [//参与的 活动或专题
  63. {
  64. "start": 10,
  65. "end": 16,
  66. "type": 1,
  67. "hashtag_name": "弹指变身术",
  68. "hashtag_id": 1636478480196621
  69. },
  70. {
  71. "start": 17,
  72. "end": 20,
  73. "type": 1,
  74. "hashtag_name": "变身",
  75. "hashtag_id": 1555318033810433
  76. }
  77. ],
  78. "video_labels": null,
  79. "aweme_type": 4,
  80. "image_infos": null,
  81. "position": null,
  82. "uniqid_position": null,
  83. "comment_list": null,
  84. "geofencing": null,
  85. "video_text": null,
  86. "label_top_text": null,
  87. "promotions": null,
  88. "long_video": null
  89. },
  90. //...多个对象
  91. ],
  92. "max_cursor": 1558603429000, //最大游标,默认是0,然后本次请求得到的值是下一次请求的值
  93. "min_cursor": 1561972997000, //暂时无用
  94. "has_more": true//true表示还有更多数据,继续请求下一页
  95. }

代码实现

1. 安装puppeteer

  1. --环境要求 nodejs 8版本以上
  2. npm init 项目名
  3. cd 项目名
  4. npm install --save puppeteer
  5. 安装过程会自动下载一个chrome浏览器到node_module目录,大概140M
  6. 网速慢的可以使用
  7. yarn add puppeteer
  8. 或者使用
  9. cnpm install -save puppeteer

无头浏览器 Puppeteer 教程和说明参考: https://www.yuque.com/dakuohao/initit/cvf5gl
就是可以用代码模拟浏览器的所有行为

2.爬取数据

  1. const puppeteer = require('puppeteer');
  2. // 站点地址url
  3. var url = `https://www.iesdouyin.com/share/user/97241835037`;
  4. class GetDouYin {
  5. constructor() {
  6. this.page = null;
  7. this.browser = null;
  8. }
  9. async init() {
  10. // 构造浏览器对象
  11. this.browser = await puppeteer.launch({
  12. 'headless': false,// 增加该参数会 显示浏览器 并显示所有操作
  13. });
  14. // this.browser = await puppeteer.launch();//不显示浏览器
  15. // 创建页面
  16. this.page = await this.browser.newPage();
  17. // 模拟浏览器信息
  18. const UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A365 Safari/600.1.4";
  19. this.page.setUserAgent(UA);
  20. // 允许执行js脚本
  21. this.page.setJavaScriptEnabled(true);
  22. // 页面视口大小
  23. this.page.setViewport({width: 400, height: 900});
  24. this.getVideo();
  25. //确保 滚屏加载数据
  26. for (let i =0;i<5;i++){
  27. this.scrollPage();
  28. }
  29. //关闭浏览器
  30. // await this.browser.close();
  31. }
  32. /* 页面滚动方法 */
  33. async scrollPage() {
  34. console.log('鼠标滚动,加载数据');
  35. //执行js代码(滚动页面)
  36. await this.page.evaluate(() => {
  37. window.scrollTo(100, document.body.offsetHeight)
  38. })
  39. };
  40. async getVideo() {
  41. // 打开页面
  42. await this.page.goto(url);
  43. let page = await this.page;
  44. //监听响应事件
  45. page.on('response', response => {
  46. // 查看所有请求地址
  47. // console.log(response.url());
  48. // 匹配所需数据的请求地址
  49. if (response.url().indexOf('https://www.iesdouyin.com/web/api/v2/aweme/post') !== -1) {
  50. // 获取数据并转为json格式
  51. let promise = response.json()
  52. .then(data => {
  53. //todo 打印输出数据,或者是保存入库
  54. console.log(JSON.stringify(data));
  55. if (data.has_more) {
  56. this.scrollPage();
  57. }
  58. })
  59. }
  60. });
  61. }
  62. }
  63. let getDouYin = new GetDouYin();
  64. getDouYin.init();