起因

我在github上发起了一个开源项目:《HelloGitHub月刊》,内容是github上收集的好玩,容易上手的开源项目。

目的:因为兴趣是最好的老师,我希望月刊中的内容可以激发读者的兴趣,从而动手参与到开源的项目中,一方面提高编程技术、另一方面哪怕是能力有限不能为开源项目提交代码,也可以给个‘star’,表示对有意思、优秀的开源项目的支持!从而让开源社区越来越好。

所以,我就需要收集github上的开源项目,目前通过两种方式发现github上优秀的项目:

  1. Follow活跃的Github用户,收集他们Starred的项目
  2. Github的Explore页

然后,我就想能不能写个脚本,每天跑一次把这两个数据源的数据,收集整理好,然后发到我的邮箱中。这个需求很简单,初步感觉就两个问题:

  1. 数据源的api
  2. 发邮件的方法

过程

数据源

Github API提供了诸多获取Github数据的接口:

  1. List public events that a user has receivedGET /users/:username/received_events/public,这个接口返回user的动态(包含user关注的用户、项目的动态)
  2. 暂时没找到Explore页的接口,如果实在找不到,我就尝试爬取。

代码

完整的代码我的Github

1、请求api:

首选requests库,真的是居家旅行必备良品。需要注意一点,请求GET /users/:username/received_events/public需要用户验证,请求api的函数如下:

def get_data(page=1, per_page=100):
"""
从目标源获取数据
""" args = '?page={page}&per_page={per_page}'.format(
page=page, per_page=per_page) response = requests.get(API['events']+args,
auth=(ACCOUNT['username'], ACCOUNT['password']))
status_code = response.status_code
if status_code == 200:
resp_json = response.json()
return resp_json
else:
logging.error('请求api失败:', status_code)
return None
2、根据条件过滤数据:

请求api回来的json数据如下:

[
...
{
"id": "4123123423",
"type": "WatchEvent",
"actor": {
"id": 12342134,
"login": "gera2ld",
"display_login": "gera2ld",
"gravatar_id": "",
"url": "https://api.github.com/users/gera2ld",
"avatar_url": "https://avatars.githubusercontent.com/u/3139113?"
},
"repo": {
"id": 23412431,
"name": "yahoo/gifshot",
"url": "https://api.github.com/repos/yahoo/gifshot"
},
"payload": {
"action": "started"
},
"public": true,
"created_at": "2016-09-03T16:25:34Z",
"org": {
"id": 234234,
"login": "yahoo",
"gravatar_id": "",
"url": "https://api.github.com/orgs/yahoo",
"avatar_url": "https://avatars.githubusercontent.com/u/16574?"
}
},
{
"id": "234234",
"type": "WatchEvent",
"actor": {
"id": 21341234,
"login": "phith0n",
"display_login": "phith0n",
"gravatar_id": "",
"url": "https://api.github.com/users/phith0n",
"avatar_url": "https://avatars.githubusercontent.com/u/5711185?"
},
"repo": {
"id": 23234,
"name": "yummybian/ThreadPool",
"url": "https://api.github.com/repos/yummybian/ThreadPool"
},
"payload": {
"action": "started"
},
"public": true,
"created_at": "2016-09-03T16:12:56Z"
}
]
...

分析上面的json数据,其中可能会包含我不需要的信息(非starred事件的数据)需要过滤掉、同时需要根据时间获取某一段时间的数据。比如我写的这个github bot脚本获取24个小时的数据,我设定脚本每天凌晨4点跑——例如:9.3 4:00——9.4 4:00(24h的数据)。下面写了两个函数,用于过滤符合条件的数据:

注意: 接口返回的数据中的create_at字段的时间值形如——created_at: "2016-09-03T16:12:56Z" 是‘协调世界时’,‘Z’是协调世界时中0时区的标志,北京是8时区,所以就是需要在这个时间的基础上+8小时。这个事件发生于北京时间:"2016-09-04 00:12:56"

def check_condition(data):
"""
过滤条件
"""
create_time = datetime.datetime.strptime(
data['created_at'], "%Y-%m-%dT%H:%M:%SZ") + datetime.timedelta(hours=8)
date_condition = create_time >= (datetime.datetime.now()
- datetime.timedelta(days=DAY))
if (data['type'] == 'WatchEvent') and date_condition:
if data['payload']['action'] == 'started':
data['date_time'] = create_time.strftime("%Y-%m-%d %H:%M:%S")
return True
else:
return False def analyze(json_data):
"""
分析获取的数据
:return 符合过滤条件的数据
"""
result_data = []
for fi_data in json_data:
if check_condition(fi_data):
result_data.append(fi_data)
return result_data
3、生成发送邮件的内容:

最终邮件内容如下:

注意: 因为获取项目stars数的接口,有的时候获取数据很慢,所以设置了超时时间。最好的方法因该是以异步的方式解决。可以参考grequests项目

CONTENT_FORMAT = """
<table border="2" align="center">
<tr>
<th>头像</th>
<th>用户名</th>
<th>项目名</th>
<th>starred日期</th>
<th>项目star数量</th>
</tr>
{starred_info}
</table>
""" def make_content():
"""
生成发布邮件的内容
"""
json_data = get_data()
data = analyze(json_data)
content = [] for fi_data in data:
user = fi_data['actor']['login']
user_url = 'https://github.com/' + user
avatar_url = fi_data['actor']['avatar_url']
repo_name = fi_data['repo']['name']
repo_url = 'https://github.com/' + repo_name
date_time = fi_data['date_time']
try:
repo_stars = requests.get(fi_data['repo']['url'], timeout=2).json()
if repo_stars:
repo_stars = repo_stars['stargazers_count']
else:
repo_stars = '未知数'
except Exception as e:
repo_stars = '未知数'
logger.warning(u'获取:{} 项目星数失败——{}'.format(repo_name, e))
starred_info = """<tr>
<td><img src={avatar_url} width=32px></img></td>
<td><a href={user_url}>{user}</a></td>
<td><a href={repo_url}>{repo_name}</a></td>
<td>{date_time}</td>
<td>{repo_stars}</td>
</tr>
""".format(user=user, repo_name=repo_name,
repo_url=repo_url, user_url=user_url,
avatar_url=avatar_url, repo_stars=repo_stars,
date_time=date_time)
content.append(starred_info)
return content
4、发送邮件:

如果是使用qq邮箱发送邮件,可以参考:qq邮件服务文档

注意: 发送邮件使用的邮箱密码,最好用授权码,因为我在测试邮件发送功能时,发送邮件的次数太多,后面突然不能发送了!而且没有任何错误提示,就卡在sendmail方法!后来登录qq邮箱,发现让我使用授权码 进行第三方授权。最后使用授权码一切就ok了!

发送邮件的函数如下:

def send_email(receivers, email_content):
"""
发送邮件
"""
sender = MAIL['mail'] # 发送邮件的邮箱
receivers = receivers # 接收邮件的邮箱,可设置多个 # 三个参数:第一个为文本内容,第二个 html 设置文本格式,第三个 utf-8 设置编码
message = MIMEText(
CONTENT_FORMAT.format(starred_info=''.join(email_content)),
'html', 'utf-8'
)
message['From'] = Header(u'Github机器人', 'utf-8')
message['To'] = Header(u'削微寒', 'utf-8') subject = u'今日Github热点' # 设置邮件主题
message['Subject'] = Header(subject, 'utf-8')
try:
smtp_obj = smtplib.SMTP_SSL() # qq邮箱要求是https连接,所以需要用SMTP_SSL
smtp_obj.connect(MAIL['host'], MAIL['port']) # 设置SMTP地址和端口号
smtp_obj.login(MAIL['username'], MAIL['password'])
smtp_obj.sendmail(sender, receivers, message.as_string())
except smtplib.SMTPException as e:
logger.error(u"无法发送邮件: {}".format(e))

完整的代码我的Github

最后

参照crontab 定时任务,在linux下设置定时任务。

1. EDITOR=vi; export EDITOR #使用vi编辑器编辑

2. crontab -e #加入定时任务

3. crontab -l #查看是否加入成功

TODO

  1. 获取Explore页的数据

参考

《HelloGitHub》之GitHub Bot的更多相关文章

  1. 《HelloGitHub》第 75 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...

  2. GitHub 热点速览 Vol.13:近 40k star 计算机论文项目再霸 GitHub Trending 榜

    作者:HelloGitHub-小鱼干 摘要:"潮流是个轮回",这句话用来形容上周的 GitHub Trending 最贴切不过.无论是已经获得近 40k 的高星项目 Papers ...

  3. GitHub 热点速览 Vol.14:周获 2k+ Vim 掀起三维编程风

    作者:HelloGitHub-小鱼干 摘要(用于 公众号/博客园等地方)寓教于乐,应该是上周 Trending 的主题了,无论是被多人转发推荐的三维 Vim 项目 Vim³ 或者是流体运动的 WebG ...

  4. GitHub 热点速览 Vol.15:Background-Matting 让你秒变专业抠图师

    作者:HelloGitHub-小鱼干 摘要:如果要选一个词来概述上周的热点,春风拂过,应该是一个不错的词.新项目像春天冒出的枝芽,朝气蓬勃,虽然获得的 star 不如之前三维 Vim 抢眼,但胜在多姿 ...

  5. GitHub 热点速览 Vol.16:化身蒙娜丽莎和乔布斯对话

    摘要:妙趣横生,上周的 GitHub 热点的关键词.无论是让你化身为爱因斯坦开启会议脑暴模式 avatarify,还是和上周人人都是抠图师项目的同门项目 3D 照片修复:3d-photo-inpain ...

  6. GitHub 热点速览 Vol.17:在?各家视频会员要不要?

    作者:HelloGitHub-小鱼干 摘要:经济实用,用作上周的 GitHub 热点的横批再合适不过.先不说 GitHub Trending 上不止一个的会员共享项目,免你找好友刷脸要会员,这项目实在 ...

  7. GitHub 热点速览 Vol.18:刷 LeetCode 的正确姿势

    作者:HelloGitHub-小鱼干 摘要:找对路子,事半功倍,正如本周 GitHub Trending #刷 LeetCode# 主题想表达的那般,正确的学习姿势方能让人走得更远,走进大厂

  8. GitHub 热点速览 Vol.19:如何叩响大厂的门?

    作者:HelloGitHub-小鱼干 摘要:进大厂,无疑是升职加薪走上人生巅峰的一个敲门砖,那,如何拿到这个敲门砖呢?前辈的经验之谈,无疑会给我们进大厂带来许多的经验参考,本周的#大厂面试经验之谈#主 ...

  9. GitHub 热点速览 Vol.20:VSCode 插件全家桶新增画图小能手

    作者:HelloGitHub-小鱼干 摘要:后浪,这个五月热词用来概括 GitHub 本周热点无疑是最佳词汇.Deno 这个 Node.js 作者制造出来的后浪,掀起了 GitHub Trending ...

随机推荐

  1. 如何布局包含Image和Title的UIButton

    UIButton中的titleEdgeInsets和imageEdgeInsets可以管理button中image和title的布局.如果对其理解不够深入,用纯数字进行布局管理,经过不断的调试,还是能 ...

  2. 369. Plus One Linked List

    Given a non-negative number represented as a singly linked list of digits, plus one to the number. T ...

  3. WebGL中添加天空盒的两种方法

    天空盒 的添加可以让模型所在的场景非常漂亮,而其原理也是非常简单的,相信看完下面代码就可以明白了. 说到天空盒的两种方法,倒不如说是两种写法,分别用了纹理加载的两个方法:loadTexture和loa ...

  4. echo, print, print_r

    echo 不是函数,没有返回值,因此只是用作输出的话会更快 print 和 print_r 有返回值,区别在于: print 用于打印一个字符串,print_r 可以打印一些复合类型,如: $arr= ...

  5. Pycharm中使用GitHub

    Pycharm是当前进行python开发,尤其是Django开发最好的IDE.GitHub是程序员的圣地,几乎人人都在用. 本文假设你对pycharm和github都有一定的了解,并且希望在pycha ...

  6. 安装Eclipse环境变量的配置,

    window7系统下的 步骤:    第一步:先安装JDK(记住你安装的位置)我安装在D:\Program Files\Java           目录下. 第二步:JDK安装好后,配置环境变量(重 ...

  7. NOIP 考前 并查集复习

    POJ 1182 把一个点拆成x,x+n,x+2*n,x吃y可以表示认为x,y+n是一类的,x+n,y+2*n是一类,x+2*n,y是一类. #include <cstdio> ; ],n ...

  8. 【LeetCode】Sort Colors

    Sort Colors Given an array with n objects colored red, white or blue, sort them so that objects of t ...

  9. Jquery.Form和jquery.validate 的使用

    有些功能需要我们利用Ajax技术进行POST提交表单,这时候就需要用到jquery.Form ,它有两种方式进行提交, AjaxForm和AjaxSubmit方式.            AjaxFo ...

  10. js中的break ,continue, return (转)

    面向对象编程语法中我们会碰到break ,continue, return这三个常用的关键字,那么关于这三个关键字的使用具体的操作是什么呢?我们在使用这三关键字的时候需要注意和需要理解的规则是什么呢? ...