ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python实战:用iTunes Search API批量抓取App Store应用数据

Python实战:用iTunes Search API批量抓取App Store应用数据 简介这是一份面向开发者和数据运营人员的Apple Store应用信息批量抓取脚本基于Python 2.7编写通过Apple Search API读取CSV中的应用程序ID自动输出包含iTunes ID、捆绑ID、应用名称、发布者及主要类别等字段的CSV结果解决手工逐个查询效率低的问题。资源包仅含3个文件包括一个主脚本、一个CSV输入模板和一份Markdown说明文档压缩包总大小仅2KB结构简单清晰便于快速阅读与修改。已有467人学习下载适合正在学习API调用或需要批量整理App元数据的入门级Python用户尤其适合竞品分析、ASO优化等小批量应用信息收集场景。脚本无需复杂配置用户只需在CSV中逐行填写待查询的App ID运行脚本即可获得结构化数据说明文档还给出了从解压、编辑到执行的完整流程帮助快速上手同时也可作为命令行脚本与外部API集成的小型练习项目。 前阵子做了一个项目名字就叫applestoredata核心功能是写一个Python脚本批量从Apple Store抓取应用的基础数据尤其是应用ID。说白了就是通过脚本把App Store里的应用信息拉下来整理成结构化数据方便后续做竞品监控、ASO分析、市场调研之类的。如果你跟我一样日常要跟一堆App打交道需要定期记录应用排名、下载量预估、版本更新动态那这个小工具的思路应该对你有参考价值。这个脚本我最早是为了解决一个很具体的痛点手动去iTunes搜应用、复制链接、抄ID再整理到表格里效率太低了。尤其是一次要处理几十个甚至上百个App的时候光复制粘贴就够呛。从最开始的一个几十行的小脚本到后来不断完善现在已经稳定跑了两三个月今天把整个思路和实现细节整理出来。1. 项目背景与核心思路拆解applestoredata这个名字是我自己起的直译就是“Apple Store数据”。最开始的想法很简单把Apple Store里应用的核心数据提取出来自动化处理。这里的“应用程序ID”其实包含两层含义一个是App的数字ID就是App Store链接里id后面那串数字另一个是Bundle ID也就是应用的唯一标识符。两者都是很有价值的基础数据可以作为关联其他数据源的键值。1.1 为什么需要抓取“应用ID”这类数据很多人可能会问应用ID不就是一个数字吗有什么好抓的但实际用起来它的价值比你想象的要大。拿竞品监控来说如果你想跟踪某几家竞品公司的所有产品动态最靠谱的方式不是手动搜索而是通过开发者账号下的App列表去枚举。这个时候你会发现开发者账号关联的应用信息里每个App的核心标识就是那个数字ID。通过它你可以拼接出App Store跳转链接、iTunes API的数据查询地址甚至可以用它来匹配广告平台的投放素材、第三方的数据报告等。再比如做ASO应用商店优化分析的时候你需要批量拉取关键词下的应用列表记录排名Top 10、Top 50的App有哪些这些App的ID、名称、评分、更新日期都是分析的基础素材。没有自动化的脚本纯靠人工去记录数据量一大基本就崩了。1.2 技术选型为什么用iTunes Search API而不是直接爬网页刚开始我想的也很简单直接用requests去请求App Store的网页然后解析HTML不就行了后来实际测试才发现这条路走不通。App Store的网页结构非常复杂各种异步加载、动态渲染真要硬爬写出来的代码又脆弱又难看改版一次就废。后来我换了个思路Apple官方其实提供了iTunes Search API可以直接通过关键词搜索应用返回JSON格式的数据。这个接口是公开的不需要开发者账号也不需要API Key白嫖就完事了。配合一些参数控制可以按国家、地区、媒体类型来过滤结果。对于绝大多数爬取需求来说这个API已经完全够用了。注意iTunes Search API有次数限制。官方文档说是每个IP每分钟最多40次请求实际测试下来批量请求的时候稍微控制一下频率问题不大。但如果是那种海量数据抓取建议自己加个代理池或者再想办法等会儿会说怎么处理。我最终的选型是Python requests iTunes Search API SQLite存储。为什么选SQLite因为简单一个文件搞定不用额外起服务查询也方便。这个方案从稳定性和落地速度上都是最优解。2. 核心细节解析与应用ID获取原理这一节会讲一些本质的东西搞清楚之后再写代码会非常顺畅。2.1 App数字ID与Bundle ID的关系与区别先明确两个概念每一个App在App Store里都有一个唯一的数字IDtrackId形如284882218这是某个知名App的ID同时还有一个Bundle ID比如com.xx.xxx英文全称是Bundle Identifier这个是在Xcode里配置的是iOS系统层面识别App的标识。数字ID是App Store生态里的“主键”它出现在链接里和API返回结果里。Bundle ID则主要用于真机调试、推送配置、企业签名的内部识别。对比项数字IDtrackIdBundle ID表示形式纯数字如 1457083670反向域名如 com.example.app获取方式通过API、链接提取通过开发者后台、App信息页面用途App Store搜索、关联分析移动端标识、推送、测试是否公开公开部分公开iOS设备可查这个脚本的主要目标是数字ID顺带把Bundle ID也一起存下来这样后面分析的时候两种标识都有了会方便很多。2.2 iTunes Search API的关键参数与请求逻辑iTunes Search API的基础请求格式是https://itunes.apple.com/search?term关键词countrycnentitysoftwarelimit50参数说明term搜索关键词注意要做URL编码countryApp Store地区代码比如cn代表中国区us代表美区entity媒体类型software代表只搜索AppsoftwareDeveloper代表搜索开发者limit返回数量上限最大值是200还有两个很有用的高级参数attribute限制搜索字段比如sellerName可以通过开发者名字来搜callback返回JSONP格式一般用不上实际请求逻辑很简单拿到搜索词拼URL发请求然后解析返回的results数组。2.3 响应数据结构与关键字段解读API返回的JSON结构里results数组中的每个元素就是一个App的完整信息常见的字段有{ trackId: 1457083670, trackName: 示例应用, bundleId: com.example.app, sellerName: 示例开发者, price: 0.00, formattedPrice: 免费, averageUserRating: 4.8, userRatingCount: 12345, releaseDate: 2023-01-01T00:00:00Z, currentVersionReleaseDate: 2024-06-01T00:00:00Z, artworkUrl512: https://example.com/icon.png, genres: [工具, 效率], trackViewUrl: https://apps.apple.com/cn/app/id1457083670 }trackId就是我们要的数字IDbundleId是Bundle ID。trackName是可以展示的名称字段sellerName是开发者名averageUserRating和userRatingCount可以用来做评分分析。genres返回的是分类数组——这里有个坑不同地区的分类叫法不一样比如中国区叫“工具”美区叫“Utilities”做数据分析的时候要小心。3. 实操过程applestoredata脚本完整实现这一部分我把脚本的核心实现拆成几步来说你可以直接照着搭。先交代一下环境macOS Python 3.10Windows上也可以跑没区别。3.1 环境准备与依赖安装主脚本需要两个第三方库requests负责HTTP请求tqdm用来显示进度条数据量大、有耗时操作的时候体验很好。如果你的环境还没装直接执行pip install requests tqdm如果是Windows用户可能会遇到一个问题执行的时候提示无法将“python”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。这个不是你代码的问题是Python没有加到系统PATH环境变量里。解决办法有两个第一安装Python的时候勾选“Add Python to PATH”第二手动把Python安装目录和Scripts目录加到环境变量里。类似的像git、pip、pnpm这种命令提示找不到十有八九都是同一个原因——环境变量没配置好。3.2 主脚本核心代码下面就是applestoredata核心抓取部分的代码我把它精简成可以直接运行的版本import requests import json import time import sqlite3 from urllib.parse import quote from tqdm import tqdm API_BASE https://itunes.apple.com/search def fetch_apps_by_keyword(keyword, countrycn, limit50): 根据关键词抓取App列表 params { term: quote(keyword), country: country, entity: software, limit: limit } # 说明requests会自己编码其实不用手动quote但历史版本保留了这个写法 resp requests.get(API_BASE, paramsparams, timeout10) if resp.status_code 200: data resp.json() return data.get(results, []) else: print(f请求失败{resp.status_code}) return [] def extract_app_info(app): 提取需要关注的字段 return { app_id: app.get(trackId), bundle_id: app.get(bundleId), name: app.get(trackName), seller: app.get(sellerName), price: app.get(price), rating: app.get(averageUserRating), rating_count: app.get(userRatingCount), version: app.get(version), genres: , .join(app.get(genres, [])), url: app.get(trackViewUrl) } def init_db(): 初始化SQLite数据库 conn sqlite3.connect(applestoredata.db) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS apps ( app_id INTEGER PRIMARY KEY, bundle_id TEXT, name TEXT, seller TEXT, price REAL, rating REAL, rating_count INTEGER, version TEXT, genres TEXT, url TEXT, last_updated TEXT DEFAULT CURRENT_TIMESTAMP ) ) conn.commit() return conn def save_to_db(conn, apps): 保存数据使用INSERT OR REPLACE去重 cursor conn.cursor() for app in apps: cursor.execute( INSERT OR REPLACE INTO apps ( app_id, bundle_id, name, seller, price, rating, rating_count, version, genres, url ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , ( app[app_id], app[bundle_id], app[name], app[seller], app[price], app[rating], app[rating_count], app[version], app[genres], app[url] )) conn.commit() def main(): keywords [游戏, 效率, 音乐] # 这里可以换成自己的关键词列表 conn init_db() for kw in tqdm(keywords): print(f正在抓取关键词{kw}) results fetch_apps_by_keyword(kw, countrycn, limit50) apps [extract_app_info(item) for item in results if item.get(trackId)] save_to_db(conn, apps) print(f关键词 {kw} 抓取完成共 {len(apps)} 条) time.sleep(2) # 频率控制避免API限流 conn.close() print(全部完成数据已保存到 applestoredata.db) if __name__ __main__: main()这段代码的思路是遍历关键词列表每个关键词调一次API返回的数据存到SQLite数据库里。INSERT OR REPLACE这句话很关键它的作用是如果app_id相同就用新数据覆盖老数据相当于天然去重。重复跑的时候不需要担心数据会翻倍。3.3 批量抓取开发者名下应用的方法前面说了有时候我们需要拿到某个开发者名下的所有App。这个用attributesellerName参数就能实现def fetch_apps_by_developer(developer_name, countrycn): 根据开发者名称抓取应用列表 params { term: quote(developer_name), country: country, entity: software, attribute: sellerName, limit: 200 } resp requests.get(API_BASE, paramsparams, timeout10) if resp.status_code 200: data resp.json() return data.get(resultCount, 0), data.get(results, []) return 0, []注意这里有个限制limit最大是200如果开发者名下应用超过200个API会截断结果。处理办法是分页但iTunes Search API并没有page参数所以只能通过其他方式补。另一个思路是先拿到开发者名下App的app_id列表然后用lookup接口去查单个App详情这个接口一次最多能查200个ID很实用。3.4 运行结果与数据校验脚本跑完之后数据库里的数据是这种效果app_idbundle_idnamesellerratinggenres1457083670com.example.game示例游戏示例科技4.7游戏, 动作1345559012com.some.dev效率工具某开发团队4.2工具, 商务1435342958com.other.app记账助手某某软件4.9财务, 效率我一般建议跑完先做一轮抽查随机挑几条数据打开url链接手动确认一下名称和ID有没有对应上。这一步虽然简单但能提前发现问题尤其是当API返回的数据跟你预期不一致的时候比如搜索“游戏”结果里混入了很多无关App需要调整关键词或者增加过滤条件。4. 常见问题与排查技巧实录脚本写得再顺手实际运行的时候还是会踩一些坑。这里把我遇到过的几个典型问题整理成速查表方便大家对照排查。4.1 常见报错排查速查表现象可能原因解决办法PowerShell提示“禁止运行脚本”执行策略限制了 .ps1 脚本以管理员身份运行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned提示claude、pnpm、mvn等命令无法识别环境变量PATH未配置将对应工具的安装目录添加到系统PATH请求返回403请求频率过高被限流在两个请求之间增加time.sleep(1)或随机延迟返回结果为空country参数错误或者关键词无匹配检查地区代码尝试更换关键词中文乱码或URL编码错误关键词未正确编码使用requests库传params不要手动拼URL数据库报“database is locked”多个连接同时写SQLite每次写入后立即commit避免长事务4.2 关于“环境变量”的踩坑细节很多新手在Windows上跑Python脚本最容易卡住的其实不是代码而是环境问题。比如pip install明明成功了但运行python却说找不到命令或者用npm装了个脚本执行的时候又说npm不是内部或外部命令。这些问题的根源基本都一样工具的安装目录没有被加入到PATH环境变量。系统在敲命令的时候会在PATH指定的目录里按顺序找对应的可执行文件找不到就报“无法识别”。解决办法很简单去控制面板→系统→高级系统设置→环境变量在Path变量里把对应工具的安装路径加进去。比如Python的安装目录里面有python.exe和它的Scripts目录里面有pip.exe。改完之后重新开一个终端窗口才能生效。4.3 API限流与请求频率控制iTunes Search API的官方限制是每个IP每分钟40次请求。实际测试下来如果是你本地跑正常做关键词搜索的话这个限制已经够用了。但如果你要跑大数据量比如一次要抓几百个关键词建议在代码里加上频率控制。我们脚本里的做法是每次请求之后time.sleep(2)这样即使跑几十个关键词也不会触发限流。如果你用的是公司IP可能还有一些额外的防火墙规则那就需要随机延迟了import random import time time.sleep(random.uniform(1, 3)) # 随机延迟1到3秒这招实测很管用把请求间隔拉开之后基本不会碰到403。4.4 数据去重与历史记录管理跑了几次脚本之后数据库里可能会有不少历史数据怎么管理这些数据也是个实际问题。我目前的方案是在表里加一个last_updated字段每次更新都会刷新这个时间戳。这样想看“哪些App在最近一周没有更新版本”就非常简单SELECT name, seller, last_updated FROM apps WHERE last_updated datetime(now, -7 days);如果你想去掉某个关键词下所有数据重新抓取可以加一个keyword字段或者直接按关键词生成独立的表。我的习惯是单独建表每次只更新“目标关键词列表”对应的数据集方便做对比分析。5. 项目扩展与后续优化方向applestoredata现在已经能稳定跑了但它还有很多可以扩展的方向。简单说几个我觉得值得做的思路。5.1 增加定时任务实现自动化监控之前在macOS/Linux上用crontab加一个定时任务比如每天凌晨2点跑一次脚本数据库里的数据就能保持每日更新。Windows上可以用“任务计划程序”操作起来也不复杂。这样你每天早上一睁眼前一天的全部App数据已经整整齐齐躺在数据库里了。5.2 接入App详情查询接口除了搜索iTunes Search API还提供了一个lookup接口可以根据ID批量查询应用详情。用法很简单def fetch_apps_by_ids(app_ids): 根据应用ID列表批量查询详情 params { id: ,.join(map(str, app_ids)), country: cn } resp requests.get(https://itunes.apple.com/lookup, paramsparams, timeout10) if resp.status_code 200: return resp.json().get(results, []) return []这个接口其实非常强大日常用的最多的就是通过app_id反查应用的最新状态比如版本号变了没有、价格变了没有、评分涨了还是跌了。我们之前有个场景是每天通过lookup接口拉取一批重点跟踪的app_id自动对比版本号和价格有变化就推送到企业微信群里做产品动态监控基本零成本跑了好几个月。5.3 导出一键Excel报表脚本跑完是SQLite数据库但对于不会SQL的人来说直接用Excel打开更方便。我在项目里加了一个导出功能把查询结果直接输出成Excel表格用Excel自带的筛选和图表功能基本能满足所有日常分析需求。Python的pandas可以很轻松地做到这一点。说真的这个项目做到后面我最大的感受就是批量的数据整理工作脚本真的能解放双手。以前手动一天才能弄完的东西现在脚本十几分钟就跑完了还能定时自动执行出错率还低。不管是做ASO、竞品分析还是单纯想了解某个类目下的App生态applestoredata这个思路都能帮上忙。如果你也有类似的场景可以拿这套代码去改一改跑起来之后你会发现其实没有想象中那么复杂。本文还有配套的精品资源点击获取
返回列表