欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python脚本抓取大乐透开奖结果核对定投号码邮件通知

程序员文章站 2022-06-03 16:18:05
...

    最近学习了一下Python的基础,想写个东西练练手。正好每次跟号的大乐透还需要手动兑奖或者去**站兑奖,自己写一个脚本自动抓取开奖结果,核对开奖金额后邮件通知。

整体思路:

  1. 找可抓取开奖结果网站
  2. 找可以发送邮件的免费服务器
  3. 写抓取、兑奖、发邮件脚本
  4. 设定自动执行脚本

踩坑:

  1. 2.7.3版本,使用requests、urllib3包的ssl有问题,最后也没解决了,执行的时候能执行,但是有警告信息,3.1上没问题。
  2. 找的网站,抓取历史数据的时候,频繁抓取会被限制,需要设定执行频率或者更改proxy。

详细过程:

1,找可抓取开奖结果网站

要求:开奖后及时更新结果;结果数据方便解析;

最后选中了彩经网的,开奖半小时内更新,而且结果只有一个table,很简单,方便解析。

例:https://www.cjcp.com.cn/kaijiang/data/ajax_dlt.php?qh=2021146

2,找免费发送的邮件服务器

 要求:常用QQ邮箱,那些非互联网上认证的邮件发送服务器(域名和出口IP不一致)的邮件会被拒收,所以需要找一个互联网上认证的邮件服务器进行发送。横向比较后,选择了163邮箱(比QQ邮箱认证简单一些)。

3,写抓取、兑奖、发邮件脚本

抓取:

#从彩经网获取大乐透开奖号码,
#lot:**期数,例如:2021140
def getlottery(lot):
    target = "https://www.cjcp.com.cn/kaijiang/data/ajax_dlt.php?qh=" + lot
    #设置requests header
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
        'Host': 'www.cjcp.com.cn',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3'
    }
    req = requests.get(url=target,headers=headers,verify=False)
    #req = requests.get(url=target,verify=False)
    #print(req.text)
    
    red = []
    #blue = []
    num=""
    #txt=(BS(req.text,'lxml')).splitlines()
    txt=req.text.splitlines()
    for ln in txt:
        if "qiu_r" in ln:
            num = ln.replace('<span class="qiu_r">',"").replace("</span>","").strip()
            #print(num)
           # red += num
            red.append(num)
        elif "qiu_b" in ln:
            #print(ln)
            num = ln.replace('<span class="qiu_b">',"").replace("</span>","").strip()
            #print(num)
            #blue += ln.replace('<span class="qiu_b">',"").replace("</span>","")
            red.append(num)
    return red

核对:

#查看是否中奖
#buy_num:买的号码,单注形式 例如:04,08,14,33,35:06,10
#prize_num:开奖号码,例如:03, 20, 25, 30, 34, 02, 09]
#return:中几等奖,0:未中奖,1-9中的奖的等数
def checkprized(buy_num,prize_num):

    prized = '0'
    #开奖红球
    pred = prize_num[0:5]
    #开奖蓝球
    pblue = prize_num[5:7]
    #购买红球
    br = buy_num.split(':')[0]
    #购买蓝球
    bb = buy_num.split(':')[1]
    #print('bought:',br,':::',bb)
    rcnt = 0
    bcnt = 0
    #红球匹配数
    for num in br.split(','):
        if num in pred:
            rcnt += 1
    #蓝球匹配数
    for num in bb.split(','):
        if num in pblue:
            bcnt += 1
    #中奖规则
    if rcnt == 5 and bcnt == 2:
        prized = '1'
    elif rcnt == 5 and bcnt == 1:
        prized = '2'
    elif rcnt == 5 and bcnt == 0:
        prized = '3'
    elif rcnt == 4 and bcnt == 2:
        prized = '4'
    elif rcnt == 4 and bcnt == 1:
        prized = '5'
    elif rcnt == 3 and bcnt == 2:
        prized = '6'
    elif rcnt == 4 and bcnt == 0:
        prized = '7'
    elif (rcnt == 3 and bcnt == 1) or\
    (rcnt == 2 and bcnt == 2):
        prized = '8'
    elif rcnt == 3 or \
    (bcnt == 1 and rcnt ==2) or \
    (bcnt == 2 and rcnt ==1) or \
    bcnt == 2:
        prized = '9'
    else:
        prized = '0'
    return prized

计算金额:

#根据中几等奖计算中奖金额
#prized:中几等奖
#return:中奖金额,1,2等奖浮动按照1千万和2百万计算
def countpay(prized):
    pay = 0
    for i in prized:
        if i == '0':
            continue
        elif i == '1':
            pay += 10000000            
        elif i == '2':
            pay += 2000000            
        elif i == '3':
            pay += 10000            
        elif i == '4':
            pay += 3000            
        elif i == '5':
            pay += 300            
        elif i == '6':
            pay += 200            
        elif i == '7':
            pay += 100            
        elif i == '8':
            pay += 15            
        elif i == '9':
            pay += 5            
    #print "中奖金额:" + str(pay)
    return pay

发送邮件


def send(subject,content,receivers=['[email protected]']):
    #设置服务器所需信息,使用163邮箱发送
    #邮箱服务器地址
    mail_host = 'smtp.163.com'
    #用户名
    mail_user = 'xxxxxxxx'
    #密码(部分邮箱为授权码) 
    mail_pass = 'xxxxxxxx'
    #邮件发送方邮箱地址
    sender = '[email protected]'  
    #邮件接受方邮箱地址,注意需要[]包裹,这意味着你可以写多个邮件地址群发
    #receivers = ['[email protected]']  

    #设置email信息
    #邮件内容设置
    message = MIMEText(content,'plain','utf-8')
    #邮件主题       
    message['Subject'] = subject 
    #发送方信息
    message['From'] = sender 
    #接受方信息     
    message['To'] = receivers[0]  

    #登录并发送邮件
    try:
        smtpObj = smtplib.SMTP() 
        #连接到服务器
        smtpObj.connect(mail_host,25)
        #登录到服务器
        smtpObj.login(mail_user,mail_pass) 
        #发送
        smtpObj.sendmail(sender,receivers,message.as_string()) 
        #退出
        smtpObj.quit() 
        
    except smtplib.SMTPException as e:
        print('error',e) 
        #打印错误

#send('测试邮件','测试内容')

主程序

#主程序开始
#从lotfile中取上次写入的期数数
lot = "2021140"
with open('lotfile', 'r') as f:
    for l in f:
        lot = l.strip('\n')
        break
f.close()

#取系统时间的年份
year = time.strftime("%Y", time.localtime())

#判断年份是否和lot的年份一致,不一致设为为当年第一期
if lot[0:4] != year:
    lot = year + '001'

#从采经网获取开奖号码
#num = ['03','04','21','22','35','02','09']
num = getlottery(lot)

#没有取得开奖结果(非未开奖)
if not num:
    print('系统或网络问题')
    sys.exit(1)
elif num[0] == '':
#未开奖的时候,有报文,没有中奖号码
    print('尚未开奖')
    sys.exit(0)

#是否中奖,针对购买号码的组数,序列类型
isprized=[]
#邮件内容
content=''

#从bought文件中读取购买号码,可以放多条,每条一行
#按照单式记录,格式为1,2,3,4,5:6,7
with open('bought', 'r') as fb:
    for l in fb:
        lt = l.strip('\n').strip()
        #如果有空行的话略过
        if len(lt) ==0:
            continue
        #每行验证是否中奖
        isprized += checkprized(lt,num)
        #将所购号码放入邮件内容中
        content += l + '\n'
    fb.close


#计算中奖金额
#isprized=['1','2','5','6','9']
#print('isprized:',isprized)
#print countpay(isprized)
pay = countpay(isprized)

#邮件标题
subject='' + lot + ':' + ','.join(num) + ':' + str(pay)
#print(subject)

#如果已开奖记录结果,并发送邮件,如果为空则为未开奖,什么都不做

#将开奖结果记入年份的文件,留作记录
with open(year, 'a+') as rf:
    rf.write(subject + '\n')
    rf.close()
    
#将下一期的期数,放到lotfile中
with open('lotfile', 'w') as lf:
    lf.write(str(int(lot)+1))
    lf.close()
    
#发送邮件,标题,内容;收件人使用默认的
send(subject,content)

4,定时执行

扔在云上的Linux服务器上,设定Crontab

crontab -u python -e

0 21 * * * /opt/sh/check_everyday.py

完整代码稍后上传。