基于 Python 爬取 TikTok 搜索数据 Tiktok爬虫(2025.3.17)
1. 前言
在数据分析和网络爬虫的应用场景中,我们经常需要获取社交媒体平台的数据,例如 TikTok。本篇文章介绍如何使用 Python 爬取 TikTok 用户搜索数据,并解析其返回的数据。

结果截图
2. 项目环境准备
在正式运行代码之前,我们需要安装相关的 Python 库:
pip install requests pandas execjs loguru
此外,我们需要一个 JavaScript 运行环境(如 Node.js),用于执行加密签名代码。
3. 代码解析
3.1 初始化爬虫类
我们创建 TiktokUserSearch 类,并在初始化方法 __init__ 中设置请求头信息,并初始化输出文件。
class TiktokUserSearch:def __init__(self, output_file=None):self.headers = { # 设置请求头"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...","referer": "https://www.tiktok.com/"}self.cookies = Noneself.output_file = output_file if output_file else f'tiktok_videos_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv'
3.2 处理 Cookie
我们需要将 TikTok 的 cookie 从字符串转换成字典格式,以便后续请求使用。
def cookie_str_to_dict(self, cookie_str) -> dict:cookie_dict = {}cookies = [i.strip() for i in cookie_str.split('; ') if i.strip() != ""]for cookie in cookies:key, value = cookie.split('=', 1)cookie_dict[key] = valuereturn cookie_dict
3.3 发送请求
TikTok 需要使用 X-Bogus 进行签名,我们需要执行 JavaScript 代码来获取该参数。
为了防止网络不稳定,设置三次重试机制。
可根据自己需求设置代理。
def get(self, keyword, cursor, search_id, cookie_str):self.cookies = self.cookie_str_to_dict(cookie_str)url = "https://www.tiktok.com/api/search/general/full/"if cursor == "0":focus_state = "true"else:focus_state = "false"params = {"WebIdLastTime": f"{int(time.time())}","aid": "1988","app_language": "zh-Hans","app_name": "tiktok_web","browser_language": "zh-CN","browser_name": "Mozilla","browser_online": "true","browser_platform": "Win32","browser_version": self.headers['user-agent'].replace('Mozilla/', ''),"channel": "tiktok_web","cookie_enabled": "true","cursor": cursor,"device_id": "7339506347602019870","device_platform": "web_pc","focus_state": focus_state,"from_page": "search","history_len": "7","is_fullscreen": "false","is_page_visible": "true","keyword": keyword,"os": "windows","priority_region": "","referer": "","region": "KR","screen_height": "1080","screen_width": "1920","tz_name": "Asia/Shanghai","web_search_code": "{\"tiktok\":{\"client_params_x\":{\"search_engine\":{\"ies_mt_user_live_video_card_use_libra\":1,\"mt_search_general_user_live_card\":1}},\"search_server\":{}}}","webcast_language": "zh-Hans","msToken": self.cookies["msToken"],}if cursor != "0":params.update({"search_id": search_id})x_b = execjs.compile(open('./encrypt.js', encoding='utf-8').read()).call("sign", urlencode(params), self.headers["user-agent"])params.update({"X-Bogus": x_b})headers = self.headers.copy()headers.update({"referer": "https://www.tiktok.com/search?q=" + keyword})max_retries = 3for attempt in range(max_retries):try:response = requests.get(url,headers=headers,cookies=self.cookies,params=params,timeout=(3, 10),proxies=None)return response.json()except (ex1, ex2, ex3) as e:print(f"尝试 {attempt + 1}/{max_retries} 发生网络错误:{e}")if attempt < max_retries - 1:time.sleep(2)else:return {"error": f"Network error after {max_retries} attempts: {str(e)}"}except Exception as e:print(f"发生其他错误:{e}")return {"error": str(e)}
3.4 解析数据并存储
解析 TikTok 返回的视频数据,并保存到 CSV 文件。
def parse_data(self, data_list):resultList = []video_data = []for u in data_list:try:item = u['item']author = item['author']stats = item['stats']author_stats = item['authorStats'] # 添加作者统计信息# 提取需要的数据video_info = {'video_id': item['id'],'desc': item['desc'],'create_time': datetime.fromtimestamp(item['createTime']).strftime('%Y-%m-%d %H:%M:%S'),'duration': item['video']['duration'],# 作者基本信息'author_id': author['id'],'author_name': author['uniqueId'],'author_nickname': author['nickname'],'author_signature': author['signature'],'author_verified': author['verified'],# 作者统计信息'author_following_count': author_stats['followingCount'], # 关注数'author_follower_count': author_stats['followerCount'], # 粉丝数'author_heart_count': author_stats['heartCount'], # 获赞总数'author_video_count': author_stats['videoCount'], # 视频总数'author_digg_count': author_stats['diggCount'], # 点赞数# 视频统计信息'digg_count': stats['diggCount'],'share_count': stats['shareCount'],'comment_count': stats['commentCount'],'play_count': stats['playCount'],'collect_count': stats.get('collectCount', 0),'video_url': item['video']['playAddr']}# 添加标签信息if 'challenges' in item:video_info['hashtags'] = ','.join([tag['title'] for tag in item['challenges']])else:video_info['hashtags'] = ''# 添加音乐信息if 'music' in item:music = item['music']video_info.update({'music_id': music['id'],'music_title': music['title'],'music_author': music['authorName'],'music_original': music['original']})video_data.append(video_info)resultList.append(f"https://www.tiktok.com/@{author['uniqueId']}")except Exception as e:logger.error(f"解析视频数据时出错: {str(e)}")continue# 将数据保存到CSV文件try:df = pd.DataFrame(video_data)# 检查文件是否存在file_exists = os.path.exists(self.output_file)# 如果文件不存在,创建新文件并写入表头# 如果文件存在,追加数据不写入表头df.to_csv(self.output_file, mode='a', header=not file_exists,index=False, encoding='utf-8-sig')logger.info(f"数据已{'追加' if file_exists else '保存'}到文件: {self.output_file}")except Exception as e:logger.error(f"保存CSV文件时出错: {str(e)}")return resultList
3.5 运行爬虫
我们定义 main 方法,负责调用 get 方法获取数据并解析。
def main(self, keyword, cookie_str, cursor="0", search_id=None):dataJson = self.get(keyword, cursor, search_id, cookie_str)if dataJson:if "error" in dataJson:return {"cursor": cursor, "search_id": search_id, "data": [], "status": "-2", "error": dataJson["error"]}elif "verify_event" in str(dataJson):return {"cursor": cursor, "search_id": search_id, "data": [], "status": "-1"}else:# 解析数据并保存到CSVif 'data' in dataJson:self.parse_data(dataJson['data'])return dataJson
3.6 运行入口
最后,我们编写 if __name__ == '__main__' 逻辑,定义要爬取的关键词,并进行循环爬取。
if __name__ == '__main__':os.makedirs('results1', exist_ok=True)topics = ["Chen Duxiu","Li Dazhao",
]for keyword in topics:logger.info(f"开始爬取 {keyword} 的视频")output_file = f'results1/{keyword}_videos.csv' # 你可以自定义文件名tiktok = TiktokUserSearch(output_file=output_file)cookie_str = '_ttp=2ZzUB37CLclhWsrgyW56Erox1XM; tiktok_webapp_theme_auto_dark_ab=1; delay_guest_mode_vid=5; passport_csrf_token=d8e4d28ec7abdf12a7829d524dca64de; passport_csrf_token_default=d8e4d28ec7abdf12a7829d524dca64de; tt_chain_token=SSmpjX/0in/IP8BYwawD+Q==; multi_sids=7361707798058615814%3A53b730c284c4eaaa9bb2157eef01d70d; cmpl_token=AgQQAPNoF-RO0rYU5JqLsx0__dmghl8Nv5IhYNkWMA; passport_auth_status=a8a7a1e1c4b96a994a45acb38dc83509%2C; passport_auth_status_ss=a8a7a1e1c4b96a994a45acb38dc83509%2C; uid_tt=7857882a3366539dc1d9ca226b3fdc91f76b1b072c7da11dd4120368d88bf861; uid_tt_ss=7857882a3366539dc1d9ca226b3fdc91f76b1b072c7da11dd4120368d88bf861; sid_tt=53b730c284c4eaaa9bb2157eef01d70d; sessionid=53b730c284c4eaaa9bb2157eef01d70d; sessionid_ss=53b730c284c4eaaa9bb2157eef01d70d; store-idc=maliva; store-country-code=ca; store-country-code-src=uid; tt-target-idc=useast1a; tt-target-idc-sign=t3pz21FprSb2qc1ucJWFQbxzCKwgoBX9PKUWEbPHh7_4mpPThOuO0EN9pm2ORzFqk0bLFt6MtI9-gofvcVtQFoGSTOI_JvUWIAAUSHz1mM1A9jP1kRk_qucQnxEMOLvir3s4ffm0hJSh62RyKNO5LBTlT-fsqbi2tQVUwrgIGF-2HFT04S52ciyRnKAXr_0NyD3Aa0lM4J4hUGplo46wKRfId1DwwajXudUfjqJ3rvAuA8qURTsSHCKuDjLbcdfhcC0WKqemrmHFBJ11hGFJxiL4VEOClIoJGrF1_S9jvlx0H0Nph9BHlHNA-wzwi3NF6hPK17WL3TSvsqfEiKclZ5ScpHMv7ATYfOK4BVOzKXrq6fCxzNBT5kCNc4-ImuvjBNqpY8yL2s2KusWxslveOyIq3gwU3Dhxl084w5Tsp13xzuFOGNVHK5ZPeS5ERmykYFB6uTIHty9W_Z6pwN1tT9yQ-34qyZRZB7WONZn_NAFsywU6Hj4wcHLQkJ-tIiAO; last_login_method=google; tiktok_webapp_theme_source=auto; tiktok_webapp_theme=dark; sid_guard=53b730c284c4eaaa9bb2157eef01d70d%7C1740207607%7C15551996%7CThu%2C+21-Aug-2025+07%3A00%3A03+GMT; sid_ucp_v1=1.0.0-KDc2NDMxMTQzMTkwNTY2NTJiOWZhMmZhM2ZlMDg3ZDE0YzNiOGU5NTUKGQiGiIec0MeClWYQ9-vlvQYYsws4CEASSAQQAxoGbWFsaXZhIiA1M2I3MzBjMjg0YzRlYWFhOWJiMjE1N2VlZjAxZDcwZA; ssid_ucp_v1=1.0.0-KDc2NDMxMTQzMTkwNTY2NTJiOWZhMmZhM2ZlMDg3ZDE0YzNiOGU5NTUKGQiGiIec0MeClWYQ9-vlvQYYsws4CEASSAQQAxoGbWFsaXZhIiA1M2I3MzBjMjg0YzRlYWFhOWJiMjE1N2VlZjAxZDcwZA; odin_tt=a7027d0b8a102be6dd20600ca35291f4aee8c003895d8913d5c2f8276f16d6b974345357a22ed0bdcb57930d326afded3e5bd3105e061197876c80a92bbdbbfc29402634b8e7439ba178a1c7ed9ca552; tt_csrf_token=qs6ncqIZ-SbUZVzUbkUZ2SViJyY7VzYRki0M; perf_feed_cache={%22expireTimestamp%22:1742302800000%2C%22itemIds%22:[%227481325874978000134%22%2C%227463463290065161505%22%2C%227466633420098112799%22]}; msToken=BnkIjkPpJEc1i9jiiwT_paC5FW-NL62UVF7-lzpHYki9WIA_KpLrplpY-qlZfuG7V12rbCDHiyQYNrZcOnTzZLk1cvnH3_E_89nfOpqpVquKbSR-Nqr6bGDmL220vjBHdutm4R-gfVnYIG7fvWOJUkZ7yg==; ttwid=1%7Cv5j4n07c_G3ZtA91KIuree-ptnDLwgTwFuM8BnZINnQ%7C1742131441%7Ce88a85fcc36fd7e79815fddb10d16ef553b5e2e4a51c65e2c40098ade19023e2; msToken=iYDKRqCM8rSqc_9ZDzQnWcQiv_iJqPk15-6Y-iFBUmk4uIzb61dM13b9fWHcg4hxGkl9L3n56glok05TllvGurkwpgBYEF8N76ZRIii7OvNEkrk004dagNuoqQVeV9Bzd0_9naXjFXtEiMRi330G5Jdakw==; passport_fe_beating_status=false'has_more = 1cursor = '0'search_id = Nonewhile has_more:data = tiktok.main(keyword, cookie_str, cursor, search_id)logger.info(data)if data and isinstance(data, dict):has_more = data.get('has_more', 0)logger.info(has_more)cursor = data.get('cursor', '0')search_id = data.get('log_pb', {}).get('impr_id')if 'data' in data:data = data['data']else:logger.error("No data found in response")breakelse:logger.error("Invalid response format")breaktime.sleep(1) # 添加延时避免请求过快logger.info(f"爬取 {keyword} 的视频完成")time.sleep(30)logger.info(f"等待30秒后继续爬取下一个主题")logger.info("所有主题的视频爬取完成")
4. 关键问题与解决方案
-
TikTok 反爬措施:
- 需要定期更新 Cookie
- 适当增加请求间隔
- 使用代理提高稳定性
-
X-Bogus参数:- 需要使用 JavaScript 计算签名
- 依赖
encrypt.js进行加密
-
数据存储:
- 使用
pandas处理数据 - 追加模式写入 CSV,避免数据丢失
- 使用
6. 总结
本文介绍了如何使用 Python 爬取 TikTok 用户搜索数据,包括如何构造请求、解析数据并存储到 CSV 文件。希望对有类似需求的读者有所帮助!
帮助与咨询:私信博主或在评论区留言
相关文章:
基于 Python 爬取 TikTok 搜索数据 Tiktok爬虫(2025.3.17)
1. 前言 在数据分析和网络爬虫的应用场景中,我们经常需要获取社交媒体平台的数据,例如 TikTok。本篇文章介绍如何使用 Python 爬取 TikTok 用户搜索数据,并解析其返回的数据。 结果截图 2. 项目环境准备 在正式运行代码之前,我…...
【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解
【HarmonyOS Next】鸿蒙中App、HAP、HAR、HSP概念详解 (图1-1) 一、鸿蒙中App、HAP、HAR、HSP是什么? (1)App Pack(Application Package) 是应用发布的形态,上架应用市场是以App Pa…...
计算机二级MS之Excel
声明:跟着大猫和小黑学习随便记下一些笔记供大家参考,二级考试之前将持续更新,希望大家二级都能轻轻松松过啦,过了二级的大神也可以在评论区留言给点建议,感谢大家!! 文章目录 考题难点&#x…...
Unity导出WebGL,无法加载,data文件无法找到 404(NotFound)
问题:data文件无法找到404Not found 示例是使用IIS托管启动 F12可以看到not found 的报错 解决办法: iis无法识别data文件,在MIME类型中增加data 类型:application/octet-stream 添加之后,会在根目录下生产一个…...
洛谷题目: P1225 黑白棋游戏 题解 (本题难)
题目传送门: P1225 黑白棋游戏 - 洛谷 (luogu.com.cn) 前言: 这道题要求我们找出从黑白棋游戏的初始棋盘状态变化到目标棋盘状态的最短着棋序列,也就是要找到最少的交换相邻方格棋子的步数以及每一步具体的交换位置。我们可以使用广度优先…...
网络安全技术分析:攻防演进、核心技术与未来挑战
本文系统梳理网络安全技术发展脉络,聚焦漏洞利用、威胁检测、数据保护三大核心领域,结合APT攻击、勒索软件、零日漏洞等典型案例,解析防火墙、IDS、零信任架构等技术原理。通过分析2023年全球重大安全事件(如MOVEit漏洞攻击、Lock…...
SpringBoot与Redisson整合,用注解方式解决分布式锁的使用问题
文章引用:https://mp.weixin.qq.com/s/XgdKE2rBKL0-nFk2NJPuyg 一、单个服务 1.代码 该接口的作用是累加一个值,访问一次该值加1 RestController public class LockController {Autowiredprivate StringRedisTemplate stringRedisTemplate;GetMappin…...
通过Typora + PicGo + 阿里云对象存储(OSS)实现图床
文章目录 通过Typora PicGo 阿里云对象存储(OSS)实现图床1 准备工作1.1 阿里云对象存储 OSS配置创建oss存储空间bucket获取AccessKey 1.2 PicGo配置1.3 Typora配置 2 使用流程3 常见问题和解决3.1 创建asesskey3.2 You have no right to access this o…...
爱普生FC-12M石英晶体谐振器精准时钟源解决方案
在当今数字化时代,电子设备无处不在,从我们日常使用的智能手机、平板电脑,到复杂的工业控制系统、通信基站,每一台设备的稳定运行都离不开精准的时钟信号。而在众多提供时钟信号的元件中,爱普生 FC-12M 石英晶体谐振器…...
【css酷炫效果】纯CSS实现手风琴折叠效果
【css酷炫效果】纯CSS实现手风琴折叠效果 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492015 缘 创作随缘,不定时更新。 创作背景 刚看到csdn出活动了&am…...
AI辅助的逆向分析
AI大模型结合反编译工具与AI的辅助分析能力,已能实现部分代码逻辑的还原与重构。 1. 技术实现路径 (1)二进制文件预处理与反编译 反编译工具:需先使用IDA Pro、Ghidra等工具将二进制文件转换为低级中间表示(如汇编代…...
物理标签与逻辑标签的区别
物理标签和逻辑标签都可以被机器(如浏览器、爬虫、屏幕阅读器)解析和识别,但它们的 语义信息 对机器的意义不同。以下是详细解释: 1. 物理标签的解析 可以识别:浏览器会正确解析物理标签(如 <b>、<…...
脚本语言 Lua
概念 Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译、运行。Lua脚本可以很容易地被C/C 代码调用,也可以反过来调用C/C的函数,这使得Lua在应用程序中可以被广泛应用。Lua并没有提供强大的库,它是不适合作为开发独立应…...
《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》
一、系统概述 本系统是一个基于 TCP 协议的多人聊天系统,由一个服务器和多个客户端组成。客户端可以连接到服务器,向服务器发送消息,服务器接收到消息后将其转发给其他客户端,实现多人之间的实时聊天。系统使用 C 语言编写&#x…...
目前主要虚拟世界平台在单一实例承载人数和伺服器架构的综合比较分析(从开资料和技术推估):
目前主要虚拟世界平台在单一实例承载人数和伺服器架构的综合比较分析(从开资料和技术推估): 1. 《Fortnite》(Epic Games) 一般游戏模式约 100人/场,但大型活动(如演唱会)采用分层串…...
鸿蒙NEXT项目实战-百得知识库04
代码仓地址,大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…...
函数的介绍
1.函数的概念 在C语言中也有函数的概念,有些翻译为:子程序,这种翻译更为准确。C语言的函数就是一个完成某项特定的任务的一小段代码。这段代码是有特殊的写法和调用方法的。 C语言的程序其实是有无数个小的函数组合而成的,也可以…...
源自Deformable Convolutional Networks的一种可变形卷积实现解析
衍生记录:深度学习pytorch之简单方法自定义9类卷积即插即用 文章目录 概述1. 可变形卷积的背景2. DeformConv2D概述2.1 构造函数分析2.2 前向传播函数解析2.2.1 偏移量的计算与应用2.2.2 目标位置的计算2.2.3 四个角的插值2.2.4 双线性插值的权重2.2.5 特征图的采样…...
记一次性能调优-20250320
2月份年后上班,刚过完年,还没从喜悦中解放出来,凌晨3点的时候同事就给我打电话,晚上的批量处理任务卡住了,快帮忙看看,做了几分钟的心里建设之后从被窝爬起来,看着手机上好几电话,赶…...
Postman高级功能深度解析:Mock Server与自动化监控——构建高效API测试与监控体系
引言:Postman在API开发中的核心价值 在数字化时代,API(应用程序编程接口)已成为系统间交互的“神经网络”,其质量直接影响用户体验与业务连续性。然而,传统API测试面临两大挑战: 开发阶段依赖…...
【最后203篇系列】020 rocksdb agent
今天还是挺开心的一天,又在工具箱里加了一个工具。嗯,但是快下班的时候也碰到一些不太顺心的事,让我有点恼火。我还真没想到一个专职的前端,加测试,以及其他一堆人,竟然不知道后端返回的markdown,在前端渲染…...
OpenCV旋转估计(2)用于自动检测波浪校正类型的函数autoDetectWaveCorrectKind()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::detail::autoDetectWaveCorrectKind 是 OpenCV 中用于自动检测波浪校正类型的函数,它根据输入的旋转矩阵集合来决定使用哪种波浪…...
mysql-connector-python 报错(0xC0000005)
报错情况: 原因: mysql-connector-python版本不对,我们的mysql版本为sql8.0需要下载mysql-connector-python8.0....的库 方法: pip install mysql-connector-python8.1.0 即可...
从零开始实现Stable Diffusion本地部署
1. 依赖安装 文件打包下载地址(Stable Diffusion) # git : 用于下载源码 https://git-scm.com/downloads/win # Python 作为基础编译环境 https://www.python.org/downloads/ # Nvidia 驱动,用于编译使用GPU显卡硬件 https://ww…...
RAG各类方法python源码解读与实践:利用Jupyter对RAG技术综合评测【3万字长文】
检索增强生成(RAG )是一种结合信息检索与生成模型的混合方法。它通过引入外部知识来提升语言模型的性能,从而提高回答的准确性和事实正确性。为了简单易学,不使用LangChain框架或FAISS向量数据库,而是利用Jupyter Note…...
transform C++标准库算法用法(对容器中元素进行转换操作:大小写转换、向量的加法乘法运算)
std::transform 是 C 标准库中的一个算法,用于对容器(如数组、向量、字符串等)中的元素进行转换操作,并将结果存储到指定的目标位置。它可以对单个范围或两个范围的元素进行操作,并将结果写入另一个容器。 1. 头文件 …...
Java File 类与文件操作
一、引言 在 Java 编程中,文件操作是一项非常常见且重要的任务。无论是读取配置文件、保存用户数据,还是进行日志记录,都离不开对文件的操作。Java 提供了 File 类来表示文件和目录的抽象路径名,通过该类可以对文件和目录进行创建、删除、重命名等操作。同时,Java 还提供…...
Python 字符串的编码格式
在 Python 中,字符串(str)默认使用 Unicode 编码,具体来说,Python 3 中的字符串是以 UTF-8 编码存储的 Unicode 字符序列。Unicode 是一种国际标准,旨在为世界上所有的字符提供唯一的编码,而 UTF-8 是 Unicode 的一种实现方式,具有兼容性和高效性。 1. Unicode 与 UTF-…...
RPA+AI 技术到底好在哪里?
在自动化领域,RPA与生成式AI都是强大的技术,都可以用来实现自动执行重复耗时的任务。 主要区别是:传统RPA擅长处理结构化与规则明确简单的流程,而在非结构化数据处理、动态上下文适应、智能决策等能力上有欠缺;而基于…...
flowable适配达梦7 (2.1)
经过第一版的问题解决,后端项目可以启动,前端页面也集成进去。 前端在流程设计页面报错 之后发现主要是组件中modelerStore这个值没有 解决方法:在data增加对象 给component/process/designer.vue 中涉及到的每个子组件传入 :modelerStore“modeler…...
