python+爬虫+微信机器人 打造属于你的网购价格监督利器
ccwgpt 2024-10-02 12:19 29 浏览 0 评论
写在最前
程序是为人类服务的,最近正好身边小伙伴们在做球衣生意,当然是去nikenba专区购买了,可是有些热门球衣发布几分钟就被抢完,有些折扣球衣也是很快就被抢售一空,那么我们只能靠自己的眼睛一直盯着网站吗?NoNoNo,作为计算机专业的学生,怎么能为这种事情浪费时间呢?那肯定想法就是写爬虫自动比对价格啊,后来又在想,爬虫数据也是在PC端啊,该怎么实时提醒我们呢?再弄一个微信机器人发送数据不就可以了吗?说干就干,代码开撸
先看下效果:
准备工作:
首先本文使用py3,需要安装以下库:
1)itchat
2)requests
3)apscheduler
分析网页:
首先我们需要做什么?毫无疑问,分析网页,因为最重要的一步就是获取数据,那么如何获取数据就是我们首先要克服的困难
附上 nike nba专区地址:https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux
首先我们要明确一个地方,我们的目的是实时监控热门打折球衣,所以我们的价格肯定首先降序排列,不过先不用着急,打开F12先看下调试器,对了我使用的是chrome浏览器
由于我们是先打开网页再打开调试窗口,所以目前我们看不到数据,别急,我们刷新一下再看
哦吼,完蛋,怎么这么多东西貌似根本没法看
别急 继续分析,作为一个学(qiong)生(bi),我们肯定先关注价格了,当然要升序排列啊!
好的 点下浏览器调试窗口中的清除按钮(就是下面这个蓝色标记的按钮)先清除下调试台中的数据 然后呢我们点下筛选方式价格由低到高(红色标记的菜单键中选择)
得到调试台如下,完蛋了还是一堆怎么办?
没关系,至少现在网页内容已经是按照价格升序排列了,我们再来看看得到的Network数据,挨个点一点看看,发现当点到名称为graphql开头的文件里去时候,有东西出现了
里面的响应内容出现了几个熟悉的队名称和球员名称甚至还有价格,等等,这不就是我们要的数据吗?
看来我们找对了地方,我们双击点开graphql开头的网页文件看看会有什么呢? 。。。 看起来杂乱无章,但是貌似确实是我们要的数据,是json格式的
在网页上看json简直是折磨,好的,我们用python开始把这个网页内容给弄下来仔细研究下
pycharm开搞
import requests import json ''' 遇到不懂的问题?Python学习交流群:821460695满足你的需求,资料都已经上传群文件,可以自行下载! ''' #刚刚在调试台得到的地址 url='https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc' #使json数据格式化输出更好观察 def better_jsprint(json_obj): # 使用indent=4 这个参数对json进行数据格式化输出 #因为json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False return json.dumps(json.loads(json_obj),indent=4,ensure_ascii=False) response=requests.get(url) print(better_jsprint(response.text))
看看输出什么:
这样看起来好多了,好的 似乎到这里我们已经可以开始选取我们需要的数据进行记录了,但是我们又会注意到一点,这个网页的内容是瀑布流方式,也就是说滚轮往下滚动才会有更多的数据出现,可是我们目前只获取了这个页面最上端的数据,如果我们想获取更多的数据怎么办?
我们还是使用调试台,其实他页面只要变化,网站交互一定是有活动的,所以我们现在就观察当滚轮往下滚动到瀑布流下端时调试台会出现什么东西就可以了
往下滚动,发现调试台确实出现了很多新的文件,我们猜想这些文件中一定有瀑布流下端的数据,对了还记得我们刚才找到的文件名是什么吗?对的,是名称为graphql开头的文件,那么会不会新的数据文件也是这个名字开头的呢?我们使用调试台搜索下看看
来了来了,它真的出现了,现在出现了3个文件都是graphql名字开头,毫无疑问第一个文件是我们上面找到的,那么第二个第三个呢? 我们点开看看,会发现对应的商品名称之类的真的是瀑布流下端的数据。
OK看起来我们现在确实得到了所有数据文件的url
我最初的想法是直接将3个url写到一个列表中然后使用循环读取如下图(其实会发现第二个url与第三个看起来貌似一样啊怎么回事?下面有解释别急)
后来呢我突然意识到,万一商品更多了怎么办?会不会出现4个5个url?而总不能每次都靠人力去数有多少个url吧?然后就想,怎样才能让程序自动添加url呢?
我们再回头看看第一次抓取下来的 url1 的json数据,首先尝试下检索page这个关键词(毕竟一般程序员都会写这个作为页面标识吧?),哦霍,发现了了不得的东西,
这些数据看起来很眼熟啊,还有uuids?再比对下第一次抓的 url1 发现里面的uuids还真的就是json里面的数据,那么又看到pages里面有个next 纳尼?这会不会是瀑布流下半部分url组成呢?快来比对 url2 地址
https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D24%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc
尝试检索下next中的内容,发现真的存在与endpoint参数后面,哦霍 现在我们猜想,会不会每个json中都包含pages next这个数据
打印url2继续检索pages的next
真的存在,并且还存在prev参数(前一页),说明我们的猜想可能是正确的,这时候细心的小伙伴可能发现了 url2中的next内容与url1中一致啊,哦原来是这样,这样才导致了我们刚刚调试台中出现3个url文件但是第二个与第三个一样的情况
但是我们猜想第三个url返回数据中应该没有next否则就应该出现第四个文件了,我们来试一试
在url3返回数据中检索next
真的为空了所以我们可以确定,只要瀑布流下方仍有数据,那么一定存在next参数 因此我们可以确定瀑布流url写法 我们网页分析完成 接下来就要进行真正的代码编写了
(其实我有一个疑问 url2与url3看起来确实是一模一样的并且我尝试做了差值运算,发现还是一样的,但是返回数据确实不同,有大神可以发现这两个url不同之处吗 下面放上这两个url)
(url已改变,根据官网实时更新数据一直在变)
url2='https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D24%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc' url3='https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=%2Fproduct_feed%2Frollup_threads%2Fv2%3Ffilter%3Dmarketplace(CN)%26filter%3Dlanguage(zh-Hans)%26filter%3DemployeePrice(true)%26filter%3DattributeIds(1c7c3d67-5d46-432d-9910-b1128d1b6503%2Ce09eabe9-5ff0-42af-b0a3-5f68af19d89a)%26anchor%3D48%26count%3D24%26consumerChannelId%3Dd9a5bc42-4b9c-4976-858a-f159cf99c647%26sort%3DproductInfo.merchPrice.currentPriceAsc'
urls构建与objects获取
我们首先需要写递归函数获取所有urls
我们观察json内容就会发现我们需要的商品数据都在一个名为objects的key中 因此需要将所有objects放在一起
递归函数(核心函数)如下
#刚刚在调试台得到的初始地址 url1='https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc' ''' 遇到不懂的问题?Python学习交流群:821460695满足你的需求,资料都已经上传群文件,可以自行下载! ''' #观察其他urls发现前面参数是一样的如下 我们先写前半部分 urlother='https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=' urls=[url1] #空list存放物品信息 观察发现json中的objects数据类型为list pricedictlist=[] #递归函数得到urls列表以及每个url中物品数据 def get_url_objcts(url=url1): #首先得到初始url的json数据 response=requests.get(url) #只取有用的数据内容 仔细观察json数据 得到下一个页面的next参数 #urllib.parse.quote(text) # 按照标准, URL 只允许一部分 ASCII 字符(数字字母和部分符号),其他的字符(如汉字)是不符合 URL 标准的。 # 所以 URL 中使用其他字符就需要进行 URL 编码。 try: nextpage_json=quote(response.json()['data']['filteredProductsWithContext']['pages']['next']) #添加objects内容到列表 pricedictlist.extend(response.json()['data']['filteredProductsWithContext']['objects']) except KeyError: nextpage_json = quote(response.json()['data']['products']['pages']['next']) # 添加objects内容到列表 pricedictlist.extend(response.json()['data']['products']['objects']) except TypeError: nextpage_json='' #递归获取url与objects if nextpage_json!='': urlnext=urlother+nextpage_json urls.append(urlnext) nextpage_json='' get_url_objcts(urlnext) #else只在不存在下一页时执行,相当于此时已经完成了objects的获取 下面构建发送信息 else: i = 0 STR = str('https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux?sort=priceAsc') compStr1 = '' for each in pricedictlist: title = each['publishedContent']['properties']['seo'] if title == None: continue currentPrice = each['productInfo'][0]['merchPrice']['currentPrice'] fullPrice = each['productInfo'][0]['merchPrice']['fullPrice'] #只选取有用的数据 我们不要童装 同时只要打折商品 if (not re.search('童', str(title['slug']))) and (fullPrice != currentPrice): i = i + 1 STR = STR + '\n\n' + ((str(title['slug']) + "\n" + " 原价" + str(fullPrice) + " 现价" + str( currentPrice)) + ' ' + str(currentPrice * 100 / fullPrice) + '%') #发现每个商品名称后面都有独特的商品码为6个字母标识,所以切片记录下来用于对比 compStr1 = compStr1 + str(title['slug'][-6:]) STR = STR + '\n' + ("本次数据一共:" + str(i) + "个")
这之上 我们已经完成了数据的获取,接下来就是微信机器人发送了
itchat微信机器人
itchat是个人账户的开放源码wechat api项目,它使您可以通过命令行访问您的个人微信帐户。
如何向群发送消息?
import itchat #登录微信网页版 参数enableCmdQR=0会出现图片二维码登录 为1则命令行窗口输出字符二维码 有的linux因为字符间距问题需要设置为2 itchat.auto_login(hotReload=0,enableCmdQR=0) # 自己创建微信群,名称自定,并且要保存到通信录 chatroomName = 'Money' # 群名 itchat.get_chatrooms(update=True) chatrooms = itchat.search_chatrooms(name=chatroomName) # print(compStr0) if len(chatrooms) == 0: # print('没有找到群聊:' + chatroomName) exit(0) else: itchat.send_msg('hello world', toUserName=chatrooms[0]['UserName']) # 发送消息
这就是简单的发送消息了,将我们上面的程序接合就可以实现微信发送了 还差一步,没错就是定时任务的问题
Python定时任务框架apscheduler
听名字就知道是干什么的 没错就是任务调度,我们可以使用这个库简洁的实现任务调度问题
简单例程如下:
from apscheduler.schedulers.blocking import BlockingScheduler import time scheduler = BlockingScheduler() def job1(): print ("%s: 执行任务" % time.asctime()) scheduler.add_job(job1, 'interval', seconds=3) scheduler.start()
输出:
Mon Aug 19 18:35:52 2019: 执行任务 Mon Aug 19 18:35:55 2019: 执行任务 Mon Aug 19 18:35:58 2019: 执行任务 Mon Aug 19 18:36:01 2019: 执行任务 Mon Aug 19 18:36:04 2019: 执行任务 Mon Aug 19 18:36:07 2019: 执行任务 Mon Aug 19 18:36:10 2019: 执行任务
最后一步就是将上面讲的所有来一个大集合
程序送上~:
将环境配置好,直接放在自己的服务器就可以运行了,这一步就不再赘述
import re import requests from urllib.parse import quote import itchat from datetime import datetime from apscheduler.schedulers.blocking import BlockingScheduler ''' 遇到不懂的问题?Python学习交流群:821460695满足你的需求,资料都已经上传群文件,可以自行下载! ''' #登录微信网页版 参数enableCmdQR=0会出现图片二维码登录 为1则命令行窗口输出字符二维码 有的linux因为字符间距问题需要设置为2 itchat.auto_login(hotReload=0,enableCmdQR=2) #比较字符串,用于判断是否更新数据 compStr0='fuckkkkkkkkkkkkkkkk' def main(): #刚刚在调试台得到的初始地址 url1='https://www.nike.com/w/graphql?queryid=filteredProductsWithContext&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&uuids=1c7c3d67-5d46-432d-9910-b1128d1b6503,e09eabe9-5ff0-42af-b0a3-5f68af19d89a&language=zh-Hans&country=CN&sortBy=priceAsc' #观察其他urls发现前面参数是一样的如下 我们先写前半部分 urlother='https://www.nike.com/w/graphql?queryid=products&anonymousId=A54CD5202A87B54B4415AD4BC11E5692&endpoint=' urls=[url1] #空list存放物品信息 观察发现json中的objects数据类型为list pricedictlist=[] #递归函数得到urls列表以及每个url中物品数据 def get_url_objcts(url=url1): #首先得到初始url的json数据 response=requests.get(url) #只取有用的数据内容 仔细观察json数据 得到下一个页面的next参数 #urllib.parse.quote(text) # 按照标准, URL 只允许一部分 ASCII 字符(数字字母和部分符号),其他的字符(如汉字)是不符合 URL 标准的。 # 所以 URL 中使用其他字符就需要进行 URL 编码。 try: nextpage_json=quote(response.json()['data']['filteredProductsWithContext']['pages']['next']) pricedictlist.extend(response.json()['data']['filteredProductsWithContext']['objects']) except KeyError: nextpage_json = quote(response.json()['data']['products']['pages']['next']) pricedictlist.extend(response.json()['data']['products']['objects']) except TypeError: nextpage_json='' #递归获取url与objects if nextpage_json!='': urlnext=urlother+nextpage_json urls.append(urlnext) nextpage_json='' get_url_objcts(urlnext) #else只在不存在下一页时执行,相当于此时已经完成了objects的获取 else: i = 0 STR = str('https://www.nike.com/cn/w/nba-sleeveless-and-tank-tops-18iwiz9sbux?sort=priceAsc') compStr1 = '' for each in pricedictlist: title = each['publishedContent']['properties']['seo'] if title == None: continue currentPrice = each['productInfo'][0]['merchPrice']['currentPrice'] fullPrice = each['productInfo'][0]['merchPrice']['fullPrice'] #只选取有用的数据 我们不要童装 同时只要打折商品 if (not re.search('童', str(title['slug']))) and (fullPrice != currentPrice): i = i + 1 STR = STR + '\n\n' + ((str(title['slug']) + "\n" + " 原价" + str(fullPrice) + " 现价" + str( currentPrice)) + ' ' + str(currentPrice * 100 / fullPrice) + '%') #发现每个商品名称后面都有独特的商品码为6个字母标识,所以切片记录下来用于对比 compStr1 = compStr1 + str(title['slug'][-6:]) STR = STR + '\n' + ("本次数据一共:" + str(i) + "个") #自己创建微信群,名称自定 chatroomName = 'Money' # 群名 itchat.get_chatrooms(update=True) chatrooms = itchat.search_chatrooms(name=chatroomName) global compStr0 # print(compStr0) if len(chatrooms) == 0: # print('没有找到群聊:' + chatroomName) exit(0) else: #判断数据是否变化 if (compStr1 != compStr0): itchat.send_msg(STR, toUserName=chatrooms[0]['UserName']) # 发送消息 compStr0 = compStr1 # print(compStr0) get_url_objcts() sched = BlockingScheduler() # 任务调度 每2分钟触发 时间自定 sched.add_job(main, 'interval', minutes=2, next_run_time=datetime.now()) sched.start() itchat.run()
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)