巧用 OSX 的 Notification

起因:最近兴起一个 App 叫好近,专做 SOHO 附近小食,每日推出 1 分钱抢购或一些特价下午茶之类的活动,很难抢,不是错过就是被秒抢,遂想出个办法来提高抢购率!

最直接的需求是相对即时通知,让你快人一步。此类工具用 Python 来实现再合适不过了

提醒方式

工作期间不能老盯着手机,考虑通过 OSX 的 Notification 实现,让它带着音乐蹦出来~
调用 OSX 接口需要依赖 PyObjC 模块,通过 pip 装之(时间比较长,装一堆 OC 相关的包):

pip install PyObjC

调用的代码示例(python2.7+适用):

import objc
import Foundation

//py2.5可以通过 from Foundation import NSUserNotification 方式引入 
NSUserNotification = objc.lookUpClass('NSUserNotification')
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')

def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}):
    notification = NSUserNotification.alloc().init()
    notification.setTitle_(title)
    notification.setSubtitle_(subtitle)
    notification.setInformativeText_(info_text)
    notification.setUserInfo_(userInfo)
    if sound:
        notification.setSoundName_("NSUserNotificationDefaultSoundName")
    notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(delay, Foundation.NSDate.date()))
    NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)

截获相关 Api

利用 Charles 可以很方便的抓取,经观察一些优惠信息只有移动端才有,构造相应的 headers,使用 requests 模块(pip 装之):

def queryNotification():
    url = "http://api.haojin.in/takeout_item_list?atag_id=0&offset=0&pagesize=10&region_id=55b9c9d4c69575999049b2b4"
    headers = {'content-type': 'application/json', 'User-Agent':'User-Agent: QMMWD/1.3.6 iPhone/9.1 AFNetwork/1.1'}
    req = requests.get(url, headers=headers)
    content = json.loads(req.content)
    items = content['data']['sale_items']
    for item in items:
        price = item['price']
        title = item['title']
        origin_price = item['origin_price']
        end_time = item['end_time']
        quantity = item['quantity']
        e = datetime.datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
        if float(price) < 2 and e > datetime.datetime.now() and quantity > 0:
            notify(u"特价提醒!!", title, u"原价"+origin_price+u",现价:"+price, sound=True)

if __name__=='__main__':
    while True:
        queryHomeNotification()
        time.sleep(30)

每 30 秒查询一次,没结束的活动中价格低于 2 元且还有库存的优惠信息,一共不到 50 行代码,运行成功。但看起来使用方式并不友好,没办法分享给小伙伴们呢。

打包

想到把代码包装成一个 OSX 的应用,这样就方便任何人用了。使用 py2app 打包(pip 装之):

  1. 新建 setup.py,可以自定义 icon(icns 格式)

    from setuptools import setup
    
    APP = ['nearRemind.py']
    APP_NAME = "NearRemind"
    DATA_FILES = []
    OPTIONS = {'argv_emulation': True, 'iconfile': 'ico.icns'}
    
    setup(
        name=APP_NAME,
        app=APP,
        data_files=DATA_FILES,
        options={'py2app': OPTIONS},
        setup_requires=['py2app'],
    
  2. 打包,默认当前路径下 dist 目录:

    Python setup.py py2app
    

可以分享给小伙伴啦,启动就好,效果如下:
notification

其他

虽然有了提示但还是未必能抢到,所以后面还给自己做了自动下单版本,因为需要 session_id 和 sid 及收货地址之类的个人信息,做公用版比较麻烦些,就当是自己的私人福利了~
有兴趣自己玩的话代码在 Github

如此简易的 App 缺陷有很多,例如启动后没有合理的关闭方式,只能右键强制退出;无限重复通知等。

顺便发现「好近」的一些问题:

  • 接口访问频率似乎没有限制
  • 重复下单(一秒十单没问题~再快也没试了)
  • 活动状态好像是根据手机当前时间与接口里 end_time 对比来判断活动是否结束,且所有时间格式如下 “end_time”: “2015-12-21 23:59:00”,这种实现貌似不够好

Notification 刚移植到 OSX 上时就觉得这东西可以有很多种玩法,比如自己实现类似番茄工作法这样的小工具,这次也算试水成功了