本篇文章将利用GET请求从OPPO官方网站或公开接口中获取官方授权体验店的分布信息,并通过Python编程语言中的requests库来实现HTTP请求,从而提取详细的门店位置数据。随着OPPO品牌的发展和市场布局的扩展,其官方授权体验店已经遍布全国各大城市和地区,成为连接消费者与品牌的桥梁。因此,掌握如何高效地从网络资源中抓取这些信息变得尤为重要。

首先,我们将探讨如何使用Python的requests库发送GET请求以访问OPPO官方网站或API接口。这包括设置正确的请求头(headers),以便模拟真实的浏览器行为,避免被服务器识别为自动化脚本而拒绝服务。接下来,我们会详细讲解如何解析返回的数据——无论是JSON格式还是HTML页面内容——从中提取所需的门店信息,如店铺名称、地址、经纬度坐标、营业时间等。

在成功获取数据后,本文还将介绍如何对这些原始数据进行清洗和结构化处理,使其更加适合后续分析。例如,可以将数据转换成易于管理和查询的表格形式,或者导入到数据库中。通过对这些结构化数据的深入分析,我们可以揭示OPPO在全国范围内的市场渗透策略、不同城市的布局密度及其与当地人口消费特征之间的关系。

OPPO官方授权体验店门店查询:OPPO 官方授权体验店查询 | OPPO 官方网站

首先,我们找到门店数据的存储位置,然后看3个关键部分标头、负载、 预览;

标头:通常包括URL的连接,也就是目标资源的位置;

负载:对于GET请求:负载通常包含了传递的参数,有些网页负载可能为空,或者没有负载,因为所有参数都通过URL传递,这里我们可以看到城市编码,当前页数,还是明文,没有进行加密;

预览:指的是对响应内容的快速查看或摘要显示,可以帮助用户快速了解返回的数据结构或内容片段;

接下来就是数据获取部分,先讲一下方法思路,一共三个步骤;

方法思路

  1. 找到对应数据存储位置,获取所有店铺列表的相关标签数据;
  2. 我们通过获取和改变行政区编码,来遍历全国门店数据;
  3. 地址转经纬度,通过coord-convert库实现GCJ-02转WGS84;

第一步:我们先找到对应数据存储位置,获取所有门店列表,经过测试,这里可以选择"通过行政区筛选",再选择"所有区域",每个区域会根据页数生成对应数量的html,我们通过修改行政区编码来进行数据获取,为了方便我们可以建立一个包含市级行政区​​​​编码的字典,通过遍历行政区编码来查询全国数据;

通过测试发现非直辖市,数据要想选到"所有区域",就得选择到市,以河北省为例,就是河北省→石家庄市,当然数据同样是通过改变编码进行传递的,但是这里是通过查询一个省,返回一个响应,所以意味着要查询所有省和自治区,才能知道所有编码;

但是我国的行政区编码通常都是一致的,所有我们去中华人民共和国民政部找最新的行政区划编码,下载下来;

通常,中国的行政区划编码规则如下:

  • 省级:前两位有效,后四位为 0000(如 110000 北京市)
  • 市级:前四位有效,后两位为 00,且不是 0000(如 110100 北京市市辖区)
  • 县级:六位均为有效数字(如 110101 东城区)

因此,我们可以通过判断编码是否满足 XXXX00 且不等于 XXXX00(排除省级)来提取市级编码;

完整代码#运行环境 Python 3.11

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import csv# 配置表头
url = "https://www.mca.gov.cn/mzsj/xzqh/2023/202301xzqh.html"
headers = {"User-Agent": "Mozilla/5.0"}
output_file = "city_codes_2023.csv"# 获取并解析
print("正在获取数据...")
res = requests.get(url, headers=headers)
res.encoding = 'utf-8'
soup = BeautifulSoup(res.text, 'html.parser')data = []
for row in soup.find_all('tr'):cells = row.find_all('td')if len(cells) >= 3:code = cells[1].get_text(strip=True)name = ''.join(cells[2].get_text().split())  # 清理空白if code.isdigit() and len(code) == 6 and code.endswith('00') and not code.endswith('0000'):if name not in ['市辖区', '县']:data.append((code, name))# 保存为CSV(带BOM,兼容Excel)
with open(output_file, 'w', encoding='utf-8-sig', newline='') as f:writer = csv.writer(f)writer.writerow(['编码', '名称'])writer.writerows(data)print(f"完成!共提取 {len(data)} 个市级单位,已保存为 '{output_file}'")

获取数据标签如下,城市编码城市名称,数据保存为city_codes_2023.csv,这里需要把上海(310100)、北京(110100)、天津(120100)、重庆(500100)这些直辖市手动加上,需要注意的是,例如北京市行政区划代码为110000,其中,110100为市辖区汇总码,所以这里直辖市使用的都是市辖区汇总码;

第二步:利用GET请求获取所有门店列表,并根据标签进行保存,另存为csv;

完整代码#运行环境 Python 3.11

# -*- coding: utf-8 -*-import requests
import csv
import time
from datetime import datetime# ================== 配置 ==================
CSV_INPUT = "city_codes_2023.csv"           # 城市编码文件(含 "编码" 列)
CSV_OUTPUT = "oppo_shops_all_cities.csv"    # 输出文件
API_URL = "https://opsiteapi-cn.oppo.com/api/public/v1/sfa/search"
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36","Referer": "https://www.oppo.com/"
}
PAGE_SIZE = 100
DELAY = 0.5  # 每个城市请求后延迟0.5秒,礼貌爬取# ================== 读取城市编码 ==================
def load_city_codes(filename):codes = []try:with open(filename, 'r', encoding='utf-8-sig') as f:reader = csv.DictReader(f)for row in reader:code = row.get("编码", "").strip()if code.isdigit() and len(code) == 6:codes.append(code)print(f"加载 {len(codes)} 个城市编码")except FileNotFoundError:print(f"错误:未找到文件 {filename},请确保 city_codes_2023.csv 存在")return []except Exception as e:print(f"读取城市编码失败: {e}")return []return codes# ================== 获取单个城市的所有门店数据 ==================
def fetch_all_pages(gid):all_shops = []page_no = 1while True:params = {"gid": gid,"shopType": "3","operateStatusList": "2","pageNo": page_no,"pageSize": PAGE_SIZE}try:response = requests.get(API_URL, params=params, headers=HEADERS, timeout=10)response.raise_for_status()data = response.json()if data.get("code") != "0":print(f"API 返回异常 (gid={gid}, page={page_no}): {data.get('message', 'Unknown')}")breakrecords = data["data"]["records"]all_shops.extend(records)# 获取总页数total_pages = data["data"]["pages"]print(f"获取 gid={gid} 第 {page_no}/{total_pages} 页,共 {len(records)} 条")if page_no >= total_pages:breakpage_no += 1time.sleep(0.1)  # 短暂延迟,避免频率过高except Exception as e:print(f"请求 gid={gid} 第 {page_no} 页失败: {e}")breakreturn all_shops# ================== 保存所有门店数据 ==================
def save_to_csv(all_shops, filename):fieldnames = ["city_gid", "id", "name", "code", "fullShopAddress","lng", "lat", "shopBusinessStart", "shopBusinessEnd", "shopContactNumber"]with open(filename, "w", encoding="utf-8-sig", newline="", errors="replace") as f:writer = csv.DictWriter(f, fieldnames=fieldnames)writer.writeheader()for shop in all_shops:loc = shop.get("locationDTO", {}) or {}writer.writerow({"city_gid": shop.get("city_gid"),  # 标记来源城市"id": shop["id"],"name": shop["name"],"code": shop["code"],"fullShopAddress": loc.get("fullShopAddress", ""),"lng": loc.get("lng", ""),"lat": loc.get("lat", ""),"shopBusinessStart": shop.get("shopBusinessStart", ""),"shopBusinessEnd": shop.get("shopBusinessEnd", ""),"shopContactNumber": shop.get("shopContactNumber", "")})print(f"所有数据已保存至: {filename}")# ================== 主函数 ==================
def main():print(f"开始获取 OPPO 门店数据 | {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")# 1. 加载城市编码city_codes = load_city_codes(CSV_INPUT)if not city_codes:returnall_shops = []success_count = 0fail_count = 0# 2. 遍历每个城市for i, gid in enumerate(city_codes, 1):print(f"[{i}/{len(city_codes)}] 正在获取城市 gid={gid} 的门店数据...")shops = fetch_all_pages(gid)# 添加城市标识for shop in shops:shop["city_gid"] = gidif shops:all_shops.extend(shops)success_count += 1else:fail_count += 1time.sleep(DELAY)  # 控制请求频率# 3. 保存结果if all_shops:save_to_csv(all_shops, CSV_OUTPUT)print(f"完成!共获取 {len(all_shops)} 条门店数据,来自 {success_count} 个城市")if fail_count > 0:print(f"{fail_count} 个城市获取失败")else:print("未获取到任何门店数据")# ================== 运行 ==================
if __name__ == "__main__":main()

获取数据标签如下,city_gid(行政区id)、id(门店id)、name(门店名称)、fullShopAddress(门店地址)、lng & lat(地理坐标)、shopBusinessStart(开始营业时间)、shopBusinessEnd(结束营业时间)、shopContactNumber(门店电话),其他一些非关键标签,这里省略;

第三步:坐标系转换,由于OPPO官方授权体验店门店数据使用的是高德坐标系(GCJ02),为了在ArcGIS上准确展示而不发生偏移,我们需要将门店的坐标从GCJ02转换为WGS-84坐标系。我们可以利用coord-convert库中的gcj2wgs(lng, lat)函数,也可以用免费这个网站:批量转换工具:地图坐标系批量转换 - 免费在线工具;
对CSV文件中的服务网点坐标列进行转换,完成坐标转换后,再将数据导入ArcGIS进行可视化;

接下来,我们进行看图说话:

OPPO官方授权体验店在中国呈现出明显的地域性差异。高度集中的现象主要出现在东部和南部地区,尤其是华东、华南以及华中地区,这些区域店铺的数量显著多于其他地区。这表明OPPO在这些经济发达、人口密集且消费能力较强的区域有着更为广泛的布局。相对而言,稀疏分布的情况则出现在西北、东北及青藏高原等地理环境较为复杂的地区。

具体来看,在东部沿海地区,包括山东、江苏、浙江、福建和广东等省份,是体验店最为密集的地方。这里不仅是我国经济发展的前沿阵地,也是电子消费品的主要市场之一。城市覆盖广的特点不仅体现在省会城市和大城市,还包括了一些中小城市,显示出OPPO对于该地区市场的重视程度。而在中部地区,如河南、湖北、湖南等地,则构成了次级集中区。尽管店铺数量不及东部沿海,但依然反映出这些地区拥有较大的市场潜力和发展空间。

相比之下,西部和北部地区的分布显得较为稀疏。例如新疆、青海、西藏、内蒙古以及黑龙江等省份,由于地理环境、人口密度及经济发展水平等因素的影响,这里的体验店数量较少。不过,即便是这些地区,OPPO也倾向于选择省会城市或较大的城市进行重点布局,如乌鲁木齐、呼和浩特等,以确保品牌影响力和服务质量。

影响上述分布的因素众多,其中经济因素扮演着重要角色。经济发展水平商业氛围较好的地方往往更受青睐;同时,人口因素也不可忽视,人口密度高且年轻人口比例大的地区,对于电子产品的需求量更大。此外,政策因素同样起到了推动作用,比如部分地区可能享有政府提供的税收优惠或者租金补贴等支持措施。

展望未来,OPPO有望继续深化其在东部和中部市场的战略布局,进一步增加体验店数量,并提升服务质量。与此同时,随着国家对西部大开发和东北振兴等战略的支持力度加大,逐步拓展西部和北部市场也将成为可能。通过不断优化店面选址和运营策略,OPPO可以根据不同地区的市场需求提供更加个性化和优质的服务,满足广大消费者的需求。

文章仅用于分享个人学习成果与个人存档之用,分享知识,如有侵权,请联系作者进行删除。所有信息均基于作者的个人理解和经验,不代表任何官方立场或权威解读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917803.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917803.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917803.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Self-RAG:基于自我反思的检索增强生成框架技术解析

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! 一、核心定义与原始论文 Self-RAG(Self-Reflective Retri…

【YOLOv8改进 - C2f融合】C2f融合DBlock(Decoder Block):解码器块,去模糊和提升图像清晰度

YOLOv8目标检测创新改进与实战案例专栏 专栏目录: YOLOv8有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例 专栏链接: YOLOv8基础解析+创新改进+实战案例 文章目录 YOLOv8目标检测创新改进与实战案例专栏 介绍 摘要 文…

LLamafactory是什么?

LLamaFactory是一个专注于大型语言模型(LLM)训练、微调和部署的开源工具平台,旨在简化大模型的应用开发流程。‌1.核心功能与特点‌LlamaFactory(全称Large Language Model Factory)作为一站式AI开发工具平台&#xff…

Element Plus编辑表格时的页面回显(scope)

1、前提&#xff1a;自定义列模版(把id作为参数&#xff0c;传递到调用的edit函数里)<template #default"scope"><el-button type"primary" size"small" click"edit(scope.row.id)"><el-icon><EditPen /><…

河南萌新联赛2025第四场-河南大学

今天又是坐牢的一次比赛&#xff0c;恭喜获得本次比赛称号&#xff1a;挂机王&#xff0c;一个签到题能卡住两个小时&#xff0c;这两个小时简直坐的我怀疑人生&#xff0c;实在是找不出哪里错了&#xff0c;后来快结束的时候才发现少了一个等于号&#xff0c;也不至于连签到题…

【Excel】通过Index函数向下拖动单元格并【重复引用/循环引用】数据源

文章目录CASE1: 列数据源&#xff0c;向下拖动&#xff0c;每个单元重复N次步骤1&#xff1a;基本的INDEX函数步骤2&#xff1a;添加行号计算步骤3&#xff1a;添加绝对引用以便拖动CASE2:列数据源&#xff0c;向下拖动&#xff0c;每个单元重复1次&#xff0c;周而复始步骤1&a…

潜行者2:切尔诺贝利之心 全DLC 送修改器(S2HOC)免安装中文版

网盘链接&#xff1a; 潜行者2&#xff1a;切尔诺贝利之心 免安装中文版 名称&#xff1a;潜行者2&#xff1a;切尔诺贝利之心 全DLC 送修改器&#xff08;S2HOC&#xff09;免安装中文版 描述&#xff1a; 探索传奇的《潜行者》世界&#xff0c;同时体验&#xff1a; 融合…

系统运维之LiveCD详解

基本概念LiveCD是一个包含完整可运行操作系统的光盘映像&#xff0c;能够在不影响主机系统的情况下启动计算机。工作原理系统从LiveCD介质启动 将必要文件加载到内存中运行 通常使用RAM磁盘作为临时文件系统 关机后所有更改默认不保存&#xff08;除非特别配置&#xff0…

达梦分布式集群DPC_分布式任务执行拆分流程_yxy

达梦分布式集群DPC_分布式执行计划执行拆分流程 1 DPC任务拆分原理 1.1 分布式架构思想 1.2 DPC如何实现任务拆分? 2 DPC任务拆分完整示例 2.1 单表查询 2.1.1 创建分区表,存储在不同BP上 2.1.2 生成sql的最佳执行计划 2.1.3 代码生成并执行、拆分 2.1.3.1 任务拆分步骤 2.1.…

怎么免费建立自己的网站步骤

以下是免费建立个人网站的详细步骤&#xff0c;结合多种方案和工具推荐&#xff1a; 一、零基础快速建站方案 ‌选择免费建站平台‌ PageAdmin CMS‌&#xff1a; 1、提供开源模板&#xff0c;模板可以自定义界面和风格&#xff0c;同时支持原创设计和定制。 2、后台支持自定义…

使用ASIWebPageRequest库编写Objective-C下载器程序

全文目录&#xff1a;开篇语前言为什么选择ASIWebPageRequest&#xff1f;安装ASIWebPageRequest库编写下载器程序1. 导入必要的库2. 创建下载任务3. 设置下载保存路径4. 发起下载请求5. 更新下载进度6. 处理下载完成7. 处理下载失败完整代码示例8. 运行程序总结文末开篇语 哈喽…

mathtype加载项搞崩了word(上)

一、Mathtype更新后word异常 在mathtype更新后&#xff0c;打开word文件时一直报宏的错&#xff1a; 点击“取消”&#xff1a; 点击“确定”&#xff1a; 点击“确定”&#xff1a; 点击“确定”&#xff1a; 还有一堆小弹窗&#xff0c;最后还是能打开word文件&#xff1a; …

算法入门第一篇:算法核心:复杂度分析与数组基础

引言&#xff1a;为什么需要学习算法&#xff1f; 你可能也发现&#xff0c;即使是社招&#xff0c;面试官也时不时会抛出几道算法题&#xff0c;从简单的反转链表到复杂的动态规划。这常常让人感到困惑&#xff1a;我一个做游戏开发的&#xff0c;写好 Unity 的 C# 代码&…

从“听指令”到“当参谋”,阿里云AnalyticDB GraphRAG如何让AI开窍

01、背景 在智能客服与医疗问诊领域&#xff0c;用户模糊描述导致的多轮对话断裂与语义关联缺失&#xff0c;长期阻碍决策效率提升。传统 RAG 技术面临双重困境&#xff1a; 单轮检索局限&#xff1a;当用户仅反馈“空调制冷效果差”、“持续发热三天”等模糊信息时&#xff…

javascript常用实例

常见字符串操作字符串反转const reversed hello.split().reverse().join(); console.log(reversed); // olleh检查回文字符串function isPalindrome(str) {return str str.split().reverse().join(); }数组处理方法数组去重const unique [...new Set([1, 2, 2, 3])]; // [1,…

RK3568下用 Qt Charts 实现曲线数据展示

实际效果: 在工业监控、智能家居等场景中,实时数据可视化是核心需求之一。本文将介绍如何使用 Qt5 的 Charts 模块,快速实现一个支持温度、湿度、大气压和噪声四个参数的实时监测系统,包含曲线动态绘制、坐标轴自适应、多窗口布局等实用功能。 项目背景与目标 环境参数监…

接口自动化测试用例详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快Post接口自动化测试用例Post方式的接口是上传接口&#xff0c;需要对接口头部进行封装&#xff0c;所以没有办法在浏览器下直接调用&#xff0c;但是可以用Curl命令…

JavaEE初阶第十四期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(十二)

专栏&#xff1a;JavaEE初阶起飞计划 个人主页&#xff1a;手握风云 目录 一、JUC的常见类 1.1. Callable接口 1.2. ReentrantLock​ 1.3. 信号量Semaphore 1.4. CountDownLatch 二、线程安全的集合类 2.1. 多线程环境使用 ArrayList​ 2.2. 多线程环境使用哈希表 一、…

什么是RabbitMQ?

什么是RabbitMQ? 一、什么是RabbitMQ? 二、Rabbitmq 的使用场景? 三、RabbitMQ基本概念 四、RabbitMQ的工作模式 1. **简单队列模式(Simple Queue)** 2. **工作队列模式(Work Queue)** 3. **发布/订阅模式(Publish/Subscribe)** 4. **路由模式(Routing)** 5. **主题…