bilibili-live reminder

破站live竟然不能自动提醒欸,好气,网上也没有现成的app,自己写一个提醒姬吧><
(Update:2017年第三季度mobile端已支持提醒)
(Update:2018年初发现bilibili-api)
Environment:

  • PC: python3.6.2, windows 10 x64 1709
  • Cloud Server: centOS 7.2 x64, python3.5

扩充技能点


  • BeautifulSoup4
  • requests-python
  • HTML+Javascrip
  • smtplib
  • base64-python
  • Linux

website analyse


通过chrome检查网页源码查看静态数据,需要得到live状态的动态数据可知用异步加载传输

检查Network定位数据来源筛选 HXR

定位live-room信息,查看Respons

该请求头包含live-room异步信息,使用requests请求段数据
[python]
#state.py
“””
BeautifulSoup4 中文文档见: http://beautifulsoup.readthedocs.io/zh_CN/latest/
“””
import requests
from bs4 import BeautifulSoup

def status(domain, cid, ts):
return_data = requests.get(domain+’player’+’?’+’id=’+cid+’&’+ts,verify=True)
soup = BeautifulSoup(str(return_data.text), “lxml”)
# 简单构造BeautifulSoup对象传入str片段或文件句柄即可
# 经过处理的对象具有若干tag,tag含有若干属性,通过字典即可访问对应属性片段
# 一个Tag可能包含多个字符串或其它的Tag,这些是这个Tag的子节点
# 如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用.string得到子节点:
# 例如LIVE,tag.string取LIVE
# 对得到的数据使用find得到对应标签通过.string即可取字符串
# 在云服务器上建议使用python标准库的”html.parser”,而非使用需要安装C语言库的lxml
if soup.find(“state”).string == ‘LIVE’:
return True
else:
return False


<h3><strong>使用python3 smtplib模块发送邮件</strong></h3> 使用<code>bilibili-api</code> [python] import requests p = r'http://live.bilibili.com/bili/isliving/' def status(uid): if len(requests.get(p + uid).text) >= 33: return True else: return False

  • 构造消息头

    message = MINEText(Content, 'plain', 'utf-8') 正文内容

    message['From'] = 'auto-reminder@XXXX.XXX' 显示的发件人

    message['To'] = 'xxxxxxx@qq.com' 显示的收件人

    message['Subject'] = Header('LIVE now!', 'utf-8') 主题

Tips:建议以上消息完整填写否则会被表示成垃圾邮件

  • 构造smtp对象
  • smtpObj = smtplib.SMTP_SSL('smtp.qq.com')

    这里我们用SSL加密协议, 在最新的普通QQ mail中已经无法使用未加密的请求,

    相应的使用SSL的访问端口为465 而非默认的的25端口,

    调试代码: reply: b'530 Error: A secure connection is requiered(such as ssl).

    其他邮箱例如163,gmail,hotmail依然可以使用 smtplib.SMTP('smtp.163.com')

    在本地SMTP_SSL()内可以留空,但在服务器中必须填上发件服务器地址否则引起socket error,怀疑默认行为在python升级中已更改

  • smtpObj.set_debuglevel(1)

    该语句用来生成调试信息,便于查看哪一步出错

  • smtpObj.connect(mail_host, mail_port)

    注意打开并参看各邮箱提供商的stmp信息填入正确的值,出错都可以在调试中审查

  • smtpObj.login(mail_username, mail_pw)

    在QQ mail中密码是相应的第三方客户端登陆授权码,而非邮箱密码

  • smtpObj.sendmail(sender, receivers, message.as_string())

Tips:
PC通过DHCP分配的IP的socket主机信息会包含空格,在构造中为语法错误,解决方法在适配器TCP/IPv4高级DNS设置中,手动填写此连接的DNS后缀

[python]
#reminder.py
#--coding:utf-8-
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from user import * # 存储邮箱配置和live-room信息

Content = “””xxx
xxxxxxxxxxxxxxxx
“””
def send_mail(to_who):
message = MIMEText(Content, ‘plain’, ‘utf-8’)
message[‘From’] = ‘xxxx@xxxx.cn’
message[‘To’] = ‘xxxxxxx@qq.com’
message[‘Subject’] = Header(to_who + ‘xxxx’, ‘utf-8’)
try:
smtpObj = smtplib.SMTP(‘smtp.qq.com’)
smtpObj.set_debuglevel(1)
smtpObj.connect(mail_host, mail_port)
smtpObj.login(mail_username, mail_pw)
smtpObj.sendmail(sender, receivers, message.as_string())
return True
except smtplib.SMTPException:
return False

通过审查 <code>XHS</code> 可知room请求字符串两个: <code>cid</code> (播主的固定id)+ <code>ts</code> (猜测为日期混合生成)

测试单个 <code>ts</code> 长期有效
[python]
#user.py
#-<em>-coding:utf-8-</em>-
#some info for query
domain = 'https://live.bilibili.com/api/'
#test01
#https://live.bilibili.com/1040
t1_cid = 'cid%3A12722'
t1_ts = '15f61520c84'

#reminder para
receivers = 'xxxxxxx@gmail.com'
sender = 'xxxxxxx@qq.com'

#第三方 SMTP 服务
mail_host = 'smtp.qq.com'

mail_port = 465
mail_username = sender
mail_pw = 'xxxxxxxxxxx'

主程序Main

[python]

#Main.py
import state
from user import *
import reminder
import time

cnt = 1
_t1_last = False

while(True):
_t1_now = state.status(domain, t1_cid, t1_ts)
s1 = (_t1_last == False and _t1_now)
if(s3):
if (reminder.send_mail(‘Test1’)):
#建议不要使用test,hello world等字眼避免出现554错误,此处设置了白名单
print(‘send suc to Test1’)
else:
print(‘send error!’)
else:
print(‘run_id ‘ + str(cnt))
cnt += 1
time.sleep(172) # 暂停秒数
_13_last = state.status(domain, t1_cid, t1_ts)

“`

跑在服务器上


主要解决python程序在后台运行,常规通过ssh与服务器建立连接,所有的进程都在ssh组下,一旦ssh连接断开其下的所有进程都将被杀死

这里简单通过screen来解决问题,因为screen运行于1组下因此在创建的虚拟环境中当ssh断开脚本并不会被一并杀死

简单命令:

screen -S name 新建一个终端环境name为环境名称

screen -ls 或者 -list 查看所有的终端环境

kill -9 PID 杀死终端环境的任一个进程即可关闭screen环境

screen -wipe 清除死掉的环境

screen -r PID 进入 PID的环境

ctrl+A + D 暂时退出活跃的环境

ps -ef |grep python 查看当前的python脚本

screen python3 Main.py $ 在后台运行脚本,暂时退出即可保留后台

分类: develop

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.