效果图
每当L公司出新的活动时,并且有优惠券发放时,我和我的小伙伴们都会收到这么一封邮件
脚本放在云端CentOS 7 服务器上,每天自动运行一次,省时省力
前情提要
昨天某鱼上突然看到有卖L公司的优惠券
4.99元N张优惠券,乱七八糟加起来能减1000大洋
心动不如行动,反正L家的东西我是经常用,无形之中成了一种肛…不对…刚需
火速下单~付款~指纹验证~ (行云流水)
完事儿之后,卖家发过来一段文字
等我打开链接 瞬间我就明白了呀!
这不就是把L公司的优惠券网址给聚合了一下,完了穿了个要密码的马甲嘛!
我的老北鼻!
咸鱼上给的是一个缩短过的url
通过密码,把真正的网站链接给隐藏起来了
付过钱之后,我现在已经拿到了L网站的优惠券发放链接,一共9个网站,每个都有优惠券
通过观察手里拿到的这9个网址,发现一个规律,他们的命名规律,很有意思
从前到后的各种活动通知,都是放在 https://LCompany.com/WebDir/ 下 「网址已做处理,这里只谈技术层面实现」
并且命令规则很有趣,分别是 1.html、2.html、3.html、…、n.html
整个url格式为
活动一:https://LCompany.com/WebDir/1.html
活动二:https://LCompany.com/WebDir/2.html
等
等
活动n:https://LCompany.com/WebDir/n.html
难得遇上这么有规律的网址,想上次我想爬知乎日报的每日短评的时候发现已经晚了
知乎日报的网址由https://daily.zhihu.com/20200731 (举个栗子,之前有这样以日期结尾名命的)
现在已经变成了https://zhuanlan.zhihu.com/p/59160181 不得不说,这样操作一下,对我这种没入门的,确实很有难度!
也正因为这个,曾经我想用苹果 捷径自动化 做的一个语音早报(当天的天气、最高、最低温、世界上发生的大事儿、甚至还有经维度…)小玩意儿,就这么鸽了…一直🐦鸽到现在(这个想法,来自我同学的三星S9+上的语音助手,每天早上播报天气,前一天的新闻快讯,着实很让我心动,作为一个iPhone用户,内心深处喊出了一句:“苹果永不为奴!”,拿起捷径看了一下,大部分需要的功能在官方接口的支持下,很容易实现天气最低最高温以及地理位置,就剩一个获取新闻的api了,找了一圈发现知乎日报是个好东西,不过以我那时候的水平[当然,还有现在]根本爬不下来东西,即使是安装了Pythonista并且Pythonista给了捷径接口–捷径可以调用Python了,我卡在了知乎的网址上,一直过不去
回到这次的正题上来,既然有这么规律的网址出现,那从网页1到网页100挨个爬一边岂不是很容了!?
通过对网页源码的分析,轻松到找到 “立即领券”字样,
简单的 请求+匹配 就能找到所有的优惠券网页,并且如果把这些网页记录下来,当下次出现新的含有优惠券的网页时,及时的通知我,岂不是美哉!
本着:人民(这里就代指我自己)需要什么,我们就造什么的原则!
还本着:5块钱不能就这么白花了呀!的原则
网站都这么给力了,不得好好盘一盘它!
一个爬虫程序渐渐的清晰了起来
淦!
程序逻辑
得到URL
通过python字符串操作将 “网址中相同的部分”+与变化的数字+“.html”组合起来,形成一个url
url_html='https://LCompany.com/WebDir/'+i+'.html' #i 为变量 从1到50
经过这个简单的操作,就可以得到50个网页的地址(可能有的网页不存在,或者没有优惠券,或者其他的什么错误,后面会有过滤)
Get(URL)获得网页内容 text
通过python resquests的get( )请求,得到网站的信息
import requests as rq
r=rq.get(url_html)
text=r.text #网页的内容
text中查找优惠券信息
使用正则匹配寻找包含优惠券信息的.js文件
通过Get( )请求,打开.js文件
引入re库进行正则运算
对.js文件进行正则匹配,判断其中包含 “立即领券”文本
import re
re.search(r'https://LCompany.com/WebDir/\w+,js',text).group()
参考:
Python 正则表达式 | 菜鸟教程
python正则表达式匹配 模式匹配 - 疯狂的狗会直立行走 - 博客园 (写的挺好,就是所有的转义符号 ‘’ 都打错了 贼坑 我头都匹配秃了,还是没匹配上,才发现是 转义符号的问题 )
网页信息记录
正则匹配成功,说明该网页含有优惠券,将该网页记录到名为ExistCoupons.txt的文件中
正则匹配失败,则说明网页中不含优惠券,开始爬取下一个网页
发现新优惠券后邮件通知
正则匹配成功后,将该网址与ExistCoupons.txt记录的网址进行匹配
匹配成功--说明这个网址之前已经出现过,不是新的优惠券
匹配失败--说明是之前没有记录过的优惠券网站--新的优惠券--调用python 邮件库,给特定的邮箱发邮件,并将该网址添加到ExistCoupons.txt记录
运行环境
这里我python用的是python3.7.3
测试过脚本能够完美运行之后,将脚本保存为Coupons.py
将Coupons.py文件上传到Cent 7服务器上
确保服务器上使用了与之前一致的python版本,程序能够正常运行。
因为版本不同,python运行失败,我折腾了一上午,最后才发现是版本问题
脚本定时运行
上传脚本成功后
直接用 crontab -e 简单粗暴的添加一个定时任务执行Coupons.py文件
00 8 * * * python /home/pi/mu_code/Coupons.py #每天8点执行一次
或者写个shell脚本来运行py文件,配合一些其他的骚操作
当然,我选择前者 简单粗暴
参考:linux服务器设置定时执行脚本_Fly—in-Beijing-CSDN博客_linux 假设已编辑好脚本data,设置其在5分钟后执行
Python代码
Coupons.py 路径
/home/pi/mu_code/Coupons.py
服务器创建/home/pi/mu_code/目录
将Coupons.py文件上传到该目录下
#!/bin/python3
# coding=utf-8
#by Murphyzer with Mu
# 在这里写上你的代码 :-)
Server_f="""RasberryPi"""
#----------------------Email----------------------#
from email.mime.text import MIMEText #
from email.header import Header #
from smtplib import SMTP_SSL #
#-------------------------------------------------#
import requests as rq
import time
import re
##-----要爬取的网页数量-----##
n=30 ##
##--------------------------##
EMAIL_FLAG=0 #程序状态标志
message = """From LCompany优惠券脚本 <"""+Server_f+""" Coupons.py>
To: To Master <Murphyzer>
发现新的优惠券!!!
"""
FILE_ExistNum = "/home/pi/mu_code/ExistNum.txt" #用来记录已知的优惠券网站信息
FILE_Coupons = "/home/pi/mu_code/Coupon.txt" #用来存放 可以领取优惠券的网页地址
ExistNum_txt = open(FILE_ExistNum,'a') #不存在就新建文件
ExistNum_txt.close()
ExistNum_txt = open(FILE_ExistNum,'r')
ExistNum =ExistNum_txt.readlines() #读取文件网站地址记录文件
ExistNum_txt.close()
#print(ExistNum)
#给爬虫头文信息添加马甲
hea = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36'}
fw = open(FILE_Coupons,'w+') #创建或打开优惠券网址记录文件
for i in range(1,n+1):
#合成url
url_html='https://LCompany.com/WebDir/'+str(i)+'.html'
print('Staring connet to '+url_html)
try:
r_html=rq.get(url_html,timeout=30) #请求网页信息
print('Got'+url_html+' respons...')
try:
#正则匹配符合条件的js文件
math_url_js=re.search(r'https://LCompany.com/WebDir//js/active_\d+.\w+.js',r_html.text).group()
print('Find js Successfully!')
except:
try:
math_404=re.search(r'哦!你迷路了',math_url_js)
print(url_html+'哦!你迷路了\n')
break
except:
print(url_html+'BIG Error!!! 404 Not Found\n')
#send Email to me
try:
#获取js文件信息
r_json=rq.get(math_url_js,headers = hea,timeout=30)
except:
print('Connet to '+math_url_js+' TimeoutError')
try:
#正则匹配,js文件中寻找“优惠券”字样
math_js_coupon=re.search(r'立即领券',r_json.text).group()
print('!!!Find a Coupon!!! ')
#将含有优惠券的网址记录到文件Coupons.txt中
fw.write(url_html+' \t'+'可以领券\n')
#判断该含有优惠券的网址,是否已经被记录过,即是否出现新的优惠券
if str(i)+'\n' not in ExistNum:
ExistNum_txt = open(FILE_ExistNum,'a')
ExistNum_txt.write(str(i)+'\n')
ExistNum_txt.close()
#Send_Email to me ---------------------
#将该网址添加到邮件正文中
message = message+url_html+'\n'
EMAIL_FLAG=1 #Send Email Flag!!!
print('found new Coupons!')
else:
print('已经存在的优惠券')
except:
print('This page No Coupon')
time.sleep(1)
print('Waiting For 2 Seconds to start next Loop\n')
except:
print('Connet to '+url_html+' TimeoutError')
#### message = message+url_html+'TimeoutError \n'
# EMAIL_FLAG=-1 #Occour TimeoutError
fw.write('web range:1-{}'.format(n))
fw.close()
f_coups=open(FILE_Coupons,'r')
message+='\n\n\n1.大部分优惠券不能重复领取,少部分可以领取两次\n2.优惠券A有效时长1个月 优惠券B为2个月(不要一次领太多)\n3.确保使用之前领取优惠券,否则无法抵扣!\n以下是所有满足条件能用的优惠券:\n'
message+=str(f_coups.read())
def SendEmailToMe(message):
#qq邮箱smtp服务器
host_server = 'smtp.qq.com'
#sender_qq为发件人的qq号码
sender_qq = '117*****0'
#pwd为qq邮箱的授权码
pwd = 'xh**********bdc' ## xh**********bdc
#发件人的邮箱
sender_qq_mail = '117*****0@qq.com'
#收件人邮箱
receiver = 'm******@qq.com'
#邮件的正文内容
mail_content = message
#邮件标题
mail_title = 'LCompany优惠券脚本 Server:'+Server_f
#ssl登录
smtp = SMTP_SSL(host_server)
#set_debuglevel()是用来调试的。参数值为1表示开启调试模式,参数值为0关闭调试模式
smtp.set_debuglevel(1)
smtp.ehlo(host_server)
smtp.login(sender_qq, pwd)
msg = MIMEText(mail_content, "plain", 'utf-8')
msg["Subject"] = Header(mail_title, 'utf-8')
msg["From"] = Header(Server_f, 'utf-8') ## 发送者的别名
msg["To"] = Header('宝贝儿', 'utf-8') ## 接收者的别名
smtp.sendmail(sender_qq_mail, receiver, msg.as_string())
smtp.quit()
##----------------------------------------------------------
#Send Email to my friends
receivers = ['12*****8@qq.com','m****i@foxmail.com','1*****2@qq.com','1*******8@qq.com'] #收件人邮箱
def SendEmailToFriends(message):
#qq邮箱smtp服务器
host_server = 'smtp.qq.com'
#sender_qq为发件人的qq号码
sender_qq = '117*****0'
#pwd为qq邮箱的授权码
pwd = 'xh**********bdc' ## xh**********bdc
#发件人的邮箱
sender_qq_mail = '117*****0@qq.com'
#邮件的正文内容
mail_content = message
#邮件标题
mail_title = 'LCompany优惠券脚本 Server:'+Server_f
#ssl登录
smtp = SMTP_SSL(host_server)
#set_debuglevel()是用来调试的。参数值为1表示开启调试模式,参数值为0关闭调试模式
smtp.set_debuglevel(1)
smtp.ehlo(host_server)
smtp.login(sender_qq, pwd)
msg = MIMEText(mail_content, "plain", 'utf-8')
msg["Subject"] = Header(mail_title, 'utf-8')
msg["From"] = Header("GJE", 'utf-8') ## Sender的别名
msg["To"] = Header("GJE的宝贝儿们", 'utf-8') ## 接收者的别名
smtp.sendmail(sender_qq_mail, receivers, msg.as_string())
smtp.quit()
##----------------------------------------------------------
if EMAIL_FLAG == 1:
SendEmailToMe(message)
SendEmailToFriends((message)
elif EMAIL_FLAG == 0:
message = """From 优惠券脚本 <"""+Server_f+""" Coupons.py>
To: To Master <murphyzer>
脚本正常运行
"""
SendEmailToMe(message)
f_coups.close()
print('\n\nNO.1-{} webs spided done!\n'.format(n))
ExistNum.txt 、Coupon.txt路径
/home/pi/mu_code/ExistNum.txt
/home/pi/mu_code/Coupon.txt
两个文件均为自动生成文件
设置自动运行
crontab -e #此命令为shell命令 在shell下执行
之后输入如下代码
00 8 * * * python /home/pi/mu_code/Coupons.py #每天8点执行一次
每天8点运行一次脚本
如果发现新优惠券就给我和我的小伙伴们发包含新优惠券网址的邮件
否则就之给我发送一个脚本运行成功的邮件
总结
以实际角需求出发,需要什么我们肝什么 (手动滑稽)
利益相关吧,我把具体的公司名字,网站都给换掉了,本着记录生活的态度,写下这么一篇文章
在这之前,我就看过一个爬虫小Demo,下载贴吧图片的,从那个里面,大概知道了爬虫是怎么会事儿,这次是第一次上手实践
python也是只会一些基本语法,类、继承什么的倒是继承了C++的特点,不会的还是不会
从昨天下午产生想法,到晚上2点写出满足基本功能的py脚本
再到今天上午成功部署到服务器,一遍遍的测试,终于正常运行
最后今天中午,最后的优化
差不多花了一整天的时间,中间好多东西都是一知半解,我知道有这么个东西,能让我实现那样的功能,但是具体实施起来,通篇的内容,都是靠百度现学得来的
总的来说效果还不错
慢慢来吧,一步步的慢慢积累
后记
为了区区几张优惠券的蝇头小利
又是没有搞学习的一天
这研究生如何考得上! 猛男落泪!