当前位置: 首页 > news >正文

Scrapy框架实战:大规模爬取华为应用市场应用详情数据

在移动互联网时代,应用商店(App Store)汇聚了海量的应用数据,这些数据对于市场分析、竞品研究、用户行为洞察乃至投资决策都具有无可估量的价值。华为应用市场作为全球Top 3的应用分发平台,其数据更是开发者、分析师和企业所关注的焦点。

手动收集这些数据无异于大海捞针,而Python爬虫技术则是实现自动化、大规模数据采集的利器。在众多Python爬虫框架中,Scrapy 以其强大的功能、高效的异步处理和清晰的项目结构,成为完成此类大规模爬取任务的不二之选。

一、项目目标与准备工作

1.1 爬取目标

我们的目标是爬取华为应用市场上指定分类(如“游戏”、“商务”)中的应用列表,并逐个获取每个应用的详细字段,包括但不限于:

  • 应用名称
  • 应用包名 (Package Name)
  • 开发者
  • 评分与评分人数
  • 应用大小
  • 更新日期
  • 应用简介
  • 应用截图URL
  • 最新版本号

1.2 环境与工具

  • Python 3.8+
  • Scrapy 2.5+: 使用 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">pip install scrapy</font> 安装
  • 浏览器开发者工具 (F12): 用于分析网络请求和目标数据结构。

1.3 核心思路分析

与一些静态网页不同,现代应用商店的数据通常通过异步API(XHR)接口动态加载。直接解析HTML不仅复杂,而且容易因前端改动而失效。更高效、稳定的方式是直接模拟浏览器调用后端API的行为

  1. 打开华为应用市场网页版:进入分类列表页。
  2. 打开浏览器开发者工具 (F12),切换到 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Network</font> -> <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">XHR</font> 标签。
  3. 滚动列表页,观察是否有新的XHR请求出现,其中包含了应用列表数据。
  4. 点击一个应用,进入详情页,同样在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Network</font> 中寻找包含详细数据的API请求。
  5. 分析找到的API请求:包括URL、请求头(Headers)、请求参数(Payload)和返回的JSON数据结构。

通过分析,我们通常能找到一个返回JSON格式列表数据的API和一个返回详细信息的API。本教程将基于此假设进行。

二、Scrapy项目搭建与核心组件编写

2.1 创建Scrapy项目

scrapy startproject huawei_appmarket
cd huawei_appmarket
scrapy genspider appmarket "huawei.com"

这会创建一个名为 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">huawei_appmarket</font> 的项目和一个名为 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">appmarket</font> 的爬虫。

2.2 定义数据模型 (Items.py)

<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">items.py</font> 中,我们定义要爬取的数据结构。这使数据管道路由和导出更加清晰。

import scrapyclass HuaweiAppmarketItem(scrapy.Item):# 定义要爬取的字段collection_name = scrapy.Field()  # 集合名,用于MongoDBcategory = scrapy.Field()         # 应用分类app_name = scrapy.Field()         # 应用名称package_name = scrapy.Field()     # 包名developer = scrapy.Field()        # 开发者rating = scrapy.Field()           # 评分rating_count = scrapy.Field()     # 评分人数size = scrapy.Field()             # 应用大小update_date = scrapy.Field()      # 更新日期description = scrapy.Field()      # 应用简介screenshot_urls = scrapy.Field()  # 截图URL列表version = scrapy.Field()          # 版本号detail_url = scrapy.Field()       # 详情页URL

2.3 编写爬虫核心逻辑 (Spiders/appmarket.py)

这是爬虫的核心。我们需要重写 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">start_requests</font><font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">parse</font> 方法。

python

import scrapy
import json
from huawei_appmarket.items import HuaweiAppmarketItem
from urllib.parse import urlencode, quoteclass AppmarketSpider(scrapy.Spider):name = 'appmarket'allowed_domains = ['huawei.com']# 代理配置proxyHost = "www.16yun.cn"proxyPort = "5445"proxyUser = "16QMSOML"proxyPass = "280651"# 假设我们分析出的列表API基础URL和参数list_api_url = "https://web-drcn.hispace.dbankcloud.cn/uowap/index?"query_params = {'method': 'internal.getTabDetail','serviceType': '20','reqPageNum': 1,'maxResults': 20,'uri': '','zone': '','locale': 'zh_CN'}# 起始分类(例如游戏)start_uri = 'gameList_1'def start_requests(self):# 构建初始请求的URLparams = self.query_params.copy()params['uri'] = self.start_uriurl = self.list_api_url + urlencode(params)# 添加必要的请求头,否则可能被拒绝访问headers = {'Accept': 'application/json, text/plain, */*','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36','Origin': 'https://appgallery.huawei.com','Referer': 'https://appgallery.huawei.com/',}# 创建请求并添加代理request = scrapy.Request(url, headers=headers, callback=self.parse_list)request.meta['proxy'] = f"http://{self.proxyUser}:{self.proxyPass}@{self.proxyHost}:{self.proxyPort}"yield requestdef parse_list(self, response):# 解析API返回的JSON数据json_data = json.loads(response.text)app_list = json_data.get('layoutData', [])# 遍历应用列表for app in app_list:item = HuaweiAppmarketItem()item['category'] = self.start_uriitem['app_name'] = app.get('name')item['detail_url'] = app.get('descUrl') # 详情页URL可能用于后续请求# 关键:获取每个应用的唯一标识(如package name或id)package_name = app.get('packageName')item['package_name'] = package_name# 这里假设我们分析出了获取详情的API,需要传入appidapp_id = app.get('id')if app_id:# 构建详情API请求 (URL需要根据实际分析结果修改)detail_api_url = f"https://web-drcn.hispace.dbankcloud.cn/uowap/index?method=internal.getTabDetail&serviceType=20&appid={app_id}&zone=&locale=zh_CN"headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36','Referer': 'https://appgallery.huawei.com/'}# 创建请求并添加代理request = scrapy.Request(detail_api_url, headers=headers, callback=self.parse_detail, meta={'item': item})request.meta['proxy'] = f"http://{self.proxyUser}:{self.proxyPass}@{self.proxyHost}:{self.proxyPort}"yield request# 分页逻辑:如果当前页不是最后一页,则请求下一页current_page = self.query_params['reqPageNum']total_page = json_data.get('totalPage', 1)if current_page < total_page:self.query_params['reqPageNum'] += 1next_params = self.query_params.copy()next_params['uri'] = self.start_urinext_url = self.list_api_url + urlencode(next_params)# 创建请求并添加代理request = scrapy.Request(next_url, headers=response.request.headers, callback=self.parse_list)request.meta['proxy'] = f"http://{self.proxyUser}:{self.proxyPass}@{self.proxyHost}:{self.proxyPort}"yield requestdef parse_detail(self, response):# 从meta中获取之前初步构建的itemitem = response.meta['item']# 解析详情API返回的JSONdetail_data = json.loads(response.text)# 这里是一个示例解析逻辑,实际结构需要根据API返回的JSON调整app_detail = detail_data.get('layoutData', [{}])[0] if detail_data.get('layoutData') else {}item['developer'] = app_detail.get('developerName')item['rating'] = app_detail.get('rating')item['rating_count'] = app_detail.get('ratingCount')item['size'] = app_detail.get('sizeDesc')item['update_date'] = app_detail.get('updateTime')item['version'] = app_detail.get('versionName')item['description'] = app_detail.get('introduction')# 解析截图screenshot_urls = []medias = app_detail.get('mediaData', [])for media in medias:if media.get('type') == 'screenshot': # 类型为截图screenshot_urls.append(media.get('url', ''))item['screenshot_urls'] = screenshot_urlsyield item

重要提示:上面的API URL和参数结构均为示例,华为应用市场的实际接口可能会频繁变动。请务必使用浏览器开发者工具分析当前有效的接口,并替换代码中的相应部分。核心是掌握这种直接请求JSON API的方法论。

2.4 配置与中间件 (Settings.py)

<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">settings.py</font> 中进行关键配置,以提高爬虫的成功率和友善度。

# 降低爬取速度,遵守robots.txt,避免对服务器造成压力
DOWNLOAD_DELAY = 1
ROBOTSTXT_OBEY = True# 启用并配置User-Agent中间件,模拟真实浏览器
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'# 启用Item Pipelines,用于后续数据存储
ITEM_PIPELINES = {'huawei_appmarket.pipelines.HuaweiAppmarketPipeline': 300,
}# 可以设置重试和超时
RETRY_TIMES = 2
DOWNLOAD_TIMEOUT = 15

2.5 数据存储管道 (Pipelines.py)

Scrapy处理完数据后,会将其发送到<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Pipelines</font>进行后续处理(如清洗、存储)。

import pymongoclass HuaweiAppmarketPipeline:def __init__(self, mongo_uri, mongo_db):self.mongo_uri = mongo_uriself.mongo_db = mongo_db@classmethoddef from_crawler(cls, crawler):return cls(mongo_uri=crawler.settings.get('MONGO_URI', 'mongodb://localhost:27017'),mongo_db=crawler.settings.get('MONGO_DATABASE', 'huawei_appmarket'))def open_spider(self, spider):self.client = pymongo.MongoClient(self.mongo_uri)self.db = self.client[self.mongo_db]def close_spider(self, spider):self.client.close()def process_item(self, item, spider):# 指定存储的集合(表)名collection_name = item.get('collection_name', 'apps')# 使用包名作为唯一索引,避免重复插入self.db[collection_name].update_one({'package_name': item['package_name']},{'$set': dict(item)},upsert=True)return item

<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">settings.py</font> 中添加MongoDB配置:

python

MONGO_URI = 'mongodb://localhost:27017'
MONGO_DATABASE = 'huawei_appmarket'

三、运行与总结

3.1 运行爬虫

在项目根目录下,执行以下命令运行爬虫并将日志输出到 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">run.log</font>

bash

scrapy crawl appmarket -s LOG_FILE=run.log

3.2 可能遇到的问题与对策

  • 反爬虫(403 Forbidden):需要补充更多请求头,如 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Origin</font>, <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Referer</font>,甚至考虑使用代理IP池。
  • API变更:这是最大的风险,需要定期检查并更新代码中的API URL和参数。
  • 数据解析错误:JSON结构可能微调,需要调整 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">parse_detail</font> 中的解析逻辑。
  • 速率限制:如果被限流,应适当增加 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">DOWNLOAD_DELAY</font>

3.3 总结

通过本项目,我们演示了使用Scrapy框架进行大规模数据爬取的标准流程:

  1. 项目分析:使用开发者工具分析API接口。
  2. 环境搭建:创建Scrapy项目与爬虫。
  3. 模型定义:在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">items.py</font> 中结构化数据。
  4. 爬虫编写:在Spider中实现核心抓取与解析逻辑(<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">parse_list</font>, <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">parse_detail</font>)。
  5. 配置优化:在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">settings.py</font> 中设置爬虫规则。
  6. 数据持久化:在 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">pipelines.py</font> 中将数据存储到数据库(如MongoDB)。

文章转载自:

http://Eirszugz.fpyLL.cn
http://BaymdAsK.fpyLL.cn
http://hY0euWMO.fpyLL.cn
http://QXJv8uTD.fpyLL.cn
http://DXjA5QGp.fpyLL.cn
http://spzht72w.fpyLL.cn
http://rEbTf649.fpyLL.cn
http://C2bjlX6G.fpyLL.cn
http://loKMvK2v.fpyLL.cn
http://9DLOkZKU.fpyLL.cn
http://5VwqRl01.fpyLL.cn
http://VSIirTkM.fpyLL.cn
http://c2TDrvVY.fpyLL.cn
http://oyVsmzqm.fpyLL.cn
http://6zTNWnSk.fpyLL.cn
http://mnwiyBXm.fpyLL.cn
http://xY8vGADB.fpyLL.cn
http://8Jz3n7B4.fpyLL.cn
http://3ijqr07m.fpyLL.cn
http://JNJYE7K0.fpyLL.cn
http://sq95s1XH.fpyLL.cn
http://hHfHAo95.fpyLL.cn
http://EsVkfNKS.fpyLL.cn
http://aV212jTE.fpyLL.cn
http://jJyMmDbU.fpyLL.cn
http://x2NMowSe.fpyLL.cn
http://djSedsxX.fpyLL.cn
http://wbLqgX9x.fpyLL.cn
http://dKe1zxnF.fpyLL.cn
http://oUpOADkG.fpyLL.cn
http://www.dtcms.com/a/364285.html

相关文章:

  • 华为HCIE证书多久续一次费?费用多少?
  • nano banana官方最强Prompt模板来了!六大场景模板详解
  • 如何将华为手机数据转移到OPPO手机
  • 《华为基本法》——企业文化的精髓,你学习了几条?
  • 车辆安全供电系统开发原则和实践
  • 利用 Java 爬虫获取淘宝商品详情 API 接口
  • 指针高级(1)
  • Meta-Learning入门:当AI学会“举一反三”——用MAML实现少样本图像分类 (Meta-Learning系列
  • Qt + windows + Linux+QtInstallerFramework打包教程
  • QNX pidin 命令中STATE 含义
  • vue2 + ts 实现透视卡片 + 瀑布上下移动效果
  • 计算机网络---CA证书体系(Certificate Authority)
  • FPGA离群值剔除算法
  • 【C++】在 Windows 系统调用第三方程序(创建进程)
  • 校园外卖点餐系统(代码+数据库+LW)
  • LeetCode 刷题【62. 不同路径】
  • 【Linux】Linux开发必备:Git版本控制与GDB调试全指南
  • ESXI8多网卡链路聚合
  • Nature Machine Intelligence 基于强化学习的磁性微型机器人自主三维位置控制
  • 【正则表达式】 正则表达式运算法优先级的先后是怎么排序的?
  • Elasticsearch(高性能分布式搜索引擎)01
  • 从“看见”到“行动”:一场机器视觉与机器人的软硬件共舞
  • 动态IP和静态IP配置上有什么区别
  • 云手机中的三大核心技术主要是指什么?
  • 都2025年了,还有人用Python 2吗
  • 华为HCIE数通含金量所剩无几?考试难度加大?
  • 【开题答辩全过程】以 垃圾分类和废物管理系统的设计与实现为例,包含答辩的问题和答案
  • AI会“胡说八道”?探秘AI幻觉背后的真相
  • C++并发编程指南14 使用future
  • MySQL知识点3