1. 项目概述与核心价值
最近在做一个关于社交媒体数据分析的项目,其中一个核心需求是持续、稳定地获取抖音账号的粉丝数据,比如粉丝数、粉丝画像(如性别、地域分布)的变动趋势。直接调用官方API?对于大多数普通开发者来说,这条路基本走不通,权限申请门槛高,数据维度也有限。用传统的网页爬虫去抓取移动端数据?你会发现抖音的网页端(m.douyin.com)和PC端展示的信息非常有限,很多关键数据,特别是动态更新的粉丝列表和详情,都只在手机App里完整呈现。
这就引出了一个经典的自动化测试工具——Appium。它能像真人一样操作手机App,点击、滑动、输入文字。理论上,我们可以写个脚本,让Appium自动打开抖音,进入个人主页,然后不断地滑动粉丝列表,把看到的数据“抄”下来。但这个方法效率太低了,想象一下,要采集一个百万粉账号的所有粉丝ID,得让手机模拟滑动多久?而且频繁的UI操作极其耗电、耗资源,App很容易因为异常弹窗或网络波动而卡死,稳定性堪忧。
于是,我引入了另一个神器:Mitmproxy。它是一个支持HTTP/HTTPS的中间人代理工具。简单说,就是让手机的所有网络请求都先经过你的电脑,这样你就能看到抖音App在背后偷偷和服务器交换了哪些数据。粉丝列表、用户详情这些数据,肯定是通过网络请求获取的,我们如果能抓到这些请求并解析出来,不就相当于拿到了数据源头吗?
所以,这个项目的核心思路就清晰了:“Appium负责自动化启动和登录抖音App,模拟必要的用户操作(如进入个人主页);Mitmproxy负责在后台监听并解密App发出的网络请求,从中精准提取出粉丝数据。”两者联动,Appium解决“身份认证”和“触发数据请求”的问题,Mitmproxy解决“高效、静默抓取数据包”的问题。最终实现的效果是,脚本运行后,你几乎看不到手机屏幕在疯狂滑动,但粉丝数据已经 quietly 地流入了你的数据库。这套方案特别适合需要长期、定时监控特定账号粉丝变化,或者进行小规模、多账号粉丝数据分析的场景。
2. 环境搭建与工具链配置
工欲善其事,必先利其器。这套方案的环境搭建稍微有点繁琐,但一步步来,完全可以搞定。核心是配置好Appium和Mitmproxy,并让它们能协同工作。
2.1 Appium环境搭建(以Android为例)
Appium是一个跨平台的移动端自动化测试框架。我们用它来操控手机。
第一步:基础环境安装
- 安装Node.js和npm:Appium服务器是基于Node.js的。去Node.js官网下载并安装LTS版本,安装后会自带npm包管理器。
- 安装Appium Server:打开命令行,通过npm全局安装Appium。
npm install -g appium。安装完成后,可以通过appium -v检查版本。为了更好的体验,我强烈建议再安装一个图形化客户端appium-doctor来检查环境:npm install -g appium-doctor,然后运行appium-doctor,它会告诉你还缺什么。 - 安装Appium Client库:这是用来写Python脚本连接Appium Server的。在你的项目虚拟环境中执行:
pip install Appium-Python-Client。
第二步:Android开发环境配置
- 安装Android SDK:推荐直接安装Android Studio,它会帮你管理SDK。安装后,打开SDK Manager,确保安装了以下内容:
- SDK Platforms:至少选择一个Android版本(如Android 13.0 “Tiramisu”的API Level 33)。
- SDK Tools:必须安装
Android SDK Build-Tools、Android SDK Platform-Tools(包含adb命令)、Android Emulator(如果你用模拟器)。
- 配置环境变量:将Android SDK的
platform-tools和tools目录路径添加到系统的PATH环境变量中。这样你才能在命令行里直接使用adb命令。 - 准备测试设备:可以是真机也可以是模拟器。
- 真机:用USB连接电脑,在手机上开启“开发者选项”和“USB调试”模式。连接后,在命令行输入
adb devices,应该能看到你的设备序列号。 - 模拟器:在Android Studio的AVD Manager中创建一个虚拟设备。启动后,同样用
adb devices确认连接。
- 真机:用USB连接电脑,在手机上开启“开发者选项”和“USB调试”模式。连接后,在命令行输入
注意:使用真机时,部分品牌手机可能需要额外安装驱动或进行授权确认。如果
adb devices显示设备为unauthorized,去手机上查看是否有“允许USB调试”的弹窗,点击允许。
第三步:Desired Capabilities配置这是Appium脚本的核心,它告诉Appium你要启动哪个App、在什么设备上启动。一个基础的配置示例如下(Python):
from appium import webdriver desired_caps = { 'platformName': 'Android', # 平台 'platformVersion': '13', # 安卓版本,根据你的设备填写 'deviceName': 'your_device_name', # 设备名,adb devices 查到的名称 'appPackage': 'com.ss.android.ugc.aweme', # 抖音的包名 'appActivity': '.splash.SplashActivity', # 抖音的启动Activity 'noReset': True, # 不重置App数据,避免每次重新登录 'automationName': 'UiAutomator2', # 自动化引擎,Android推荐这个 'newCommandTimeout': 600, # 命令超时时间设长一点 'udid': 'your_device_udid' # 设备唯一标识,防止多设备冲突 } driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)这里的关键是appPackage和appActivity。如何获取?有一个简单的方法:打开抖音App,停留在你想启动的页面(如首页),然后在命令行输入adb shell dumpsys window | findstr mCurrentFocus(Windows)或adb shell dumpsys window | grep mCurrentFocus(Mac/Linux),输出结果里就有当前的包名和Activity。
2.2 Mitmproxy环境搭建与证书配置
Mitmproxy是我们的“数据监听员”。
第一步:安装Mitmproxy直接用pip安装即可:pip install mitmproxy。这会同时安装mitmproxy(命令行交互式)、mitmdump(命令行非交互式,我们主要用这个)和mitmweb(Web图形界面)三个工具。
第二步:配置代理与安装证书这是最关键的步骤,目的是让手机信任Mitmproxy颁发的证书,从而解密HTTPS流量。
- 启动Mitmproxy:在电脑上启动mitmdump,监听默认端口8080:
mitmdump -s your_script.py。-s参数后面跟你的Python处理脚本,可以先不加。 - 配置手机代理:确保手机和电脑在同一个Wi-Fi网络下。在手机的Wi-Fi设置中,修改当前网络为手动代理,服务器地址填写你电脑的局域网IP(在命令行输入
ipconfig或ifconfig查看),端口填写8080。 - 安装CA证书:
- 在手机浏览器中访问
mitm.it。这是一个Mitmproxy提供的便捷安装页面。 - 根据你的手机系统(Android/iOS),点击对应的图标下载证书。
- 对于Android:下载后,进入系统设置 -> 安全 -> 加密与凭据 -> 安装证书 -> CA证书,找到下载的文件进行安装。安装时可能需要设置锁屏密码。
- 证书安装成功后,务必重启mitmdump,否则可能不生效。
- 在手机浏览器中访问
实操心得:Android 7.0以上系统,App默认不信任用户安装的CA证书,导致无法解密部分App(包括抖音)的HTTPS流量。解决方法有两种:一是将Mitmproxy的CA证书安装到系统信任的凭据存储区(这通常需要Root权限);二是对测试用的App进行重新打包,在其网络配置中信任用户证书。对于抖音,我们采用另一种更实用的方案:只抓取我们能解密的请求。幸运的是,抖音的部分API接口(尤其是数据接口)使用的证书校验策略可能不那么严格,或者我们只需要关注其HTTP请求的URL和参数规律,有时即使不解密内容,也能通过请求模式进行分析。但为了最大化成功率,建议使用已Root或可调试的系统镜像(如模拟器或开发测试机)。
第三步:验证代理是否生效在手机代理设置好、mitmdump运行、证书安装后,用手机浏览器访问一个普通HTTP网站(如http://example.com),观察mitmdump的命令行窗口,应该能看到滚动的请求日志。如果能抓到包,说明代理配置基本成功。
3. 联动策略设计与核心脚本解析
环境搭好了,现在来设计Appium和Mitmproxy如何“打配合”。核心思想是:Appium做“手”和“眼”,触发数据加载;Mitmproxy做“耳”,窃听数据通道。
3.1 分工与协作流程
- 启动阶段:首先启动Mitmproxy(
mitmdump),并加载我们编写的Python解析脚本。然后启动Appium Server,最后运行我们的主控Python脚本,该脚本通过Appium Client连接Server并启动抖音。 - 登录与导航:主控脚本利用Appium驱动抖音完成登录(如果未登录),并导航到目标账号的个人主页。这部分完全模拟真人操作:可能通过搜索用户名,或者直接访问个人主页链接。
- 触发数据请求:进入粉丝列表页面。这里Appium只需要执行一个关键动作:点击“粉丝”Tab。一旦点击,抖音App就会向服务器发起请求,获取粉丝列表数据。
- 监听与抓取:当粉丝列表的请求发出时,经过手机代理的设置,请求会流经我们电脑上的Mitmproxy。我们在Mitmproxy的脚本中,预先写好了规则,专门筛选URL中包含特定关键词(如
/aweme/v1/user/follower/list/)的请求。 - 解析与存储:Mitmproxy脚本捕获到目标请求后,直接解析其响应内容(通常是JSON格式),提取出粉丝ID、昵称等信息,然后存入本地文件或数据库。在这个过程中,Appium不需要再去滑动列表加载更多!因为Mitmproxy抓取的是接口返回的原始数据包,一个请求可能就包含了20个、50个甚至100个粉丝数据。我们只需要分析接口的分页参数(如
max_time,cursor),然后在Mitmproxy脚本里,模拟构造后续分页请求,或者简单地控制Appium触发几次“上拉加载更多”即可。 - 循环与结束:重复步骤3-5,直到抓取到足够的数据或翻页结束。最后,主控脚本关闭Appium驱动,Mitmproxy也停止工作。
3.2 Appium脚本核心:触发与容错
Appium脚本的任务相对单纯,主要是“导航到粉丝列表页面”。但实际写起来,需要考虑各种弹窗和状态判断。
from appium.webdriver.common.touch_action import TouchAction import time def navigate_to_follower_list(driver, target_username): """ 导航到指定用户的粉丝列表页 """ # 1. 处理可能的启动页、青少年模式弹窗等 time.sleep(3) # 这里可以加入一些通用的弹窗关闭逻辑,例如通过ID或XPath查找“我知道了”、“跳过”按钮并点击 # driver.find_element(AppiumBy.ID, 'com.ss.android.ugc.aweme:id/close_btn').click() # 2. 搜索目标用户(假设从首页开始) search_btn = driver.find_element(AppiumBy.ACCESSIBILITY_ID, '搜索按钮') # 可能需要用XPath search_btn.click() time.sleep(2) search_box = driver.find_element(AppiumBy.ID, 'com.ss.android.ugc.aweme:id/search_input') search_box.send_keys(target_username) driver.press_keycode(66) # 模拟键盘回车键 time.sleep(3) # 3. 进入用户主页 # 假设第一个搜索结果就是目标用户 first_result = driver.find_element(AppiumBy.XPATH, '//android.widget.ListView/android.widget.RelativeLayout[1]') first_result.click() time.sleep(4) # 等待主页加载 # 4. 点击“粉丝”Tab # 粉丝Tab的定位可能比较麻烦,需要借助UI Automator Viewer或Appium Inspector来查看具体控件信息 # 这里是一个示例XPath,实际情况可能需要调整 follower_tab = driver.find_element(AppiumBy.XPATH, '//*[@text="粉丝"]') follower_tab.click() time.sleep(5) # 等待粉丝列表加载,这个时间很关键,确保网络请求发出 print("已成功进入粉丝列表页面,Mitmproxy可以开始抓包。") # 5. (可选)触发多次加载。简单做法:缓慢滑动几次,模拟人工浏览。 # 获取屏幕尺寸 size = driver.get_window_size() start_x = size['width'] / 2 start_y = size['height'] * 0.7 end_y = size['height'] * 0.3 for i in range(5): # 计划滑动5次,加载更多数据 driver.swipe(start_x, start_y, start_x, end_y, duration=800) time.sleep(3) # 每次滑动后等待数据加载 print(f"已触发第{i+1}次滑动加载。")注意事项:UI自动化最大的敌人是界面变化和网络延迟。上述代码中的
time.sleep是简单的等待,在实际项目中应替换为更可靠的“显式等待”(WebDriverWait),等待特定元素出现后再操作,这样脚本更健壮。此外,所有控件的定位符(ID、XPath)都可能随抖音版本更新而改变,需要定期维护。
3.3 Mitmproxy脚本核心:过滤、解析与存储
这才是数据采集的“大脑”。我们编写一个addons.py脚本,供mitmdump -s addons.py调用。
import json from mitmproxy import http, ctx import sqlite3 import re class DouyinFollowerCapture: def __init__(self): self.follower_list_url_pattern = re.compile(r'/aweme/v1/user/follower/list/') # 粉丝列表接口特征 self.db_conn = sqlite3.connect('douyin_followers.db') self.init_db() def init_db(self): """初始化数据库表""" cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS followers ( uid TEXT PRIMARY KEY, nickname TEXT, unique_id TEXT, signature TEXT, captured_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') self.db_conn.commit() def request(self, flow: http.HTTPFlow): """请求阶段,可以修改请求。这里我们用来添加自定义Header或记录URL。""" # 如果需要,可以在这里添加一些请求头,例如模拟特定的User-Agent pass def response(self, flow: http.HTTPFlow): """响应阶段,处理我们感兴趣的响应。""" # 1. 检查URL是否匹配粉丝列表接口 if self.follower_list_url_pattern.search(flow.request.pretty_url): ctx.log.info(f"捕获到粉丝列表请求: {flow.request.url}") # 2. 检查响应状态码和内容类型 if flow.response.status_code == 200 and 'application/json' in flow.response.headers.get('content-type', ''): try: # 3. 解析JSON响应 response_data = json.loads(flow.response.text) # 4. 提取粉丝数据。抖音的JSON结构需要实际抓包分析。 # 通常数据在 response_data['followers'] 或 response_data['data'] 下 followers = response_data.get('followers', []) or response_data.get('data', []) if not isinstance(followers, list): ctx.log.warn(f"未找到粉丝列表,响应结构: {response_data.keys()}") return # 5. 遍历并存储 cursor = self.db_conn.cursor() for follower in followers: # 提取关键字段,字段名需根据实际抓包结果调整 uid = follower.get('uid') or follower.get('user_id') nickname = follower.get('nickname') unique_id = follower.get('unique_id') # 抖音号 signature = follower.get('signature') # 个性签名 if uid: # 确保有用户ID try: cursor.execute(''' INSERT OR REPLACE INTO followers (uid, nickname, unique_id, signature) VALUES (?, ?, ?, ?) ''', (uid, nickname, unique_id, signature)) ctx.log.info(f"保存粉丝: {nickname} (UID: {uid})") except sqlite3.Error as e: ctx.log.error(f"数据库插入失败: {e}") self.db_conn.commit() ctx.log.info(f"本轮成功处理 {len(followers)} 个粉丝数据。") # 6. (高级)解析分页参数,为自动化翻页做准备 has_more = response_data.get('has_more', 0) max_time = response_data.get('max_time') # 或 cursor ctx.log.info(f"分页信息 - has_more: {has_more}, max_time: {max_time}") # 可以将 max_time 传递给Appium脚本,用于控制是否继续滑动触发加载 except json.JSONDecodeError as e: ctx.log.error(f"JSON解析失败: {e}, URL: {flow.request.url}") except Exception as e: ctx.log.error(f"处理响应时发生未知错误: {e}") else: ctx.log.warn(f"请求未成功或非JSON响应: {flow.response.status_code}") # 可以添加其他接口的匹配规则,例如用户详情接口 /aweme/v1/user/profile/other/ 等 def done(self): """组件关闭时调用,用于清理资源""" self.db_conn.close() ctx.log.info("数据库连接已关闭。") # 将插件实例添加到mitmproxy addons = [DouyinFollowerCapture()]这个脚本做了几件关键事:
- URL过滤:只处理包含特定路径的请求,避免处理大量无关流量。
- 数据解析:解析JSON,定位到粉丝数据数组。
- 数据存储:将解析出的粉丝信息存入SQLite数据库,使用
INSERT OR REPLACE避免重复。 - 分页感知:记录接口返回的
has_more和max_time字段,为后续自动化翻页提供决策依据。
实操心得:抖音的接口参数和返回结构可能经常变动。最可靠的方法是先手动操作一遍,用Mitmproxy抓包,找到真正的粉丝列表请求URL和响应格式。使用
mitmweb工具可以图形化地查看请求和响应,非常方便。找到正确的接口后,再用正则表达式或字符串匹配来过滤。
4. 高级技巧与实战优化
基础流程跑通后,我们会发现很多实际问题。下面分享一些提升稳定性、效率和隐蔽性的技巧。
4.1 应对Appium的UI识别难题
抖音的UI控件ID经常变化,或者在不同机型上表现不一致。纯靠ID或固定XPath定位非常脆弱。
策略一:使用相对定位和模糊匹配
from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 使用文本内容定位“粉丝”Tab,比用ID更稳定 follower_tab = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((AppiumBy.XPATH, '//*[contains(@text, "粉丝")]')) ) follower_tab.click() # 如果“粉丝”Tab在某个特定的布局容器里,可以结合父节点定位 # 例如:先找到“关注”、“粉丝”、“获赞”所在的父布局,再在其中找“粉丝” tab_container = driver.find_element(AppiumBy.ID, 'com.ss.android.ugc.aweme:id/tab_container') follower_in_container = tab_container.find_element(AppiumBy.XPATH, './/*[@text="粉丝"]')策略二:图像识别辅助(备用方案)当UI结构完全无法定位时,可以借助OpenCV进行简单的图像模板匹配,作为最后的手段。但这会显著增加复杂度和运行时间。
4.2 提升Mitmproxy抓包成功率与效率
1. 处理未知的HTTPS请求: 如果发现关键的粉丝列表请求无法解密(响应体是乱码),可能是抖音使用了证书绑定(SSL Pinning)。应对方法有:
- 使用已Root的手机并安装JustTrustMe等Xposed模块:这类模块可以绕过证书绑定。但这属于较深度的系统修改。
- 使用Frida等动态插桩工具:在运行时Hook掉SSL验证逻辑。这需要一定的逆向工程能力。
- 我们的策略:对于数据采集,如果主要接口无法解密,可以退而求其次,分析未解密的请求模式。即使看不到响应内容,我们也能看到请求的URL、频率、参数变化规律。结合Appium获取的少量界面数据(如第一页粉丝昵称),可以尝试反推接口逻辑。或者,集中精力抓取那些能被解密的次要接口来获取补充信息。
2. 优化过滤规则,减少性能开销: Mitmproxy会处理所有流经的请求,如果规则太宽泛,会消耗大量CPU和内存。要精确过滤。
# 更精确的URL匹配,结合请求方法 if flow.request.method == 'GET' and '/aweme/v1/user/follower/list/' in flow.request.path: # 进一步检查查询参数,例如是否包含特定的user_id query = flow.request.query target_user_id = '123456789' # 你要监控的目标用户ID if query.get('user_id') == target_user_id: # 这才是我们要处理的目标请求 process_follower_list(flow)3. 实现自动化分页: 粉丝列表是分页的。我们可以在Mitmproxy的response方法中,解析出has_more和max_time(或cursor)。然后,通过某种方式通知Appium脚本:“这一页抓完了,可以滑动加载下一页了”。一个简单的实现方式是使用一个共享文件或队列。
- Mitmproxy脚本将
has_more和max_time写入一个临时文件。 - Appium脚本在每次滑动后,读取这个文件,如果
has_more为1,则继续滑动;如果为0,则停止。 - 更优雅的方式是使用进程间通信(IPC),比如Redis或简单的Socket,但这会增加架构复杂度。
4.3 稳定性与反爬考量
1. 请求频率控制: 无论是Appium的操作还是Mitmproxy触发的接口请求,都要模拟人类行为,加入随机延迟。
import random, time def human_like_delay(min_s=1, max_s=3): time.sleep(random.uniform(min_s, max_s))在Appium滑动和Mitmproxy处理完一批数据后,都调用这个函数。
2. 账号安全: 长期用同一个账号高频采集数据,有被风控甚至封禁的风险。
- 使用多个账号轮换:准备几个“小号”,在Appium脚本中实现自动切换登录。
- 避免全天候采集:设置合理的采集时间窗口,例如每天只在活跃时段运行几小时。
- 模拟完整用户行为:除了点击粉丝列表,偶尔可以模拟浏览视频、点赞等行为,让账号行为更像真人。
3. 异常处理与状态恢复: 脚本必须健壮。要考虑网络中断、App崩溃、意外弹窗等情况。
- Appium:使用
try...except包裹关键操作,捕获NoSuchElementException,TimeoutException等。出现异常时,可以尝试截图保存现场,然后重启App或从某个检查点恢复。 - Mitmproxy:做好数据库操作的异常捕获和日志记录。定期检查数据库连接状态。
4. 数据去重与增量更新: 使用数据库的UNIQUE约束或INSERT OR IGNORE/REPLACE语句。在采集前,可以先查询已采集的最新max_time,从那个时间点之后开始请求,实现增量采集。
5. 常见问题排查与解决方案实录
在实际操作中,你几乎一定会遇到下面这些问题。这里是我踩过坑后的经验总结。
5.1 Appium连接或操作失败
问题1:adb devices能识别设备,但Appium连接时报错Cannot start the ‘app’ activity。
- 原因:
appActivity参数不正确,或者App有多个启动Activity。 - 解决:使用
adb shell dumpsys window | grep mCurrentFocus命令时,确保抖音App正处于你希望脚本启动后进入的初始页面(通常是启动后的主页面)。获取到的Activity可能不是标准的启动页。一个更稳妥的方法是查阅资料或使用APK分析工具(如apkanalyzer)来查找主Activity。也可以尝试不指定appActivity,只指定appPackage,让Appium自动探测。
问题2:脚本运行时,找不到页面元素(NoSuchElementException)。
- 原因:页面还没加载完就执行查找;UI结构已更新;元素在嵌套的WebView中。
- 解决:
- 增加等待:用
WebDriverWait替代time.sleep。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC element = WebDriverWait(driver, 15).until( EC.presence_of_element_located((AppiumBy.ID, "some_id")) ) - 更新定位符:使用最新的
appium inspector或UI Automator Viewer重新查看元素属性。 - 检查上下文(Context):如果元素在H5页面(WebView)里,需要先切换到WebView上下文:
driver.switch_to.context('WEBVIEW_com.ss.android.ugc.aweme'),操作完再切回来:driver.switch_to.context('NATIVE_APP')。
- 增加等待:用
5.2 Mitmproxy抓不到包或HTTPS解密失败
问题1:手机设置了代理,但mitmdump看不到任何请求。
- 原因:电脑防火墙阻止了8080端口;手机和电脑不在同一网络;代理设置未保存。
- 解决:
- 关闭电脑防火墙或为mitmdump添加入站规则。
- 确保手机连接的Wi-Fi和电脑是同一个局域网。
- 在手机Wi-Fi设置中保存代理后,有时需要关闭再打开Wi-Fi开关。
- 尝试在电脑上使用
mitmweb,通过浏览器界面查看更直观。
问题2:能看到HTTP请求,但抖音的HTTPS请求显示TLS handshake failed或响应是乱码。
- 原因:CA证书未正确安装或不被抖音信任(SSL Pinning)。
- 解决:
- 重新访问
mitm.it,下载并安装证书。Android 10+ 系统,安装证书时一定要选“VPN和应用”或“所有应用”的凭据存储位置,如果只有“用户”选项,则可能对部分App无效。 - 对于无法绕过SSL Pinning的情况,可以尝试抓取模拟器的流量。一些Android模拟器(如官方模拟器、夜神)的系统镜像可以更容易地安装系统级证书(通过拖拽证书文件到模拟器并设置)。
- 如果只是为了分析请求规律,可以关注未被解密的请求的URL和查询参数,这些信息仍然是明文可见的。
- 重新访问
问题3:抓包过程中,抖音App提示“无网络连接”或无法加载内容。
- 原因:Mitmproxy的拦截影响了某些长连接或CDN请求。
- 解决:在Mitmproxy脚本的
request方法中,将某些域名加入忽略列表。
这需要观察哪些域名的请求失败导致了App异常,然后将其排除。def request(self, flow: http.HTTPFlow): ignore_hosts = ['log-upload.tiktokv.com', 'monitor.tiktokv.com', '*.snssdk.com'] # 示例 if any(flow.request.pretty_host.endswith(host.replace('*.', '')) for host in ignore_hosts): ctx.log.info(f"忽略请求: {flow.request.url}") return
5.3 数据解析与存储问题
问题:Mitmproxy脚本能抓到请求,但解析JSON时出错,或提取不到数据字段。
- 原因:抖音接口返回的数据结构复杂或已加密;接口版本更新导致字段名变化。
- 解决:
- 仔细分析原始响应:使用
mitmweb或将响应体保存到文件,用JSON格式化工具仔细查看结构。关键数据可能藏在多层嵌套下,或者是一个经过Base64编码的字符串。 - 打印调试:在脚本中打印出
response_data.keys()或整个响应结构的概要,找到数据真正的路径。 - 关注加密字段:有时粉丝列表中的用户ID或昵称可能是加密的。需要观察其他接口(如用户主页信息接口)是否返回了明文信息,或者尝试寻找其解密规律(这涉及逆向分析,难度较大)。对于基础数据采集,可能只需要关注接口的宏观调用规律。
- 仔细分析原始响应:使用
这套Appium+Mitmproxy的联动方案,将UI自动化的“触发能力”与网络抓包的“窃听效率”相结合,在移动端数据采集上开辟了一条实用路径。它最大的优势在于,只要App本身能正常展示数据,我们就有机会通过监听网络通道来获取。整个过程就像是在数据的“高速公路”旁设立了一个检查站,车(Appium)把货(数据请求)引出来,我们(Mitmproxy)再对货物进行快速分拣。当然,这条路需要你耐心地铺设“铁轨”(环境配置)和应对各种“天气变化”(反爬与变更)。在实际操作中,保持工具的更新,多分析抓包数据,勤于编写异常处理,你的数据采集管道就会越来越稳定。最后,务必在法律法规和平台用户协议允许的范围内使用此类技术,将数据用于正当的分析和学习目的。