小程序项目思路分享爬虫

小程序项目思路分享爬虫

具体需求:
 有这几个就行,门店名称+门店地址+门店类型,再加上省、市、县/区

在这里插入图片描述

门店名称:storeName

门店地址:storeAddress

程序运行:

honor_spider获取经纬度信息。

经纬度——>详细店铺接口

这是荣耀店铺接口数据,请求参数带有省/市的经纬度信息。返回响应数据是省、市下的行政区划荣耀店铺信息

https://retail.hihonor.com/isrp/sms/online/store-info/getTargetStore/hi-honor
curl
curl -H 'Host: retail.hihonor.com' -H 'appsource: wxapp' -H 'x-from: wxapp' -H 'charset: utf-8' -H 'x-appname: wxapp' -H 'user-agent: Mozilla/5.0 (Linux; Android 13; Mi 10 Build/TKQ1.221114.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 XWEB/1160117 MMWEBSDK/20240301 MMWEBID/291 MicroMessenger/8.0.48.2580(0x2800303D) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android' -H 'x-user-token: ' -H 'content-type: application/json' -H 'x-access-token: ' -H 'referer: https://servicewechat.com/wxde6bc80b07638016/409/page-frame.html' --data-binary '{"coordinateType":"2","longitude":116.31188232421874,"latitude":40.03590304904514,"isGetTargetStore":true,"operatingStatus":1,"isCheckSpu":true,"range":50000,"enableWechatApplet":1}' --compressed 'https://retail.hihonor.com/isrp/sms/online/store-info/getTargetStore/hi-honor'
接口特点:

接口只返回省市下的店铺信息,而不返回区级及以下的店铺信息。所以要提取行政区划信息,要对店铺地址写正则表达式提取。

代码:
import requests
import json

headers = {
    "Host": "retail.hihonor.com",
    "appsource": "wxapp",
    "x-from": "wxapp",
    "charset": "utf-8",
    "x-appname": "wxapp",
    "user-agent": "Mozilla/5.0 (Linux; Android 13; Mi 10 Build/TKQ1.221114.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 XWEB/1160117 MMWEBSDK/20240301 MMWEBID/291 MicroMessenger/8.0.48.2580(0x2800303D) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android",
  
}
url = "https://retail.hihonor.com/isrp/sms/online/store-info/getTargetStore/hi-honor"
data = {
    "coordinateType": "2",
    "longitude": 114.571090,
    "latitude": 38.146190,
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, data=data)

# 解析响应数据
response_data = response.json()  # 使用.json()方法直接解析JSON响应数据

# 提取storeName和storeAddress字段
if response_data['status'] == 'success' and 'result' in response_data:
    for store in response_data['result']:
        store_name = store.get('storeName')  # 使用get方法避免KeyError
        store_address = store.get('storeAddress')  # 使用get方法避免KeyError
        print('店铺名称:', store_name)
        print('店铺地址:', store_address)
else:
    print('请求失败或响应数据格式不正确')
结果

在这里插入图片描述

创建scrapy:scrapy startproject miniprogram

创建爬虫:scrapy genspider honor

省市——>经纬度接口
url = 'https://apis.map.qq.com/jsapi?qt=geoc&addr={}&output=jsonp&pf=jsapi&ref=jsapi&cb=qq.maps._svcb3.geocoder0'.format(name)
    

请求参数是省市名称,返回的数据是经纬度信息,这里我调用的是开源的腾讯地图api接口。

爬取直辖市
        province_data = {'北京市': 'CN-11', '天津市': 'CN-12', '河北省': 'CN-13', '山西省': 'CN-14',
                         '内蒙古自治区': 'CN-15', '辽宁省': 'CN-21', '吉林省': 'CN-22', '黑龙江省': 'CN-23',
                         '上海市': 'CN-31', '江苏省': 'CN-32', '浙江省': 'CN-33', '安徽省': 'CN-34', '福建省': 'CN-35',
                         '江西省': 'CN-36', '山东省': 'CN-37', '河南省': 'CN-41', '湖北省': 'CN-42', '湖南省': 'CN-43',
                         '广东省': 'CN-44', '广西壮族自治区': 'CN-45', '海南省': 'CN-46', '重庆市': 'CN-50',
                         '四川省': 'CN-51', '贵州省': 'CN-52', '云南省': 'CN-53', '西藏自治区': 'CN-54',
                         '陕西省': 'CN-61', '甘肃省': 'CN-62', '青海省': 'CN-63', '宁夏回族自治区': 'CN-64',
                         '新疆维吾尔自治区': 'CN-65'}
请求测试逻辑
# import requests
# import json
# import re
#
# # 假设您已经定义了get_proxies方法,如果没有,您可以将proxies参数从下面的请求中移除
# def get_proxies():
#     # 返回代理服务器的配置,例如:
#     
#     # 如果您不使用代理,可以返回None或者直接在请求中移除proxies参数
#     return None
#
# # 坐标
# def zb(name):  # name是区名
#     print('爬取坐标')
#     url = 'https://apis.map.qq.com/jsapi?qt=geoc&addr={}&output=jsonp&pf=jsapi&ref=jsapi&cb=qq.maps._svcb3.geocoder0'.format(name)
#     headers = {
#         "user-agent": '
#     }
#     try:
#         response = requests.get(url=url, headers=headers, proxies=get_proxies(), timeout=7)
#         html = response.text
#         if html[-1] != ';':
#             html = html + ';'
#
#         html = html.replace('\n', '').replace('\t', '').replace('\r', '')
#         html = re.findall('\({(.*?)\);', html)[0]
#         html = json.loads('{' + html)
#         return html
#     except Exception as e:
#         print('获取坐标错误', name, '重试!')
#         print(e)
#         return zb(name)
#
# # 测试代码
# if __name__ == "__main__":
#     test_name = "北京市"  # 测试用的区名,可以更换为其他区名。用provinceName
#     result = zb(test_name)
#     print(json.dumps(result, indent=4, ensure_ascii=False))  

import requests
import json
import re
from connRedis import OPRedis

# 假设您已经定义了get_proxies方法,如果没有,您可以将proxies参数从下面的请求中移除
# def get_proxies():
#如需调用,自行配置,这里我删除了。
#        proxies = {
        "http": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": tid, "pwd": password, "proxy": proxy_ip},
        "https": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": tid, "pwd": password, "proxy": proxy_ip}
    }

    return proxies

# 坐标
def zb(name):  # name是区名
    print('爬取坐标')
    url = 'https://apis.map.qq.com/jsapi?qt=geoc&addr={}&output=jsonp&pf=jsapi&ref=jsapi&cb=qq.maps._svcb3.geocoder0'.format(name)
    headers = {
        "user-agent": 
    }
    try:
        response = requests.get(url=url, headers=headers, proxies=get_proxies(), timeout=7)
        html = response.text
        if html[-1] != ';':
            html = html + ';'

        html = html.replace('\n', '').replace('\t', '').replace('\r', '')
        jsonp_str = re.findall('\((.*?)\);', html)[0]  # 提取JSONP响应中的JSON部分
        json_data = json.loads(jsonp_str)  # 将JSON字符串转换为字典
        pointx = json_data['detail']['pointx']
        pointy = json_data['detail']['pointy']
        return {'pointx': pointx, 'pointy': pointy}  # 返回经纬度的值
    except Exception as e:
        print('获取坐标错误', name, '重试!')
        print(e)
        return zb(name)

# 测试代码
if __name__ == "__main__":
    test_name = "正定县"  # 测试用的区名,可以更换为其他区名
    coordinates = zb(test_name)
    print('经度:', coordinates['pointx'])
    print('纬度:', coordinates['pointy'])
返回数据

在这里插入图片描述

import requests
import json


headers = {
    "Host": "retail.hihonor.com",
    "appsource": "wxapp",
    "x-from": "wxapp",
    "charset": "utf-8",
    "x-appname": "wxapp",
    "user-agent": 
    "x-user-token": "",
    "content-type": "application/json",
    "x-access-token": "",
    "referer": "https://servicewechat.com/wxde6bc80b07638016/409/page-frame.html"
}
url = "https://retail.hihonor.com/isrp/sms/online/store-info/getTargetStore/hi-honor"
data = {
    "coordinateType": "2",
    "longitude": 116.231280,
    "latitude": 40.220770,
    "isGetTargetStore": True,
    "operatingStatus": 1,
    "isCheckSpu": True,
    "range": 50000,
    "enableWechatApplet": 1
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, data=data)

print(response.text)
print(response)

帮我提取出这段代码中的
问题
1.获取某些省,位置坐标报错

在这里插入图片描述

只能获取市级单位的经纬坐标

可见从头开始做测试的重要性,切忌想当然!!

2.代理不稳定,要重复请求
石家庄市

在这里插入图片描述

省——>市接口
"https://ccpce-cn.consumer.huawei.com/ccpcmd/services/dispatch/secured/CCPC/EN/ccpc/queryRegionList/1000"

这个接口比较特殊,是在华为消费者官网上找到的接口,通过这个接口。可以直接将省下面的市名列表获取到。这样就不用单独建数据库表了,直接调用就好了。这里注明来源,防止之后失效。

代码
# 获取下一级,省->市->区/县->
def get_next_level(code, level):#返回的是市级的数据,不要区县
    headers = {
        "Accept": "*/*",
        "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
        "Connection": "keep-alive",
        "Referer": "https://consumer.huawei.com/",
        "Sec-Fetch-Dest": "script",
        "Sec-Fetch-Mode": "no-cors",
        "Sec-Fetch-Site": "same-site",
        "User-Agent": 
        "sec-ch-ua": "^\\^Not",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "^\\^Windows^^"
    }

    cookies = {
    }
    url = "https://ccpce-cn.consumer.huawei.com/ccpcmd/services/dispatch/secured/CCPC/EN/ccpc/queryRegionList/1000"
    params = {
        "jsonp": "jQuery36205836021093286132_{}".format(int(time.time() * 1000)),  # 使用当前时间戳,
        "countryCode": "CN",
        "lang": "zh-cn",
        "parent_alpha_2_code": code,
        "scopeGrade": level,
        "curpage": "1",
        "pagesize": "1000",
        "_": int(time.time() * 1000)
    }

    # 初始化重试次数
    max_retries = 3
    attempts = 0

    while attempts < max_retries:
        try:
            response = requests.get(url=url, headers=headers, cookies=cookies, params=params, proxies=get_proxies(), timeout=7)
            html = response.text
            # print(html)
            # 确保返回的JavaScript响应以分号结尾
            if html[-1] != ';':
                html = html + ';'
            # 使用正则表达式提取JSONP响应中的JSON数据
            html = re.findall('\({(.*?)\);', html)[0]
            # 将提取的JSON字符串转换为Python字典
            html = json.loads('{' + html)
            # 初始化一个空列表,用于存储解析后的数据
            datas = []
            # 遍历响应数据中的list部分,将每一项数据添加到datas列表中
            for data in html['responseData']['list']:
                datas.append(data)
                # print('打印响应数据')
                # print('----------------------------------------')
                # print(datas)
            # 返回解析后的数据列表
            return datas
        except Exception as e:
            print('获取下一级错误', code, '返回空数组!')
            print('异常类型:', type(e).__name__)
            print('异常信息:', e)

            # 如果尝试次数达到最大重试次数,则返回空数组
            if attempts == max_retries:
                print('已达到最大尝试次数,返回空数组!')
                return []
            # 短暂休眠后再次尝试
            time.sleep(2)


# if __name__ == '__main__':
#         data = get_next_level("CN-36","city")#逻辑是如果是省调用这个接口
# 主函数
if __name__ == '__main__':
    # 遍历province_data中的每个省份
    for province_name, province_code in province_data.items():
        # 如果省份名称以"市"结尾,跳过直辖市,因为直辖市不需要获取下级市
        if province_name.endswith('市'):
            continue
        # 获取省份下的市级数据
        city_data = get_next_level(province_code, "city")
        # 市数量计数
        city_count = len(city_data)
        # # 初始化市名列表
        # city_names = [city['regionName'] for city in city_data]
        # city_names = [item['multi_lang_name'] for item in city_data['responseData']['list']]

        city_names = [item['multi_lang_name'] for item in city_data]# 打印省份名称,市的个数和市名列表
        print(f'省份名称: {province_name}')
        print(f'市的个数: {city_count}')
        print(f'包含的市名列表: {city_names}')
        print('----------------------------------------')
结果

在这里插入图片描述

代码优化:

写成了面向对象,有需要的可以后台call我。

之后如果客户有其他小程序的需求,还需要用scrapy框架进行分布式爬取数据

封装成scrapy框架
scrapy genspider honor consumer.huawei.com
实例:Scrapy框架请求逻辑
import scrapy
import json
import re
import time
from connRedis import OPRedis

class RegionSpider(scrapy.Spider):
    name = 'region_spider'
    allowed_domains = ['consumer.huawei.com']
    province_data = {
        # ... 省略其他省份数据 ...
        '江西省': 'CN-36',
        # ... 省略其他省份数据 ...
    }

    def start_requests(self):
        for province_name, province_code in self.province_data.items():
            if province_name.endswith('市'):
                continue
            yield scrapy.Request(
                url=self.get_url(province_code, "city"),
                callback=self.parse_city,
                meta={'province_name': province_name, 'province_code': province_code},
                cookies=self.get_cookies(),
                headers=self.get_headers()
            )

    def parse_city(self, response):
        province_name = response.meta['province_name']
        province_code = response.meta['province_code']
        try:
            jsonp_string = response.text
            json_string = re.findall(r'\((.*?)\);', jsonp_string)[0]
            data = json.loads(json_string)
            city_data = data['responseData']['list']
            city_count = len(city_data)
            city_names = [item['multi_lang_name'] for item in city_data]
            print(f'省份名称: {province_name}')
            print(f'市的个数: {city_count}')
            print(f'包含的市名列表: {city_names}')
        except Exception as e:
            self.logger.error(f'解析错误: {e}, 省份代码: {province_code}')

    def get_url(self, code, level):
        timestamp = int(time.time() * 1000)
        return f"https://ccpce-cn.consumer.huawei.com/ccpcmd/services/dispatch/secured/CCPC/EN/ccpc/queryRegionList/1000?jsonp=jQuery36205836021093286132_{timestamp}&countryCode=CN&lang=zh-cn&parent_alpha_2_code={code}&scopeGrade={level}&curpage=1&pagesize=1000&_={timestamp}"

    def get_cookies(self):
        return {
            # ... 省略其他cookies ...
            "JSESSIONID": "F78B38998A33F9B74DE0077819BF987E603F6C1FC1AC1005",
            # ... 省略其他cookies ...
        }

    def get_headers(self):
        return {
          
            "Accept": "*/*",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
  
        }

代码用法

Scrapy爬虫类中,start_requests方法生成初始请求,parse_city方法解析响应并打印结果。get_urlget_cookiesget_headersget_proxies方法用于构建请求的URL、Cookies、Headers和代理。

在这里connRedis的模块和OPRedis的类是代理中间件。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

selenium添加代理(有账号密码)

以下为各种尝试的记录&#xff0c;正确实现可直接参考最后一条&#xff01; 1&#xff0c;导入Proxy库来添加capabilities属性&#xff1a;可以访问网站&#xff0c;但ip还是本机ip from selenium import webdriver from selenium.webdriver.chrome.options import Options f…

雪亮工程视频汇聚EasyCVR视频建设方案:当前现状与痛点分析

一、现状分析与痛点 经过近几年的努力&#xff0c;平安城市雪亮工程建设取得了显著的成绩&#xff0c;完成了前端高清视频点位和高清卡口系统建设&#xff0c;建成了视频监控类、卡口类和应用类的平台。这些系统的建设在提高城市公共事业和社会治安动态管理方面发挥了积极作用…

uniapp 上传视频到阿里云之后回显视频获取视频封面

uniapp 上传视频到阿里云之后回显视频获取视频封面 官网的解决方案 1.initial-time Number 指定视频初始播放位置&#xff0c;单位为秒&#xff08;s&#xff09;。 没什么卵用 2.使用 uni.createVideoContext(“myVideo”, this).seek(number)。 没什么卵用 <video :id&quo…

Python | Leetcode Python题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; class Solution:def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:dummy ListNode(0, head)first headsecond dummyfor i in range(n):first first.nextwhile first:first first.nextsecond second.nextsecond.ne…

C语言 函数——断言与防御式编程

目录 如何确定假设的真假&#xff1f; 断言 防御式编程&#xff08;Defensive programming&#xff09; 如何确定假设的真假&#xff1f; 程序中的假设 *某个特定点的某个表达式的值一定为真 *某个特定点的某个表达式的值一定位于某个区间等 问题&#xff1a;如何确定这些…

test4111

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

ExoPlayer停止更新,建议升级到AndroidX Media3

1. 大家常用的ExoPlayer地址&#xff1a;GitHub - google/ExoPlayer: An extensible media player for Android ExoPlayer是谷歌官方提供的媒体播放库&#xff0c;大家在开发项目中经常使用ExoPlayer播放音视频&#xff0c;谷歌官方已经明确表示该库在2024-04-03停止更新&…

Linux(CentOS7)安装 Docker 以及 Docker 基本使用教程

目录 安装 基础依赖 安装 docker 开机自启 启动 docker 配置国内镜像源 使用教程 帮助命令 镜像命令 容器命令 容器终端 构建镜像 安装 基础依赖 如果直接安装 docker 时报错&#xff0c;提示缺少依赖&#xff0c;则根据提示将前置依赖安装即可&#xff0c;这里直…

Savitzky-Golay滤波器基本原理

本文介绍Savitzky-Golay滤波器基本原理。 Savitzky-Golay滤波器&#xff08;简称为S-G滤波器&#xff09;被广泛地运用于数据平滑去噪&#xff0c;它是一种在时域内基于局域多项式最小二乘法拟合的滤波方法。这种滤波器最大的特点在于在滤除噪声的同时确保信号的形状&#xff…

MT3020 任务分配

思路&#xff1a;利用二分找到某个时间是满足“k个人可以完成” &#xff0c;并且时间最小。 因为尽量让后面的人做任务&#xff0c;所以从后往前排任务&#xff08;倒着分配&#xff09;。从后往前遍历任务&#xff0c;如果此人加上这个任务超出之前求得的时间&#xff0c;就…

Qt5中使用QPrinter和QprintDialog类

学习Qt过程中&#xff0c;做一个简单的编辑器&#xff0c;其中需要使用到打印文本功能&#xff0c;在使用Qt printer时遇到了几个麻烦。 一、在使用到QPrinter和QprintDialog类时的附加处理 ①若是在qt creator中&#xff0c;需要在 &#xff08;.pro&#xff09;工程文件中加…

inner join和left semi join的联系和区别

参考&#xff1a;添加链接描述 添加链接描述 1 简介 LEFT SEMI JOIN &#xff08;左半连接&#xff09;是 IN/EXISTS 子查询的一种更高效的实现。 示例 可以改写为 2 特点 1、left semi join 的限制是&#xff0c; JOIN 子句中右边的表只能在 ON 子句中设置过滤条件&…

Python学习从0开始——项目一day01爬虫

Python学习从0开始——项目一day01爬虫 一、导入代码二、使用的核心库三、功能测试3.1初始代码3.2新建文件3.3代码调试 四、页面元素解析4.1网页4.2修改代码4.3子页面4.4修改代码 一、导入代码 在Inscode新建一个python类型的项目&#xff0c;然后打开终端&#xff0c;粘贴以下…

[通俗易懂]《动手学强化学习》学习笔记2-第2、3、4章

文章目录 前言小总结&#xff08;前文回顾&#xff09;第二章 多臂老虎机2.2.2形式化描述 第三章 马尔可夫决策过程3.6 占用度量 代码3.6 占用度量 定理2 第四章 动态规划算法4.3.3 策略迭代算法 代码 总结 前言 参考&#xff1a; 《动手学强化学习》作者&#xff1a;张伟楠&a…

使用 Docker 部署 Open-Resume 在线简历平台

1&#xff09;Open-Resume 介绍 GitHub&#xff1a; https://github.com/xitanggg/open-resume Open-Resume 是一款功能强大的开源 简历生成器 和 简历解析器 。可以帮助我们快速的生成个人简历&#xff0c;并定制化不同的主题和布局风格。该项目的目标是为每个人提供免费的现…

Harmony鸿蒙南向驱动开发-UART

UART指异步收发传输器&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;&#xff0c;是通用串行数据总线&#xff0c;用于异步通信。该总线双向通信&#xff0c;可以实现全双工传输。 两个UART设备的连接示意图如下&#xff0c;UART与其他模块一般用2线&a…

算法打卡day42|动态规划篇10| Leetcode 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

算法题 Leetcode 121. 买卖股票的最佳时机 题目链接:121. 买卖股票的最佳时机 大佬视频讲解&#xff1a;121. 买卖股票的最佳时机视频讲解 个人思路 这道题之前贪心算法做过&#xff0c;当然动规也能解决这道题 解法 贪心法 取最左最小值&#xff0c;取最右最大值&#x…

CSS设置首字母大小写和首行样式

一、首字母大小写 1.代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title&…

顺序表(增删减改)+通讯录项目(数据结构)

什么是顺序表 顺序表和数组的区别 顺序表本质就是数组 结构体初阶进阶 系统化的学习-CSDN博客 简单解释一下&#xff0c;就像大家去吃饭&#xff0c;然后左边是苍蝇馆子&#xff0c;右边是修饰过的苍蝇馆子&#xff0c;但是那个好看的苍蝇馆子一看&#xff0c;这不行啊&a…

校园论坛系统

文章目录 校园论坛系统一、项目演示二、项目介绍三、10000字论文参考四、系统部分功能截图五、部分代码展示六、底部获取项目和10000字论文参考&#xff08;9.9&#xffe5;&#xff09; 校园论坛系统 一、项目演示 校园论坛系统 二、项目介绍 基于springbootvue的前后端分离…
最新文章