短视频平台关键词搜索爬虫设计与实现指南

一、技术方案概述

短视频平台作为国内主流的短视频内容社区,其搜索接口蕴含大量有价值的数据。本方案采用浏览器自动化控制与网络请求拦截相结合的技术路线,通过模拟用户操作触发搜索请求,精准捕获目标API返回的JSON数据。相较于传统爬虫框架,该方案具有三大优势:无需处理复杂的反爬机制、可获取动态渲染的完整数据、支持JavaScript执行环境。

二、开发环境准备

1. 核心依赖库

  1. import time
  2. import json
  3. import threading
  4. from typing import List, Dict, Optional
  5. from datetime import datetime
  6. from urllib.parse import quote
  7. from openpyxl import Workbook
  8. from DrissionPage import ChromiumPage
  9. from DrissionPage.common import Actions
  • ChromiumPage:基于Selenium与Requests的混合驱动浏览器自动化库
  • openpyxl:Excel数据存储格式支持
  • threading:多线程任务管理
  • typing:类型注解增强代码可维护性

2. 浏览器配置方案

  1. class VideoPlatformCrawler:
  2. def __init__(self):
  3. self.browser = None
  4. self.stop_event = threading.Event()
  5. def init_browser(self):
  6. """多模式浏览器初始化策略"""
  7. try:
  8. # 基础模式初始化
  9. self.browser = ChromiumPage()
  10. self._test_browser("基础模式")
  11. return True
  12. except Exception as e:
  13. print(f"基础模式失败: {str(e)}")
  14. try:
  15. # 自定义配置模式
  16. from DrissionPage import ChromiumOptions
  17. co = ChromiumOptions()
  18. co.set_arguments([
  19. '--no-sandbox',
  20. '--disable-dev-shm-usage',
  21. '--disable-gpu',
  22. '--remote-debugging-port=9222'
  23. ])
  24. self.browser = ChromiumPage(addr_or_opts=co)
  25. self._test_browser("自定义配置模式")
  26. return True
  27. except Exception as e:
  28. print(f"自定义配置失败: {str(e)}")
  29. try:
  30. # 远程调试模式
  31. self.browser = ChromiumPage(addr_or_opts='127.0.0.1:9222')
  32. self._test_browser("远程调试模式")
  33. return True
  34. except Exception as e:
  35. print(f"远程调试失败: {str(e)}")
  36. return False
  37. def _test_browser(self, mode: str):
  38. """浏览器可用性测试"""
  39. self.browser.get("https://www.baidu.com")
  40. time.sleep(2)
  41. print(f"{mode}初始化成功")

该实现采用三级容错机制,依次尝试三种初始化方式,确保在各种环境下都能建立有效的浏览器会话。

三、核心数据捕获技术

1. 接口定位方法论

通过浏览器开发者工具的Network面板,重点监控以下特征请求:

  • 请求方法:POST
  • Content-Type:application/json
  • 请求参数包含:keywordsearch_id等字段
  • 响应数据包含:video_listaweme_list等关键字段

2. 动态参数处理

  1. def generate_search_params(self, keyword: str) -> Dict:
  2. """生成带加密参数的请求体"""
  3. base_params = {
  4. "keyword": keyword,
  5. "cursor": 0,
  6. "count": 20,
  7. "type": 1,
  8. "is_pull_refresh": True
  9. }
  10. # 实际项目中需补充动态参数生成逻辑
  11. # 通常需要分析前端JS代码获取加密算法
  12. return base_params

对于包含动态签名的参数,建议通过以下方式处理:

  1. 使用PyExecJS执行前端加密脚本
  2. 通过中间人攻击获取加密参数生成规则
  3. 参考开源社区已破解的加密方案

四、完整实现流程

1. 主控制流程

  1. def run(self, keywords: List[str]):
  2. """主控制流程"""
  3. if not self.init_browser():
  4. raise RuntimeError("浏览器初始化失败")
  5. try:
  6. self._login_if_needed() # 可选登录流程
  7. results = []
  8. for keyword in keywords:
  9. print(f"开始采集: {keyword}")
  10. data = self._fetch_search_result(keyword)
  11. results.extend(data)
  12. time.sleep(3) # 礼貌性延迟
  13. self._save_to_excel(results)
  14. print("数据采集完成")
  15. finally:
  16. self.browser.quit()

2. 数据采集实现

  1. def _fetch_search_result(self, keyword: str) -> List[Dict]:
  2. """执行单关键词采集"""
  3. search_url = "https://www.example.com/api/search" # 需替换为实际接口
  4. params = self.generate_search_params(keyword)
  5. # 方法1:直接请求API(推荐)
  6. try:
  7. response = self.browser.session.post(
  8. search_url,
  9. json=params,
  10. headers={
  11. 'User-Agent': 'Mozilla/5.0',
  12. 'Referer': 'https://www.example.com'
  13. }
  14. )
  15. return response.json().get('data', {}).get('aweme_list', [])
  16. except Exception as e:
  17. print(f"API请求失败: {str(e)}")
  18. # 方法2:通过浏览器交互触发(备用方案)
  19. try:
  20. self.browser.get("https://www.example.com")
  21. self.browser.ele('css selector', '.search-input').input(keyword)
  22. self.browser.ele('css selector', '.search-btn').click()
  23. time.sleep(5) # 等待结果加载
  24. # 通过页面元素提取数据(需根据实际HTML结构调整)
  25. items = self.browser.eles('css selector', '.video-item')
  26. return [self._parse_item(item) for item in items]
  27. except Exception as e:
  28. print(f"页面交互失败: {str(e)}")
  29. return []

五、数据存储方案

1. Excel存储实现

  1. def _save_to_excel(self, data: List[Dict]):
  2. """数据存储到Excel"""
  3. wb = Workbook()
  4. ws = wb.active
  5. ws.append(['视频ID', '标题', '播放量', '点赞数', '发布时间'])
  6. for item in data:
  7. ws.append([
  8. item.get('aweme_id', ''),
  9. item.get('desc', ''),
  10. item.get('statistics', {}).get('play', 0),
  11. item.get('statistics', {}).get('digg', 0),
  12. self._format_time(item.get('create_time', 0))
  13. ])
  14. timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
  15. filename = f"search_result_{timestamp}.xlsx"
  16. wb.save(filename)
  17. print(f"数据已保存至: {filename}")

2. 扩展存储方案

对于大规模数据采集,建议考虑:

  1. 对象存储:将原始JSON数据存储至云存储服务
  2. 时序数据库:对播放量等时序数据进行专门存储
  3. 消息队列:构建分布式采集系统时使用

六、反爬策略应对

  1. IP轮换:使用代理IP池
  2. User-Agent随机化:维护常用UA列表
  3. 请求间隔控制:采用指数退避算法
  4. 验证码处理:集成第三方打码平台
  5. Session维持:保持长期有效的浏览器会话

七、性能优化建议

  1. 多线程采集:对非关联关键词并行处理
  2. 增量采集:记录已采集关键词避免重复
  3. 数据压缩:对存储数据进行gzip压缩
  4. 错误重试:实现自动化的错误恢复机制

八、法律合规提示

  1. 严格遵守目标平台的robots协议
  2. 控制采集频率避免对服务器造成压力
  3. 仅采集公开可访问的数据
  4. 妥善保管采集到的用户数据

本方案通过模块化设计实现了高可扩展性,开发者可根据实际需求调整各模块实现。对于企业级应用,建议在此基础上增加监控告警、任务调度等配套系统,构建完整的爬虫管理平台。