百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

python+爬虫+微信机器人 打造属于你的网购价格监督利器

toyiye 2024-08-16 05:15 9 浏览 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()

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码