你的网购价格监督利器——python+爬虫+微信机器人
前言
文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。
作者:风,又奈何
PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http://t.cn/A6Zvjdun
准备工作:
首先本文使用py3,需要安装以下库:
1)itchat
2)requests
3)apscheduler
分析网页:
首先我们需要做什么?毫无疑问,分析网页,因为最重要的一步就是获取数据,那么如何获取数据就是我们首先要克服的困难
首先我们要明确一个地方,我们的目的是实时监控热门打折球衣,所以我们的价格肯定首先降序排列,不过先不用着急,打开F12先看下调试器,对了我使用的是chrome浏览器
由于我们是先打开网页再打开调试窗口,所以目前我们看不到数据,别急,我们刷新一下再看
哦吼,完蛋,怎么这么多东西貌似根本没法看
别急 继续分析,作为一个学(qiong)生(bi),我们肯定先关注价格了,当然要升序排列啊!
好的 点下浏览器调试窗口中的清除按钮(就是下面这个蓝色标记的按钮)先清除下调试台中的数据 然后呢我们点下筛选方式价格由低到高(红色标记的菜单键中选择)
得到调试台如下,完蛋了还是一堆怎么办?
没关系,至少现在网页内容已经是按照价格升序排列了,我们再来看看得到的Network数据,挨个点一点看看,发现当点到名称为graphql开头的文件里去时候,有东西出现了
里面的响应内容出现了几个熟悉的队名称和球员名称甚至还有价格,等等,这不就是我们要的数据吗?
看来我们找对了地方,我们双击点开graphql开头的网页文件看看会有什么呢? 。。。 看起来杂乱无章,但是貌似确实是我们要的数据,是json格式的
在网页上看json简直是折磨,好的,我们用python开始把这个网页内容给弄下来仔细研究下
pycharm开搞
import requests
import json
#刚刚在调试台得到的地址
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 地址
尝试检索下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已改变,根据官网实时更新数据一直在变)
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'
#观察其他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
听名字就知道是干什么的 没错就是任务调度,我们可以使用这个库简洁的实现任务调度问题
简单例程如下:
程序送上~:
将环境配置好,直接放在自己的服务器就可以运行了,这一步就不再赘述
import re
import requests
from urllib.parse import quote
import itchat
from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
#登录微信网页版 参数enableCmdQR=0会出现图片二维码登录 为1则命令行窗口输出字符二维码 有的linux因为字符间距问题需要设置为2
itchatauto_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的应用,可以私信小编
你的网购价格监督利器——python+爬虫+微信机器人的更多相关文章
- python+爬虫+微信机器人 打造属于你的网购价格监督利器
写在最前 程序是为人类服务的,最近正好身边小伙伴们在做球衣生意,当然是去nikenba专区购买了,可是有些热门球衣发布几分钟就被抢完,有些折扣球衣也是很快就被抢售一空,那么我们只能靠自己的眼睛一直盯着 ...
- Python创建微信机器人
微信,一个日活10亿的超级app,不仅在国内社交独领风骚,在国外社交也同样占有一席之地,今天我们要将便是如何用Python来生成一个微信机器人,突然想起鲁迅先生曾经说过的一句话:因为是微信机器人系列的 ...
- Python自制微信机器人:群发消息、自动接收好友
运营公众号也有半年了,今年5月份开始的,之前一直用一款windows工具来运营自动接受好友请求.群发文章.自动回复等操作,但颇有不便. 举几个场景: 突然在外面看到一篇文章很好,临时写了一篇,想群发一 ...
- 用python自制微信机器人,定时发送天气预报
0 引言 前段时间找到了一个免费的天气预报API,费了好段时间把这个API解析并组装成自己想用的格式了,就想着如何实现每天发送天气信息给自己.最近无意中发现了wxpy库,用它来做再合适不过了.以下是w ...
- python爬虫利器Selenium使用详解
简介: 用pyhon爬取动态页面时普通的urllib2无法实现,例如下面的京东首页,随着滚动条的下拉会加载新的内容,而urllib2就无法抓取这些内容,此时就需要今天的主角selenium. Sele ...
- (转)Python爬虫利器一之Requests库的用法
官方文档 以下内容大多来自于官方文档,本文进行了一些修改和总结.要了解更多可以参考 官方文档 安装 利用 pip 安装 $ pip install requests 或者利用 easy_install ...
- Python 爬虫利器 Selenium 介绍
Python 爬虫利器 Selenium 介绍 转 https://mp.weixin.qq.com/s/YJGjZkUejEos_yJ1ukp5kw 前面几节,我们学习了用 requests 构造页 ...
- Python爬虫利器二之Beautiful Soup的用法
上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Be ...
- python 爬虫利器 Beautiful Soup
python 爬虫利器 Beautiful Soup Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文 ...
随机推荐
- Django之Cookie,Session
COOKIE Cookie的由来 大家都知道HTTP协议是无状态的. 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不 ...
- 题解 P3205 【[HNOI2010]合唱队】
讲讲我的做法 看了题目发现要用区间\(dp\),为什么? 我们发现区间\(dp\)有一个性质--大区间包涵小区间,这道题就符合这样的一个性质 所以我们要用区间\(dp\)来解决这道题. 如何设计状态 ...
- 题解 P4302 【[SCOI2003]字符串折叠】
讲讲我的做法 题目大意:对一个字符串进行折叠是它长度最小 看一眼数据范围:哇!字符串长度不超过100!这是一道省选题,不可能给你太宽裕的时限,所以,题目基本暗示你要用\(n^{3}\)多一些的算法复杂 ...
- 【HDU2883】kebab——最大流
题目链接 把"时间粒子"作为最大流的计算结果 设置超级源点为 0 顾客点范围为 1 - 204 时间点 205 - 610 超级汇点 615 超级源点与所有顾客连线,容量为需求的烤 ...
- flume面试题
1 你是如何实现Flume数据传输的监控的使用第三方框架Ganglia实时监控Flume. 2 Flume的Source,Sink,Channel的作用?你们Source是什么类型?1.作用 (1)S ...
- Qt 的信号与槽(纯干货)
接触Qt断断续续有些时间了,总看了一堆的文章说信号槽的概念,心里就想骂人,做为一个初学者,最重要的就是怎么写代码,写代码写多了,再去看理论,有时水到渠成的就明白那些理论了.但所有讲信号槽的都把一堆信号 ...
- 用python的BeautifulSoup分析html
序言 之前用python爬取网页的时候,一直用的是regex或者自带的库sgmllib里的SGMLParser.但是遇到复杂一点的情况时,SGMLParser往往就不那么给力了!(哈,难道说我 too ...
- TensorFlow系列专题(三):深度学习简介
一.深度学习的发展历程 深度学习的起源阶段 深度学习的发展阶段 深度学习的爆发阶段 二.深度学习的应用 自然语言处理 语音识别与合成 图像领域 三.参考文献 一.深度学习的发展历程 作为机器学习最 ...
- GIS中地图投影的定义
我国的基本比例尺地形图[1:5千.1:1万.1:2.5万.1:5万.1:10万.1:25万.1:50万.1:100万]中,大于等于50万的均采用高斯-克吕格投影[Gauss-Kruger]:小于50万 ...
- coding++:MySQL-ERROR:Column 'complaint_settlement_id' in field list is ambiguous
(多表查询出现的问题)列'ID'在字段列表中重复,其实就是两张表有相同的字段,但是使用时表字段的名称前没有加表名,导致指代不明. 如 前面加上表名前缀就没问题了.