推送公司今日菜单内容到手机

此文已由作者张耕源授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


自从公司的易信公众服务号有了查询今日菜单的功能,自己慢慢养成了每次去吃饭前查一 下各个窗口的菜谱,再决定去哪吃饭的习惯。

不过这个功能使用的越多,越来越觉得它不方便。目前在易信公众号查询菜单的步骤是:

  1. 打开易信

  2. 打开网易精灵公众号

  3. 点击便捷服务

  4. 点击今日菜单

  5. 等待返回今日菜单的入口链接

  6. 点击入口链接查看今日菜单

作为固定的每天至少要操作两次的动作,整个流程是被动的、并且有点复杂了。特别是 第五步、第六步都需要网络访问,如果手机网络访问不稳定(WiFi、4G信号不好等,在 坐、等电梯时很容易碰到这个情况),其中任何一步都会卡住导致无法查询;还有一些 同学由于种种原因根本就没有关注网易精灵公共号,无从查看今日菜单。

所以我就想,有没有更简单的办法,直接把每日菜单内容直接主动推送到手机,只需要 简单的点一下就能查看菜单了呢:

  1. 点击推送消息

  2. 查看今日菜单

有了这个想法就动手做了。

这件事可以拆成三步:

  1. 数据抓取

  2. 数据处理

  3. 数据推送

下面详细说。

数据抓取

要想爬菜谱的数据,首先需要知道这些信息是从哪里查询出来的。我没有做过易信公众号 的开发,但是根据一般的经验,不管是微信还是易信的公众号发布的文章一般就是一个 简单的 HTTP 页面。想要找出每日菜单数据的来源,找出这些 HTTP 页面地址的 pattern 一般就搞定了。

抓取手机网络请求的方法很多,最方便的办法应该是在手机后台跑一个类似 tcpdump 功能 的工具的同时,访问易信的今日菜单,就可以抓到想要的结果。不过由于我的手机是没有 越狱的 iOS 系统,由于沙盒机制的限制无法做到。

最后用的办法是,在相同网络的电脑上跑一个 mitmproxy1 服务,将手机的 HTTP Proxy 地址指定为电脑的地址,在易信里打开今日菜单的链接,就可以在 mitmproxy 里看到一串 手机的 HTTP 访问记录,其中就包含我们要抓取今日菜单的 HTTP URL 。

Alt pic

可以发现今日菜单的 HTTP URL 链接就是下面的 pattern:

http://numenplus.yixin.im/singleNewsWap.do?companyId=1&materialId=${id}

其中只有一个变量 ${id} ,是个正整数,应该就是文章的ID。我们要爬的每日菜单内容, 都在这些链接里面,还包含网易精灵公众号发布的其他一些广告文章,这个页面就是简单 的 HTTP GET 就可以爬到内容,不需要做额外的处理。

自己研究了一下没有找出今日菜单的文章的 ID 生成的规律,推测应该是在易信后端生成 的,手机客户端无法直接拿到这个 ID。于是干脆就每个ID都爬一遍,检查内容是今日菜单 的文章就处理,不是就忽略。这样就搞定今日菜单的数据来源了。

比较熟悉 Python,就用 Python 实现了:

import requestsdef http_get(url, timeout=3):try:res = requests.get(url, timeout)    except:LOG.exception("Failed to GET: %s" % url)    else:        if res.status_code != 200:            return Noneelse:            return resdef fetch(start, step=300):last_id = start    for i in iter(range(start, start + step)):url = ("http://numenplus.yixin.im/singleNewsWap.do?""companyId=1&materialId=%d" % i)response = http_get(url)        if not response:            continue# handle menu data here

数据处理

数据处理,主要有两个任务:

  1. 上面也提到了,需要检查爬取的文章内容是不是今日菜单

  2. 解析 HTML 内容,获得我们想要的菜单信息

第一个问题比较简单,我们可以直接通过简单的关键词正则表达式匹配来检查。比如文章 内容含有“今日菜单”这四个字,我们就认为这篇文章内容是今日菜单。

第二个问题稍微复杂一些,我们需要从爬取的 HTML 源数据提取出其中的文本数据,然后 从中生成这份菜单的日期、早餐、午餐、晚餐信息。这个用稍微复杂一点的正则表达式也 可以搞定。

Python 中有一个比较有名的处理 HTML 格式内容的第三方库 BeautifulSoup , 使用非常方便:

获取菜单正文内容

def _parse(self, content):try:bs = BS(content, "html.parser")        if bs.find_all(class_="m-error"):            return Noneelse:            return bs    except:LOG.exception("Failed to Parse content: %s" % content)def _handle_menu(bs):try:content = bs.find(id="divCNT")    except:LOG.warn("Failed to get content")        return Noneelse:        return content

HTML 解析前是这个样子

Alt pic

解析后就是这个样子,已经把 HTML 的 tag 都脱掉了

Alt pic

判断是否是今日菜单

def _is_menu(text):# \u4eca\u65e5\u83dc\u5355 => 今日菜单if re.findall(ur"\u4eca\u65e5\u83dc\u5355", text, re.UNICODE):        return Trueelse:        return False

提取菜单日期

def _handle_date(content):# \u6708 => 月 \u65e5 => 日res = re.findall(ur"(\d+)\u6708(\d+)\u65e5", content.text, re.UNICODE)    if not res:LOG.warn("Failed to parse date")        return Noneelse:month, day = tuple([int(i) for i in res[0]])year = datetime.datetime.now().year        return datetime.datetime(year, month, day)

提取菜单早餐、午餐、晚餐内容

def _menu_to_text(content):# \u65e9\u9910 => 早餐# \u4e2d\u9910 => 中餐# \u665a\u9910 => 晚餐# \u591c\u5bb5 => 夜宵text = content.get_text()res = re.findall(ur"\u65e9\u9910([\s\S]+)\u4e2d\u9910([\s\S]+)"ur"\u665a\u9910([\s\S]+)\u591c\u5bb5",text, re.UNICODE | re.MULTILINE)    if not res:LOG.warn("Failed to match menu")        return Noneelse:menu = {}menu[BREAKFAST] = res[0][0]menu[LUNCH] = res[0][1]menu[SUPPER] = res[0][2]        return menu

数据推送

现在已经解决了今日菜单的数据爬取、处理,就差如何把菜单内容推送到手机了。

经过调研,iOS 平台上比较好用的第三方消息推送服务有 Pushover、Pushbullet、 Boxcar、Amazon SNS 等。

Amazon SNS 没有提供现成的客户端首先否决掉;Pushover 综合看起来是最好的选择, 不过每个手机客户端使用需要付 5$ 的一次性授权费用,穷,也否决掉;综合看起来, Pushbullet 功能较全、免费、文档清晰、全平台支持,最后选择 Pushbullet 推送消息。

按照 Pushbullet 提供的 API 文档写一个 HTTP POST 请求就可以实现推送功能了:

def send_notification(subject, content, channel=PUSHBULLET_CHANNEL):try:res = requests.post(            "%s/pushes" % PUSHBULLET_API,headers={"Access-Token": PUSHBULLET_TOKEN},data={"title": subject,                  "body": content,                  "type": "note",                  "channel_tag": channel},timeout=30)    except:LOG.exception("Failed to send notification")    else:        if res.status_code != 200:LOG.warn("Error when pushing notification")

推送过来的菜单就是这样了:

Alt pic

Alt pic

PC/Mac 端同样支持:

Alt pic

把上面这些代码片段拼起来,就是一个可以抓取、推送今日菜单的小项目了,最后能跑的 代码放在这里(代码里还包含之前写的把菜单内容发邮件通知的功能):

https://g.hz.netease.com/hzzhanggy/what2eat2day_ntes

自动化

整个数据爬取、推送的流程都写好了,最后剩下的需要做的事情就是让整个流程自动化 运行,我们只需要每天饭点看手机推送消息就可以了。

其实就是将数据爬取、推送做成定时任务就可以了。我通过 systemd timer 实现:

在 virtualenv 中运行脚本的 wrapper run.sh

#!/bin/bashBASE=/home/stanzgy/workspace/what2eat2day_ntes$BASE/.venv/bin/python $BASE/fetch.py $@

今日菜单抓取 service 文件 menu_fetch.service

[Unit]Description=Fetch NetEase menu today[Service]Type=oneshotExecStart=/home/stanzgy/workspace/what2eat2day_ntes/run.sh f[Install]WantedBy=multi-user.target

今日菜单抓取 timer 文件 menu_fetch.timer

[Unit]Description=Fetch NetEase menu everyday[Timer]OnCalendar=Mon-Fri *-*-* 10:00:00Unit=menu_fetch.service[Install]WantedBy=multi-user.target

推送今日菜单的 timer 配置类似上面,仅仅是命令行传入的参数不一样,这里就省略了。 最后效果如下

Alt pic

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击。

相关文章:
【推荐】 手把手带你打造一个 Android 热修复框架
【推荐】 git 常用命令
【推荐】 从golang的垃圾回收说起(上篇)

转载于:https://www.cnblogs.com/163yun/p/9895583.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android开发中如何创建自定义对话框

背景: 无论是Android,还是其他什么平台,对话框的主要形式都是弹出,或者我们可以说是一个在当前活动中打开的提示,来执行一些操作或实现一些功能。 你可以用一个对话框来问用户以确认一个行动,向用户通告一个…

树莓派接入公网(花生壳)

参考:树莓派接入公网 作者:图触靓 发布时间: 2020-12-22 17:28:19 网址:https://blog.csdn.net/bhbhhyg/article/details/107994829 目录为什么要接入公网接入公网的方法(花生壳)1、下载工具huashenke2、安…

cant find module express

安装express成功,测试一个应用如下:但是,运行却报错,如下图:说是express找不到,不应该啊!命令都能用啊!表面的原因是因为我install express用的是-g。参考链接如下:http:…

Linux虚拟机sqlite数据库安装教程、命令实现sqlite

参考:Linux虚拟机sqlite数据库安装教程 作者:图触靓 发布时间: 2021-04-08 19:07:56 网址:https://blog.csdn.net/bhbhhyg/article/details/115528254 一、在官网下载压缩包到window里面 SQLite官网下载地址 如图我们下载sqlite-a…

SecureCRT 使用 rz命令提示waiting to receive.**B0100000023be50

SecureCRT 远程连接Linux服务器,使用 rz命令提示waiting to receive.**B0100000023be50,或者使用sz命令提示: **B0100000023be50 解决方法设置如下: 转载于:https://www.cnblogs.com/pandaly/p/9898173.html

Python时间复杂度计算题答案

评论 题目链接 https://blog.csdn.net/qq_33254766/article/details/132255078 答案 时间复杂度:O(n)。 分析:这段代码遍历了n次,所以时间复杂度是线性的,即O(n)。 时间复杂度:O(n^2)。 分析:两个嵌套的…

wxpython使用方法_python图形界面开发之wxPython树控件使用方法详解

wxPython树控件介绍树(tree)是一种通过层次结构展示信息的控件,如下图所示是树控件示例,左窗口中是树控件,在wxPython中树控件类是wx.TreeCtrl。wx.TreeCtrl常用的方法有AddRoot(text, image-1, selImage-1, dataNone)。添加根节点&#xff0…

DSP_SCI

F2833x Serial Communication Interface 簡介 串行通信接口(SCI)模塊是一個串行I / O端口,允許F2833x與其他外圍設備之間的異步通信。 它通常被稱為UART(通用異步接收器發送器),通常根據RS232標準使用。 SC…

如何让自己的写的程序在阿里云一直运行

参考:如何让自己的写的程序在阿里云一直运行 作者:图触靓 发布时间: 2020-08-02 11:53:28 网址:https://blog.csdn.net/bhbhhyg/article/details/107742311 目录1、下载screen:2、运行screen,创建一个scree…

C程序设计语言--第五章:指针与数组

为什么80%的码农都做不了架构师?>>> 指针是一种保存变量地址的变量. 5.1 指针与地址 通常的机器都有一系列连续编号或编址的存储单元,这些存储单元可以单个进行操纵,也可以连续成组的方式操纵.指针是能够存放一个地址的一组存储单元(通常是两个或四个…

java list 自定义类型转换_使用Java Stream API将List按自定义分组规则转换成Map的一个例子...

本文完整测试代码见文末。测试数据是List里的4个员工对象实例:根据员工所在的城市进行分组:结果分成了三组:第一组的员工在上海:第二组的员工在成都:统计每组员工个数:把员工进行分组,得分大于1…

安卓app与阿里云服务器的无线通信(非局域网)

参考:安卓app与阿里云服务器的无线通信(非局域网) 作者:图触靓 发布时间: 2020-08-01 16:13:14 网址:https://blog.csdn.net/bhbhhyg/article/details/107732156 目录写在阿里云里面的服务器代码&#xff1…

10.继承和派生

2019独角兽企业重金招聘Python工程师标准>>> 类成员访问权限: 成员访问权限:私有成员:只能被类自身的成员和友元访问; 公有成员:可以被任何普通函数和任何类的成员函数或子类访问; 保护成员&a…

树莓派与阿里云服务器之间的无线通信(非局域网)

参考:Linux虚拟机sqlite数据库安装教程 作者:图触靓 发布时间: 2020-08-01 15:45:026 网址:https://blog.csdn.net/bhbhhyg/article/details/107731166 购买服务器后。我们可以点击控制台,找到实例列表,点击…

业余剪辑——从拍摄到剪辑到加字幕

工作需要帮公司做一个公司的宣传片,要求不是很高所以就让我这个半吊子“设计”来做视频了。。。 以下设备和软件的使用只是我个人本次的使用的记录,大家按需使用即可 一、拍摄 设备:手机 软件:剪辑大师app(应用商店下载…

树莓派作为客户端与WemosD1作为服务器的无线通信(局域网通信)

参考:树莓派作为客户端与WemosD1作为服务器的无线通信(局域网通信) 作者:图触靓 发布时间: 2020-07-26 21:50:39 网址:https://blog.csdn.net/bhbhhyg/article/details/107599915 目录wemos版作为服务端代码…

Lync Server的环境搭建(五):Lync-Server的安装部署

今天,我们接着来进行Lync-Server服务端的安装。我们分别打开“Lync-DC”和“Lync-Server”这两台虚拟机,切换到“Lync-Server”下,“开始”—“Lync Server安装部署,单击“安装或更新Lync Server系统”。弹出”部署向导“窗口,我们…

NodeMan介绍

近年来,随着nodejs的突飞猛进,node项目数量增长迅猛,node项目完美的阐释了“开箱即用”的理念。小到创业公司,大到阿里这样的巨头,背后均有node的身影。 node项目基于Chrome的V8引擎,使用JavaScript&#x…

#ifndef, #define, #endif的作用

目录作用示例作用 #ifndef 它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种——条件编译。 在c语言中,对同一个变量或者函数进行…