#前言 我的Github主页上写着加入的时间——``Joined on Nov 8, 2010``,那时才大一,在那之后的那长日子里我都没有过到。也许是因为我学的不是计算机,到了今天——``2015.3.9``,我也发现这其实是程序员的社交网站。 过去,曾经有很长的一些时间我试过在Github上连击,也试着去了解别人是如何用好这个工具的。当然粉丝在Github上也是很重要的。 在这里,我会试着将我在Github上学到的东西一一分享出来。 #为什么你应该深入Github 在我大四找工作的时候,试图去寻找一份硬件、物联网相关的工作(ps: 专业是电子信息工程)。尽管简历上写得满满的各种经历、经验,然而并没有卵用。跑了几场校园招聘会后,十份简历(ps: 事先已经有心里准备)一个也没有投出去——因为学校直接被拒。我对霸面什么的一点兴趣都没有,千里马需要伯乐。后来,我加入了Martin Flower所在的公司,当然这是后话了。 这是一个残酷的世界,在学生时代,如果你长得不帅不高的话,那么多数的附加技能都是白搭(ps: 通常富的是看不到这篇文章的)。在工作时期,如果你上家没有名气,那么将会影响你下一份工作的待遇。而,很多东西却会改变这些,Github就是其中一个。 ##我与Github的故事 注册Github的时候大概是大二的时候,我熟悉的时候已经是大四了,现在已经毕业一年了。在过去的近两年里,我试着以几个维度在Github上创建项目: 1. 快速上手框架来实战,即demo 2. 重构别人的代码 3. 创建自己可用的框架 4. 快速构建大型应用 5. 构建通用的框架 ###Github与收获 先说说**与技能无关的收获**吧,毕业设计做的是一个《[最小物联网系统](https://github.com/phodal/iot)》,考虑到我们专业老师没有这方面知识,答辩时会带来问题,尽量往这方面靠拢。当我毕业后,这个项目已经有过百个star了,这样易上手的东西还是比较受欢迎的(ps: 不过这种硬件相关的项目通常受限于Github上硬件开发工程师比较少的困扰)。 毕业后一个月收到PACKT出版社的邮件(ps: 他们是在github上找到我的),内容是关于Review一本[物联网](iot)书籍,即在《[从Review到翻译IT书籍](http://www.phodal.com/blog/review-it-books-with-translate-book/)》中提到的《Learning Internet of Things》。作为一个四级没过的"物联网专家",去审阅一本英文的物联网书籍。。。当然,后来是审阅完了,书上有我的英文简介。 一个月前,收到MANNING出版社的邮件(ps: 也是在github上),关于Review一本[物联网](iot)书籍的目录,并提出建议。 也因此带来了其他更多的东西,当然不是这里的主题。在这里,我们就不讨论各种骚扰邮件,或者中文合作。从没有想象过,我也可以在英语世界有一片小天地。 这些告诉我们,Github上找一个你擅长的主题,那么会有很多人找上你的。 ###Github与成长 过去写过一篇《[如何通过github提升自己](http://www.phodal.com/blog/use-github-grow-self/)》的文章,现在只想说三点: 1. 测试 2. 更多的测试 3. 更多的、更多的、更多的测试 没有测试的项目是很扯淡的,除非你的项目只有一个函数,然后那个函数返回``Hello,World``。 如果你的项目代码有上千行,如果你能保证测试覆盖率可以达到95%以的话,那么我想你的项目不会有太复杂的函数。假使有这样的函数,那么他也是被测试覆盖住的。 如果你在用心做这个项目,那么你看到代码写得不好也会试着改进,即重构。当有了一些,你的技能会不断提升。你开始会试着接触更多的东西,如stub,如mock,如fakeserver。 有一天,你会发现你离不开测试。 然后就会相信: **那些没有写测试的项目都是在耍流氓** ##为什么你应该深入Github 上面我们说的都是我们可以收获到的东西,我们开始尝试就意味着我们知道它可能给我们带来好处。上面已经提到很多可以提升自己的例子了,这里再说说其他的。 ###方便工作 我们可以从中获取到不同的知识、内容、信息。每个人都可以从别人的代码中学习,当我们需要构建一个库的时候我们可以在上面寻找不同的库和代码来实现我们的功能。如当我在实现一个库的时候,我会在Github上到相应的组件: - Promise 支持 - Class类(ps:没有一个好的类使用的方式) - Template 一个简单的模板引擎 - Router 用来控制页面的路由 - Ajax 基本的Ajax Get/Post请求 ###获得一份工作 越来越多的人因为Github获得工作,因为他们的做的东西正好符合一些公司的要求。那么,这些公司在寻找代码的时候,就会试着邀请他们。 因而,在Github寻找合适的候选人,已经是一种趋势。 ###扩大人脉 如果我们想创造出更好、强大地框架时,那么认识更多的人可能会带来更多的帮助。有时候会同上面那一点一样的效果。 #介绍 ###什么是Github Wiki百科上是这么说的 > GitHub 是一个共享虚拟主机服务,用于存放使用Git版本控制的软件代码和内容项目。它由GitHub公司(曾称Logical Awesome)的开发者Chris Wanstrath、PJ Hyett和Tom Preston-Werner 使用Ruby on Rails编写而成。 当然让我们看看官方的介绍: > GitHub is the best place to share code with friends, co-workers, classmates, and complete strangers. Over eight million people use GitHub to build amazing things together. 它还是什么? - 网站 - 免费博客 - 管理配置文件 - 收集资料 - 简历 - 管理代码片段 - 托管编程环境 - 写作 等等。看上去像是大餐,但是你还需要了解点什么? ###版本管理与软件部署 jQuery[^jQuery]在发布版本``2.1.3``,一共有152个commit。我们可以看到如下的提交信息: - Ajax: Always use script injection in globalEval … bbdfbb4 - Effects: Reintroduce use of requestAnimationFrame … 72119e0 - Effects: Improve raf logic … 708764f - Build: Move test to appropriate module fbdbb6f - Build: Update commitplease dev dependency - ... ###Github与Git > Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理。在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中。目前,包括Rubinius、Merb和Bitcoin在内的很多知名项目都使用了Git。Git同样可以被诸如Capistrano和Vlad the Deployer这样的部署工具所使用。 > GitHub可以托管各种git库,并提供一个web界面,但与其它像 SourceForge或Google Code这样的服务不同,GitHub的独特卖点在于从另外一个项目进行分支的简易性。为一个项目贡献代码非常简单:首先点击项目站点的“fork”的按钮,然后将代码检出并将修改加入到刚才分出的代码库中,最后通过内建的“pull request”机制向项目负责人申请代码合并。已经有人将GitHub称为代码玩家的MySpace。 [^jQuery]: jQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作。 ##用好Github ###敏捷软件开发 显然我是在扯淡,这和敏捷软件开发没有什么关系。不过我也不知道瀑布流是怎样的。说说我所知道的一个项目的组成吧: - 看板式管理应用程序(如trello,简单地说就是管理软件功能) - CI(持续集成) - 测试覆盖率 - 代码质量(code smell) 对于一个不是远程的团队(如只有一个人的项目) 来说,Trello、Jenkin、Jira不是必需的: > 你存在,我深深的脑海里 当只有一个人的时候,你只需要明确知道自己想要什么就够了。我们还需要的是CI、测试,以来提升代码的质量。 ###测试 通常我们都会找Document,如果没有的话,你会找什么?看源代码,还是看测试? it("specifying response when you need it", function (done) { var doneFn = jasmine.createSpy("success"); lettuce.get('/some/cool/url', function (result) { expect(result).toEqual("awesome response"); done(); }); expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url'); expect(doneFn).not.toHaveBeenCalled(); jasmine.Ajax.requests.mostRecent().respondWith({ "status": 200, "contentType": 'text/plain', "responseText": 'awesome response' }); }); 代码来源: [https://github.com/phodal/lettuce](https://github.com/phodal/lettuce) 上面的测试用例,清清楚楚地写明了用法,虽然写得有点扯。 等等,测试是用来干什么的。那么,先说说我为什么会想去写测试吧: - 我不希望每次做完一个个新功能的时候,再手动地去测试一个个功能。(自动化测试) - 我不希望在重构的时候发现破坏了原来的功能,而我还一无所知。 - 我不敢push代码,因为我没有把握。 虽然,我不是TDD的死忠,测试的目的是保证功能正常,TDD没法让我们写出质量更高的代码。但是有时TDD是不错的,可以让我们写出逻辑更简单地代码。 也许你已经知道了``Selenium``、``Jasmine``、``Cucumber``等等的框架,看到过类似于下面的测试 Ajax ✓ specifying response when you need it ✓ specifying html when you need it ✓ should be post to some where Class ✓ respects instanceof ✓ inherits methods (also super) ✓ extend methods Effect ✓ should be able fadein elements ✓ should be able fadeout elements 代码来源: [https://github.com/phodal/lettuce](https://github.com/phodal/lettuce) 看上去似乎每个测试都很小,不过补完每一个测试之后我们就得到了测试覆盖率 File | Statements | Branches | Functions | Lines -----|------------|----------|-----------|------ lettuce.js | 98.58% (209 / 212)| 82.98%(78 / 94) | 100.00% (54 / 54) | 98.58% (209 / 212) 本地测试都通过了,于是我们添加了``Travis-CI``来跑我们的测试 ###CI 虽然node.js不算是一门语言,但是因为我们用的node,下面的是一个简单的``.travis.yml``示例: language: node_js node_js: - "0.10" notifications: email: false before_install: npm install -g grunt-cli install: npm install after_success: CODECLIMATE_REPO_TOKEN=321480822fc37deb0de70a11931b4cb6a2a3cc411680e8f4569936ac8ffbb0ab codeclimate < coverage/lcov.info 代码来源: [https://github.com/phodal/lettuce](https://github.com/phodal/lettuce) 我们把这些集成到``README.md``之后,就有了之前那张图。 CI对于一个开发者在不同城市开发同一项目上来说是很重要的,这意味着当你添加的部分功能有测试覆盖的时候,项目代码会更加强壮。 ###代码质量 像``jslint``这类的工具,只能保证代码在语法上是正确的,但是不能保证你写了一堆bad smell的代码。 - 重复代码 - 过长的函数 - 等等 ``Code Climate``是一个与github集成的工具,我们不仅仅可以看到测试覆盖率,还有代码质量。 先看看上面的ajax类: Lettuce.get = function (url, callback) { Lettuce.send(url, 'GET', callback); }; Lettuce.send = function (url, method, callback, data) { data = data || null; var request = new XMLHttpRequest(); if (callback instanceof Function) { request.onreadystatechange = function () { if (request.readyState === 4 && (request.status === 200 || request.status === 0)) { callback(request.responseText); } }; } request.open(method, url, true); if (data instanceof Object) { data = JSON.stringify(data); request.setRequestHeader('Content-Type', 'application/json'); } request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); request.send(data); }; 代码来源: [https://github.com/phodal/lettuce](https://github.com/phodal/lettuce) 在[Code Climate](https://codeclimate.com/github/phodal/lettuce/src/ajax.js)在出现了一堆问题 - Missing "use strict" statement. (Line 2) - Missing "use strict" statement. (Line 14) - 'Lettuce' is not defined. (Line 5) 而这些都是小问题啦,有时可能会有 - Similar code found in two :expression_statement nodes (mass = 86) 这就意味着我们可以对上面的代码进行重构,他们是重复的代码。 ###重构 不想在这里说太多关于``重构``的东西,可以参考Martin Flower的《重构》一书去多了解一些重构的细节。 这时想说的是,只有代码被测试覆盖住了,那么才能保证重构的过程没有出错。 #Git基本知识与Github使用 ##Git 从一般开发者的角度来看,git有以下功能: 1. 从服务器上克隆数据库(包括代码和版本信息)到单机上。 2. 在自己的机器上创建分支,修改代码。 3. 在单机上自己创建的分支上提交代码。 4. 在单机上合并分支。 5. 新建一个分支,把服务器上最新版的代码fetch下来,然后跟自己的主分支合并。 6. 生成补丁(patch),把补丁发送给主开发者。 7. 看主开发者的反馈,如果主开发者发现两个一般开发者之间有冲突(他们之间可以合作解决的冲突),就会要求他们先解决冲突,然后再由其中一个人提交。如果主开发者可以自己解决,或者没有冲突,就通过。 8. 一般开发者之间解决冲突的方法,开发者之间可以使用pull 命令解决冲突,解决完冲突之后再向主开发者提交补丁。 从主开发者的角度(假设主开发者不用开发代码)看,git有以下功能: 1. 查看邮件或者通过其它方式查看一般开发者的提交状态。 2. 打上补丁,解决冲突(可以自己解决,也可以要求开发者之间解决以后再重新提交,如果是开源项目,还要决定哪些补丁有用,哪些不用)。 3. 向公共服务器提交结果,然后通知所有开发人员。 ###Git初入 如果是第一次使用Git,你需要设置署名和邮箱: $ git config --global user.name "用户名" $ git config --global user.email "电子邮箱" 将代码仓库clone到本地,其实就是将代码复制到你的机器里,并交由Git来管理: $ git clone git@github.com:someone/symfony-docs-chs.git 你可以修改复制到本地的代码了(symfony-docs-chs项目里都是rst格式的文档)。当你觉得完成了一定的工作量,想做个阶段性的提交: 向这个本地的代码仓库添加当前目录的所有改动: $ git add . 或者只是添加某个文件: ##Github   多种方式 > …or create a new repository on the command line echo "# github-roam" >> README.md git init git add README.md git commit -m "first commit" git remote add origin git@github.com:phodal/github-roam.git git push -u origin master > …or push an existing repository from the command line git remote add origin git@github.com:phodal/github-roam.git git push -u origin master #Github项目分析一 ##生成图表 如何分析用户的数据是一个有趣的问题,特别是当我们有大量的数据的时候。除了``matlab``,我们还可以用``numpy``+``matplotlib`` 数据可以在这边寻找到 [https://github.com/gmszone/ml](https://github.com/gmszone/ml) 最后效果图  要解析的json文件位于``data/2014-01-01-0.json``,大小6.6M,显然我们可能需要用每次只读一行的策略,这足以解释为什么诸如sublime打开的时候很慢,而现在我们只需要里面的json数据中的创建时间。。 ==,这个文件代表什么? **2014年1月1日零时到一时,用户在github上的操作,这里的用户指的是很多。。一共有4814条数据,从commit、create到issues都有。** ###数据解析 ```python import json for line in open(jsonfile): line = f.readline() ``` 然后再解析json ```python import dateutil.parser lin = json.loads(line) date = dateutil.parser.parse(lin["created_at"]) ``` 这里用到了``dateutil``,因为新鲜出炉的数据是string需要转换为``dateutil``,再到数据放到数组里头。最后有就有了``parse_data`` ```python def parse_data(jsonfile): f = open(jsonfile, "r") dataarray = [] datacount = 0 for line in open(jsonfile): line = f.readline() lin = json.loads(line) date = dateutil.parser.parse(lin["created_at"]) datacount += 1 dataarray.append(date.minute) minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)] f.close() return minuteswithcount ``` 下面这句代码就是将上面的解析为 ```python minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)] ``` 这样的数组以便于解析 ```python [(0, 92), (1, 67), (2, 86), (3, 73), (4, 76), (5, 67), (6, 61), (7, 71), (8, 62), (9, 71), (10, 70), (11, 79), (12, 62), (13, 67), (14, 76), (15, 67), (16, 74), (17, 48), (18, 78), (19, 73), (20, 89), (21, 62), (22, 74), (23, 61), (24, 71), (25, 49), (26, 59), (27, 59), (28, 58), (29, 74), (30, 69), (31, 59), (32, 89), (33, 67), (34, 66), (35, 77), (36, 64), (37, 71), (38, 75), (39, 66), (40, 62), (41, 77), (42, 82), (43, 95), (44, 77), (45, 65), (46, 59), (47, 60), (48, 54), (49, 66), (50, 74), (51, 61), (52, 71), (53, 90), (54, 64), (55, 67), (56, 67), (57, 55), (58, 68), (59, 91)] ``` ###Matplotlib 开始之前需要安装``matplotlib ```bash sudo pip install matplotlib ``` 然后引入这个库 import matplotlib.pyplot as plt 如上面的那个结果,只需要
plt.figure(figsize=(8,4))
plt.plot(x, y,label = files)
plt.legend()
plt.show()
最后代码可见
```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import dateutil.parser
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
def parse_data(jsonfile):
f = open(jsonfile, "r")
dataarray = []
datacount = 0
for line in open(jsonfile):
line = f.readline()
lin = json.loads(line)
date = dateutil.parser.parse(lin["created_at"])
datacount += 1
dataarray.append(date.minute)
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
f.close()
return minuteswithcount
def draw_date(files):
x = []
y = []
mwcs = parse_data(files)
for mwc in mwcs:
x.append(mwc[0])
y.append(mwc[1])
plt.figure(figsize=(8,4))
plt.plot(x, y,label = files)
plt.legend()
plt.show()
draw_date("data/2014-01-01-0.json")
```
##每周分析
继上篇之后,我们就可以分析用户的每周提交情况,以得出用户的真正的工具效率,每个程序员的工作时间可能是不一样的,如

这是我的每周情况,显然如果把星期六移到前面的话,随着工作时间的增长,在github上的使用在下降,作为一个
a fulltime hacker who works best in the evening (around 8 pm).
不过这个是osrc的分析结果。
###python github 每周情况分析
看一张分析后的结果

结果正好与我的情况相反?似乎图上是这么说的,但是数据上是这样的情况。
data
├── 2014-01-01-0.json
├── 2014-02-01-0.json
├── 2014-02-02-0.json
├── 2014-02-03-0.json
├── 2014-02-04-0.json
├── 2014-02-05-0.json
├── 2014-02-06-0.json
├── 2014-02-07-0.json
├── 2014-02-08-0.json
├── 2014-02-09-0.json
├── 2014-02-10-0.json
├── 2014-02-11-0.json
├── 2014-02-12-0.json
├── 2014-02-13-0.json
├── 2014-02-14-0.json
├── 2014-02-15-0.json
├── 2014-02-16-0.json
├── 2014-02-17-0.json
├── 2014-02-18-0.json
├── 2014-02-19-0.json
└── 2014-02-20-0.json
我们获取是每天晚上0点时的情况,至于为什么是0点,我想这里的数据量可能会比较少。除去1月1号的情况,就是上面的结果,在只有一周的情况时,总会以为因为在国内那时是假期,但是总觉得不是很靠谱,国内的程序员虽然很多,会在github上活跃的可能没有那么多,直至列出每一周的数据时。
6570, 7420, 11274, 12073, 12160, 12378, 12897,
8474, 7984, 12933, 13504, 13763, 13544, 12940,
7119, 7346, 13412, 14008, 12555
###Python 数据分析
重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack
```python
def get_minutes_counts_with_id(jsonfile):
datacount, dataarray = handle_json(jsonfile)
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
return minuteswithcount
def handle_json(jsonfile):
f = open(jsonfile, "r")
dataarray = []
datacount = 0
for line in open(jsonfile):
line = f.readline()
lin = json.loads(line)
date = dateutil.parser.parse(lin["created_at"])
datacount += 1
dataarray.append(date.minute)
f.close()
return datacount, dataarray
def get_minutes_count_num(jsonfile):
datacount, dataarray = handle_json(jsonfile)
return datacount
def get_month_total():
"""
:rtype : object
"""
monthdaycount = []
for i in range(1, 20):
if i < 10:
filename = 'data/2014-02-0' + i.__str__() + '-0.json'
else:
filename = 'data/2014-02-' + i.__str__() + '-0.json'
monthdaycount.append(get_minutes_count_num(filename))
return monthdaycount
```
接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程?
###Python Matplotlib图表
让我们的matplotlib来做这些图表的工作
```python
if __name__ == '__main__':
results = pd.get_month_total()
print results
plt.figure(figsize=(8, 4))
plt.plot(results.__getslice__(0, 7), label="first week")
plt.plot(results.__getslice__(7, 14), label="second week")
plt.plot(results.__getslice__(14, 21), label="third week")
plt.legend()
plt.show()
```
蓝色的是第一周,绿色的是第二周,蓝色的是第三周就有了上面的结果。
我们还需要优化方法,以及多线程的支持。
#Github项目分析二
让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章[http://www.huyng.com/posts/python-performance-analysis/](http://www.huyng.com/posts/python-performance-analysis/)讲的就是分析这部分内容的。
##Time Python分析
分析程序的运行时间
```bash
$time python handle.py
```
结果便是,但是对于我们的分析没有一点意义
```
real 0m43.411s
user 0m39.226s
sys 0m0.618s
```
##line_profiler python
```bash
sudo ARCHFLAGS="-Wno-error=unused-command-line-argument-hard-error-in-future" easy_install line_profiler
```
然后在我们的``parse_data.py``的``handle_json``前面加上``@profile``
```python
@profile
def handle_json(jsonfile):
f = open(jsonfile, "r")
dataarray = []
datacount = 0
for line in open(jsonfile):
line = f.readline()
lin = json.loads(line)
date = dateutil.parser.parse(lin["created_at"])
datacount += 1
dataarray.append(date.minute)
f.close()
return datacount, dataarray
```
Line_profiler带了一个分析脚本``kernprof.py``,so
```bash
kernprof.py -l -v handle.py
```
我们便会得到下面的结果
```
Wrote profile results to handle.py.lprof
Timer unit: 1e-06 s
File: parse_data.py
Function: handle_json at line 15
Total time: 127.332 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
15 @profile
16 def handle_json(jsonfile):
17 19 636 33.5 0.0 f = open(jsonfile, "r")
18 19 21 1.1 0.0 dataarray = []
19 19 16 0.8 0.0 datacount = 0
20
21 212373 730344 3.4 0.6 for line in open(jsonfile):
22 212354 2826826 13.3 2.2 line = f.readline()
23 212354 13848171 65.2 10.9 lin = json.loads(line)
24 212354 109427317 515.3 85.9 date = dateutil.parser.parse(lin["created_at"])
25 212354 238112 1.1 0.2 datacount += 1
26 212354 260227 1.2 0.2 dataarray.append(date.minute)
27
28 19 349 18.4 0.0 f.close()
29 19 20 1.1 0.0 return datacount, dataarray
```
于是我们就发现我们的瓶颈就是从读取``created_at``,即创建时间。。。以及解析json,反而不是我们关心的IO,果然``readline``很强大。
##memory_profiler
首先我们需要install memory_profiler:
```bash
$ pip install -U memory_profiler
$ pip install psutil
```
如上,我们只需要在``handle_json``前面加上``@profile``
```bash
python -m memory_profiler handle.py
```
于是
```
Filename: parse_data.py
Line # Mem usage Increment Line Contents
================================================
13 39.930 MiB 0.000 MiB @profile
14 def handle_json(jsonfile):
15 39.930 MiB 0.000 MiB f = open(jsonfile, "r")
16 39.930 MiB 0.000 MiB dataarray = []
17 39.930 MiB 0.000 MiB datacount = 0
18
19 40.055 MiB 0.125 MiB for line in open(jsonfile):
20 40.055 MiB 0.000 MiB line = f.readline()
21 40.066 MiB 0.012 MiB lin = json.loads(line)
22 40.055 MiB -0.012 MiB date = dateutil.parser.parse(lin["created_at"])
23 40.055 MiB 0.000 MiB datacount += 1
24 40.055 MiB 0.000 MiB dataarray.append(date.minute)
25
26 f.close()
27 return datacount, dataarray
```
##objgraph python
安装objgraph
```bash
pip install objgraph
```
我们需要调用他
```python
import pdb;
```
以及在需要调度的地方加上
```python
pdb.set_trace()
```
接着会进入``command``模式
```python
(pdb) import objgraph
(pdb) objgraph.show_most_common_types()
```
然后我们可以找到。。
```
function 8259
dict 2137
tuple 1949
wrapper_descriptor 1625
list 1586
weakref 1145
builtin_function_or_method 1117
method_descriptor 948
getset_descriptor 708
type 705
```
也可以用他生成图形,貌似这里是用``dot``生成的,加上``python-xdot``
很明显的我们需要一个数据库。
如果我们每次都要花同样的时间去做一件事,去扫那些数据的话,那么这是最好的打发时间的方法。
##python SQLite3 查询数据
我们创建了一个名为``userdata.db``的数据库文件,然后创建了一个表,里面有owner,language,eventtype,name url
```python
def init_db():
conn = sqlite3.connect('userdata.db')
c = conn.cursor()
c.execute('''CREATE TABLE userinfo (owner text, language text, eventtype text, name text, url text)''')
```
接着我们就可以查询数据,这里从结果讲起。
```python
def get_count(username):
count = 0
userinfo = []
condition = 'select * from userinfo where owener = \'' + str(username) + '\''
for zero in c.execute(condition):
count += 1
userinfo.append(zero)
return count, userinfo
```
当我查询``gmszone``的时候,也就是我自己就会有如下的结果
```bash
(u'gmszone', u'ForkEvent', u'RESUME', u'TeX', u'https://github.com/gmszone/RESUME')
(u'gmszone', u'WatchEvent', u'iot-dashboard', u'JavaScript', u'https://github.com/gmszone/iot-dashboard')
(u'gmszone', u'PushEvent', u'wechat-wordpress', u'Ruby', u'https://github.com/gmszone/wechat-wordpress')
(u'gmszone', u'WatchEvent', u'iot', u'JavaScript', u'https://github.com/gmszone/iot')
(u'gmszone', u'CreateEvent', u'iot-doc', u'None', u'https://github.com/gmszone/iot-doc')
(u'gmszone', u'CreateEvent', u'iot-doc', u'None', u'https://github.com/gmszone/iot-doc')
(u'gmszone', u'PushEvent', u'iot-doc', u'TeX', u'https://github.com/gmszone/iot-doc')
(u'gmszone', u'PushEvent', u'iot-doc', u'TeX', u'https://github.com/gmszone/iot-doc')
(u'gmszone', u'PushEvent', u'iot-doc', u'TeX', u'https://github.com/gmszone/iot-doc')
109
````
一共有109个事件,有``Watch``,``Create``,``Push``,``Fork``还有其他的,
项目主要有``iot``,``RESUME``,``iot-dashboard``,``wechat-wordpress``,
接着就是语言了,``Tex``,``Javascript``,``Ruby``,接着就是项目的url了。
值得注意的是。
```bash
-rw-r--r-- 1 fdhuang staff 905M Apr 12 14:59 userdata.db
```
这个数据库文件有**905M**,不过查询结果相当让人满意,至少相对于原来的结果来说。
Python自带了对SQLite3的支持,然而我们还需要安装SQLite3
```bash
brew install sqlite3
```
或者是
```bash
sudo port install sqlite3
```
或者是Ubuntu的
```bash
sudo apt-get install sqlite3
```
openSUSE自然就是
```bash
sudo zypper install sqlite3
```
不过,用yast2也很不错,不是么。。
###数据导入
需要注意的是这里是需要python2.7,起源于对gzip的上下文管理器的支持问题
```python
def handle_gzip_file(filename):
userinfo = []
with gzip.GzipFile(filename) as f:
events = [line.decode("utf-8", errors="ignore") for line in f]
for n, line in enumerate(events):
try:
event = json.loads(line)
except:
continue
actor = event["actor"]
attrs = event.get("actor_attributes", {})
if actor is None or attrs.get("type") != "User":
continue
key = actor.lower()
repo = event.get("repository", {})
info = str(repo.get("owner")), str(repo.get("language")), str(event["type"]), str(repo.get("name")), str(
repo.get("url"))
userinfo.append(info)
return userinfo
def build_db_with_gzip():
init_db()
conn = sqlite3.connect('userdata.db')
c = conn.cursor()
year = 2014
month = 3
for day in range(1,31):
date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz")
fn_template = os.path.join("march",
"{year}-{month:02d}-{day:02d}-{n}.json.gz")
kwargs = {"year": year, "month": month, "day": day, "n": "*"}
filenames = glob.glob(fn_template.format(**kwargs))
for filename in filenames:
c.executemany('INSERT INTO userinfo VALUES (?,?,?,?,?)', handle_gzip_file(filename))
conn.commit()
c.close()
```
``executemany``可以插入多条数据,对于我们的数据来说,一小时的文件大概有五六千个会符合我们上面的安装,也就是有``actor``又有``type``才是我们需要记录的数据,我们只需要统计用户的那些事件,而非全部的事件。
我们需要去遍历文件,然后找到合适的部分,这里只是要找``2014-03-01``到``2014-03-31``的全部事件,而光这些数据的gz文件就有1.26G,同上面那些解压为json文件显得不合适,只能用遍历来处理。
这里参考了osrc项目中的写法,或者说直接复制过来。
首先是正规匹配
```python
date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz")
```
不过主要的还是在于``glob.glob``
> glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索,支持通配符操作。
这里也就用上了``gzip.GzipFile``又一个不错的东西。
最后代码可以见
[github.com/gmszone/ml](http://github.com/gmszone/ml)
更好的方案?
##Redis
查询用户事件总数
```python
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
pipe = pipe = r.pipeline()
pipe.zscore('osrc:user',"gmszone")
pipe.execute()
```
系统返回了``227.0``,试试别人。
```bash
>>> pipe.zscore('osrc:user',"dfm")