尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python爬虫实战:高效稳定爬取华为应用市场App数据

Python爬虫实战:高效稳定爬取华为应用市场App数据 1. 项目缘起为什么选择华为应用市场作为数据源做数据分析和市场调研的朋友经常会遇到一个难题如何高效、批量地获取主流应用商店的App数据无论是为了竞品分析、市场趋势洞察还是构建自己的应用数据库手动一个个去查显然不现实。这时候Python爬虫就成了我们的得力助手。在众多应用市场中华为应用市场AppGallery因其庞大的用户基数和独特的生态定位成为了一个极具价值的数据金矿。你可能已经尝试过搜索“Python爬虫 华为应用市场”但找到的教程要么年代久远接口已失效要么只讲了皮毛遇到反爬机制就束手无策。网上的代码跑起来不是返回一堆乱码就是直接给你一个“404 Not Found”或者“百度安全验证”的拦截页面让人非常头疼。这正是因为华为应用市场作为主流商业平台其网页结构和数据接口都具备一定的防护和动态特性用简单的requests库加正则表达式那一套老方法已经很难行得通了。所以今天我想分享的不仅仅是如何“爬取”更是如何“稳定、高效、合规地”爬取华为应用市场的App数据。我们会绕过那些显而易见的坑比如动态加载的数据、需要处理的参数签名、以及如何模拟真实用户行为以避免触发反爬。整个过程我会基于最新的网页结构以撰写时的2023年下半年至2024年初为准进行拆解并提供完整的、可运行的代码示例。你会发现只要思路清晰工具得当这件事并没有想象中那么复杂。2. 核心思路与工具选型告别“requestsBeautifulSoup”的蛮干时代在开始写代码之前我们必须先想清楚策略。直接对华为应用市场的网页发起请求你会发现很多关键数据如应用详情、下载量、评分详情并不是直接存在于初始HTML中的而是通过JavaScript异步加载Ajax而来的。这就是为什么你用requests.get()拿到网页源码后用BeautifulSoup怎么都找不到下载量数据的原因。因此我们的核心思路需要升级不再与渲染前的HTML源码较劲而是直接模拟浏览器行为获取最终渲染完成后的页面数据或者更直接地找到网站背后用于传输数据的真实API接口。基于这个思路我们的工具链也需要更新Selenium ChromeDriver这是模拟真实用户浏览器操作的“核武器”。它能够启动一个真正的浏览器如Chrome等待页面完全加载包括所有JavaScript执行完毕然后我们再获取此时的页面源码或直接提取元素。这种方法最接近人工操作几乎能应对所有动态网站但缺点是速度较慢资源占用高。它非常适合用于分析阶段帮助我们找到真实的数据接口和请求参数。Requests 浏览器开发者工具DevTools这是我们追求效率的最终方案。通过Selenium辅助我们打开开发者工具F12切换到Network网络标签页然后手动或自动触发我们想要的数据加载动作如点击“查看更多评论”。此时Network面板会记录下浏览器发出的所有HTTP请求其中通常就包含了以.json或特定API路径结尾的数据接口请求。我们仔细分析这个请求的URL、Headers尤其是Cookie,User-Agent,Referer等和Payload请求体参数。一旦我们成功模拟这个请求就可以用轻量级的requests库直接获取结构化的JSON数据效率极高。辅助工具库json用于解析API返回的JSON数据。pandas用于将爬取到的结构化数据列表、字典进行清洗、处理和保存为Excel或CSV文件这是数据分析前的标准操作。time/random用于在请求间插入随机延时模拟人类操作间隔避免请求过于频繁被服务器封禁IP。为什么这样选型纯requests方案对静态网页是高效的但对动态网页无能为力。“Selenium抓取渲染后页面”方案通用但笨重不适合大规模爬取。而“Selenium分析 Requests模拟API”的方案结合了二者的优点用Selenium的“眼睛”找到数据通道再用Requests的“快腿”去跑数据是当前处理这类商业网站最有效、最专业的做法。下面我们就按照这个“侦察兵主力部队”的协作模式来展开。3. 环境准备与侦察找到数据入口的“门牌号”工欲善其事必先利其器。首先我们需要把“侦察兵”Selenium配置好。3.1 安装必要的库打开你的命令行CMD或Terminal使用pip安装以下库pip install selenium pandas3.2 配置WebDriverSelenium需要一个浏览器驱动WebDriver来操控浏览器。这里以Chrome为例。查看Chrome版本打开Chrome浏览器点击右上角三个点 - 帮助 - 关于Google Chrome记下版本号例如120.0.6099.217。下载对应驱动访问 ChromeDriver官网 或国内镜像站下载与你的Chrome版本号完全匹配的chromedriver。放置驱动将下载的chromedriver.exe文件放在一个你记得住的路径下例如C:\WebDriver\。或者更推荐的做法是将其所在目录添加到系统的环境变量PATH中这样在代码里就不需要指定具体路径了。3.3 首次侦察手动分析数据接口让我们先人工走一遍流程理解数据是如何被加载的。打开目标页面并启动侦察在Chrome中打开华为应用市场网页版例如某个游戏分类页 https://appgallery.huawei.com/ 。按F12打开开发者工具并切换到Network网络标签页。记得勾选上Preserve log保留日志防止页面跳转时请求记录被清空。触发数据加载在页面上进行一些操作比如滚动到底部加载更多应用或者点击进入某个应用的详情页。寻找可疑请求在Network面板中你会看到大量请求。将Filter过滤器设置为XHR或Fetch这样可以过滤出大部分用于传输数据的API请求。这些请求的Type通常是xhr或fetch。分析关键请求仔细查看这些请求的Name名称和Preview预览。你可能会发现一些包含query、list、detail、product等关键词的请求其Preview里直接就是结构化的JSON数据包含了应用列表、详情、评论等信息。这个请求的URL和Headers就是我们下一步要用requests去模拟的关键。注意华为应用市场的接口可能会有参数签名或令牌token这些信息往往藏在Headers的Cookie里或者请求参数Payload中。你需要仔细查看Headers的Request Headers部分和Payload标签页可能是Query String Parameters或Form Data。为了让你更直观地理解假设我们通过分析发现了一个获取应用列表的接口其形态可能类似于https://web-drcn.hispace.dbankcloud.cn/uowap/index?methodinternal.getTabDetailuriapp|{category_id}...zonelocalezh_CN其中{category_id}是分类ID。这个接口的响应就是一个标准的JSON里面包含了应用列表。我们的目标就是找到这样的接口规律。4. 实战爬取从应用列表到详情数据的完整链路侦察完毕我们开始编写主力爬虫代码。整个过程分为两步先爬取列表页拿到一批App的ID再根据ID去爬取每个App的详情数据。4.1 第一步爬取应用列表获取App ID这里我们以“游戏”类别下的“休闲游戏”子类为例。通过之前的侦察我们假设找到了列表接口。import requests import json import time import random import pandas as pd from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def get_app_list_from_api(category_id, page1): 模拟API请求获取应用列表 :param category_id: 分类ID需要从网页分析中获取 :param page: 页码 :return: 应用ID列表 # 这是一个示例URL实际URL需要你通过开发者工具分析得到 # 注意以下URL、参数和Headers均为示例实际值必须通过你的分析确定 url https://web-drcn.hispace.dbankcloud.cn/uowap/index params { method: internal.getTabDetail, uri: fapp|{category_id}, pageNum: page, pageSize: 30, # 每页数量 zone: , locale: zh_CN, # 可能还有其他必要参数如serviceType、version等 } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://appgallery.huawei.com/, # Cookie至关重要通常需要从已登录的浏览器中复制。 # Cookie: 你的Cookie字符串 } try: response requests.get(url, paramsparams, headersheaders, timeout10) response.raise_for_status() # 检查请求是否成功 data response.json() # 解析JSON提取应用ID。具体路径需要根据实际API返回结构调整 app_list data.get(layoutData, []) app_ids [] for item in app_list: # 假设每个item里有一个productId字段是应用的唯一ID app_id item.get(productId) if app_id: app_ids.append(app_id) print(f第{page}页获取到{len(app_ids)}个App ID。) return app_ids except requests.exceptions.RequestException as e: print(f请求列表页失败: {e}) return [] except json.JSONDecodeError as e: print(f解析JSON失败: {e}) return [] # 使用Selenium辅助获取Cookie如果API需要登录态 def get_cookie_with_selenium(): 启动浏览器访问页面获取Cookie供requests使用 options webdriver.ChromeOptions() # 可选无头模式不显示浏览器窗口 # options.add_argument(--headless) driver webdriver.Chrome(optionsoptions) driver.get(https://appgallery.huawei.com/) time.sleep(5) # 等待页面加载可以更精确地使用WebDriverWait # 这里可能需要你手动处理登录如果有登录弹窗或者页面已经包含了必要的匿名Cookie # 获取Cookie cookies driver.get_cookies() driver.quit() # 将Selenium的Cookie格式转换为requests可用的字典格式 cookie_dict {} for cookie in cookies: cookie_dict[cookie[name]] cookie[value] # 将字典格式的Cookie转换为字符串格式用于放入headers cookie_str ; .join([f{k}{v} for k, v in cookie_dict.items()]) return cookie_str if __name__ __main__: # 先获取Cookie如果需要 # cookie get_cookie_with_selenium() # print(f获取到的Cookie: {cookie[:100]}...) # 打印前100字符 # 假设我们通过分析得知‘休闲游戏’的category_id是某个值例如C101074875 target_category_id C101074875 all_app_ids [] for page in range(1, 6): # 假设爬取前5页 print(f正在爬取第{page}页...) app_ids get_app_list_from_api(target_category_id, page) if not app_ids: # 如果某一页没拿到数据可能已到末页或出错 break all_app_ids.extend(app_ids) # 随机延时避免请求过快 time.sleep(random.uniform(1, 3)) print(f总共获取到{len(all_app_ids)}个App ID。) # 保存ID列表供下一步使用 with open(huawei_app_ids.txt, w, encodingutf-8) as f: for app_id in all_app_ids: f.write(app_id \n)关键点解析User-Agent和Referer这是模拟浏览器请求最基本的两个头部信息缺少它们很容易被识别为爬虫。Cookie这是本次爬取能否成功的最大难点。很多数据接口需要携带有效的Cookie尤其是包含登录态或会话信息的Cookie才能返回数据。我们可以先用Selenium打开一次网页让浏览器自动处理这些Cookie然后我们再从Selenium的driver里把Cookie提取出来交给requests使用。这就是“侦察兵”和“主力部队”的配合。参数签名一些更严格的接口会对参数进行加密签名。如果遇到这种情况你需要仔细分析网页加载的JavaScript文件找到签名算法并用Python实现。这属于进阶反爬策略本篇暂不深入。错误处理网络请求总是不可靠的务必使用try...except包裹并对响应状态码response.raise_for_status()和JSON解析进行异常处理。4.2 第二步爬取应用详情数据拿到App ID列表后我们就可以遍历这个列表去请求每个App的详情页接口了。详情页的数据通常更丰富。def get_app_detail(app_id, cookie_str): 根据App ID爬取应用详情 :param app_id: 应用ID :param cookie_str: 从Selenium获取的Cookie字符串 :return: 包含详情信息的字典 # 详情页API URL示例同样需要实际分析 detail_url https://web-drcn.hispace.dbankcloud.cn/uowap/index params { method: internal.getTabDetail, uri: fapp|{app_id}, # 注意这里变成了单个app的ID zone: , locale: zh_CN, } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: fhttps://appgallery.huawei.com/app/{app_id}, Cookie: cookie_str, # 使用传入的Cookie } app_info {app_id: app_id} try: response requests.get(detail_url, paramsparams, headersheaders, timeout10) response.raise_for_status() detail_data response.json() # 以下是解析示例字段路径必须根据实际API返回结构调整 # 假设详情数据在 layoutData[0][dataList][0] 里 data_list detail_data.get(layoutData, [{}])[0].get(dataList, []) if data_list: detail data_list[0] app_info[app_name] detail.get(name, N/A) app_info[developer] detail.get(developer, N/A) app_info[rating] detail.get(score, N/A) app_info[rating_count] detail.get(commentCount, N/A) app_info[download_count] detail.get(downloadCount, N/A) # 注意华为市场可能不直接提供下载量 app_info[category] detail.get(categoryName, N/A) app_info[update_time] detail.get(updateTime, N/A) app_info[app_size] detail.get(size, N/A) app_info[version] detail.get(versionName, N/A) app_info[description] detail.get(introduction, N/A) else: print(fApp {app_id} 未找到详情数据。) except requests.exceptions.RequestException as e: print(f请求App {app_id} 详情失败: {e}) except (KeyError, IndexError, json.JSONDecodeError) as e: print(f解析App {app_id} 详情数据时出错: {e}) # 每次请求后随机休眠 time.sleep(random.uniform(0.5, 1.5)) return app_info def batch_crawl_details(id_file_path, output_filehuawei_app_details.csv): 批量爬取详情 :param id_file_path: 存储了App ID的文本文件路径 :param output_file: 输出CSV文件名 # 1. 获取Cookie每次运行爬虫获取一次即可可缓存 print(正在通过Selenium获取初始Cookie...) cookie get_cookie_with_selenium() # 2. 读取App ID列表 with open(id_file_path, r, encodingutf-8) as f: app_ids [line.strip() for line in f if line.strip()] all_app_details [] total len(app_ids) # 3. 遍历ID爬取详情 for idx, app_id in enumerate(app_ids, 1): print(f正在处理第 {idx}/{total} 个应用: {app_id}) detail get_app_detail(app_id, cookie) if detail: all_app_details.append(detail) # 4. 使用pandas保存数据 if all_app_details: df pd.DataFrame(all_app_details) # 选择要保存的列并排序 columns_to_save [app_id, app_name, category, developer, rating, rating_count, download_count, update_time, app_size, version] # 确保列存在 existing_columns [col for col in columns_to_save if col in df.columns] df df[existing_columns] df.to_csv(output_file, indexFalse, encodingutf-8-sig) # utf-8-sig解决Excel打开中文乱码 print(f数据已保存至 {output_file} 共 {len(df)} 条记录。) print(df.head()) # 预览前几条数据 else: print(未爬取到任何有效详情数据。) if __name__ __main__: # 假设上一步保存的ID文件是 huawei_app_ids.txt batch_crawl_details(huawei_app_ids.txt)关键点解析与避坑指南Cookie的有效期通过Selenium获取的Cookie可能有有效期。如果爬取过程中大量请求开始返回错误如401、403可能是Cookie失效了。此时需要重新运行get_cookie_with_selenium()函数获取新的Cookie。更稳健的做法是监控请求返回值一旦发现失效迹象就自动重新获取。下载量数据华为应用市场的公开页面上通常不直接显示具体的下载次数如“1亿次下载”而是用“亿万下载”、“热门”等标签替代。通过API获取的downloadCount字段也可能是一个经过处理的等级或范围值而非精确数字。这是数据源本身的限制需要知晓。字段映射API返回的JSON结构可能非常复杂且嵌套很深。你需要像侦探一样在开发者工具的Preview里一层层展开找到你需要的字段如应用名、开发者、评分对应的准确路径。上面的代码中的detail.get(name, N/A)只是示例你必须根据实际看到的结构来调整。异常处理与日志在批量爬取中个别请求失败不应导致整个程序崩溃。完善的try...except和打印日志print能帮你快速定位是哪个App ID出了问题方便后续补爬。速度控制time.sleep(random.uniform(0.5, 1.5))这样的随机延时是礼貌爬虫的基本素养。过于频繁的请求会加重服务器负担也极易触发IP限流或封禁。根据目标网站的反爬强度可以适当调整间隔时间。5. 数据清洗、存储与简单分析爬取到的原始数据往往比较“脏”需要清洗后才能用于分析。pandas在这里能发挥巨大作用。import pandas as pd def clean_and_analyze_data(csv_file): 清洗数据并进行简单分析 df pd.read_csv(csv_file, encodingutf-8-sig) print(原始数据预览) print(df.head()) print(f\n数据形状: {df.shape}) print(f\n列信息: {df.columns.tolist()}) print(f\n数据类型: \n{df.dtypes}) # 1. 处理缺失值 print(f\n缺失值统计: \n{df.isnull().sum()}) # 对于数值列可以用中位数或均值填充对于分类列可以用众数或‘未知’填充 # 这里以评分(rating)为例用中位数填充 if rating in df.columns: median_rating df[rating].median() df[rating].fillna(median_rating, inplaceTrue) print(f已用中位数({median_rating})填充‘rating’列的缺失值。) # 2. 转换数据类型 # 例如将‘download_count’从字符串如‘100万’转换为数值比较困难可能需要先清洗字符串。 # 假设我们的‘download_count’已经是数字字符串或数字 if download_count in df.columns: # 先去除可能的‘万’、‘亿’等中文字符和‘’号这是一个复杂过程此处简化 # df[download_count_clean] df[download_count].astype(str).str.replace(万, 0000).str.replace(亿, 00000000).str.replace(, ).str.replace(,, ) # 尝试转换为数值错误强制为NaN # df[download_count_num] pd.to_numeric(df[download_count_clean], errorscoerce) pass # 实际清洗逻辑根据数据情况定制 # 3. 去重 before_drop len(df) df.drop_duplicates(subset[app_id], inplaceTrue, keepfirst) after_drop len(df) print(f\n根据app_id去重删除了 {before_drop - after_drop} 条重复记录。) # 4. 简单分析示例 print(\n--- 简单分析报告 ---) if rating in df.columns: print(f应用平均评分: {df[rating].mean():.2f}) print(f应用评分中位数: {df[rating].median():.2f}) print(f最高评分应用: \n{df.loc[df[rating].idxmax()][[app_name, rating]] if not df.empty else N/A}) if developer in df.columns: top_dev df[developer].value_counts().head(5) print(f\n发布应用数量最多的前5个开发商: \n{top_dev}) # 5. 保存清洗后的数据 cleaned_file csv_file.replace(.csv, _cleaned.csv) df.to_csv(cleaned_file, indexFalse, encodingutf-8-sig) print(f\n清洗后的数据已保存至: {cleaned_file}) return df # 使用函数 df_cleaned clean_and_analyze_data(huawei_app_details.csv)数据清洗心得下载量清洗是难点像“10万”、“1亿次下载”这样的文本直接转数字会失败。需要写复杂的字符串处理函数识别“万”、“亿”、“千万”等单位并进行换算。有时网站提供的是范围如“1000-5000”处理起来更麻烦。在爬虫设计阶段如果发现目标字段是这种模糊文本就要评估其分析价值有时放弃这个字段或将其作为分类标签如‘热门’、‘一般’是更务实的选择。关注数据一致性检查同一字段的数据格式是否统一。例如“更新日期”有的是“2023-12-01”有的是“2023年12月1日”需要统一为一种格式如datetime类型才能进行时间序列分析。利用pandas的强大功能df.describe()可以快速查看数值列的统计信息df[column].value_counts()可以查看分类列的分布这些都是快速了解数据质量的利器。6. 高级话题与伦理考量6.1 应对更复杂的反爬机制如果上述方法仍然无法获取数据或者很快被屏蔽你可能遇到了更高级的反爬策略IP限制解决方案是使用代理IP池。市面上有许多付费或免费的代理IP服务在requests请求中通过proxies参数设置即可。需要定期检测代理IP的有效性。请求头校验除了User-Agent和Cookie服务器可能还会校验Accept,Accept-Language,Accept-Encoding,Connection等头部。最稳妥的办法是从浏览器开发者工具里把整个Request Headers字典复制下来筛选出必要的部分用在爬虫里。JavaScript挑战有些网站会先返回一段JavaScript代码要求浏览器执行并计算出某个值如_cf_chl_opt等再将这个值作为后续请求的参数。这种情况通常需要用到PyExecJS、js2py等库来执行JS代码或者更彻底地使用Selenium/Playwright这类自动化工具来全程模拟。验证码遇到验证码小型项目可以考虑手动识别大规模项目则需要接入打码平台或训练简单的OCR模型。6.2 爬虫伦理与法律风险这是每个爬虫开发者必须严肃对待的问题。遵守robots.txt在网站根目录下如https://appgallery.huawei.com/robots.txt查看该网站允许或禁止爬虫访问的路径。尽管这不是法律文件但遵守它是行业惯例和道德要求。尊重版权与数据所有权爬取的数据尤其是应用描述、图标等可能受版权保护。未经授权不得用于商业用途或大量公开传播。控制访问频率像前面做的添加延时避免对目标服务器造成DoS攻击式的压力。你的爬虫不应该影响网站的正常用户访问。明确数据用途将爬取的数据用于个人学习、研究或非商业性的市场分析风险相对较低。但如果用于商业竞争、售卖或任何可能损害被爬方利益的行为则法律风险极高。关注用户协议网站的用户协议中通常会有关于数据抓取的条款。违反这些条款可能导致你的IP被永久封禁甚至收到法律函告。我的个人建议是对于华为应用市场这类大型商业平台爬取公开的、概要性的数据如应用名、开发者、评分用于分析学习通常在其容忍范围内但务必保持低调、控制频率。切勿尝试爬取用户隐私数据、破解付费内容或进行任何恶意攻击。整个流程走下来从环境配置、接口分析、请求模拟到数据清洗你会发现爬虫工作更像是一个系统工程而不仅仅是写几行抓取代码。它考验的是你的耐心分析、细心处理细节和责任心遵守规则。希望这篇超详细的指南能帮你绕过我当年踩过的那些坑顺利地从华为应用市场这座金矿里挖到你想要的数据。如果在实际操作中遇到了新的问题不妨再回头仔细看看Network面板里的请求答案往往就藏在那些看似复杂的参数和头部信息里。
返回列表