<![CDATA[梁杰的个人博客]]> 2017-12-31T22:03:00.502Z http://yoursite.com/ Hexo <![CDATA[寏VWIRED》一文章的分析]]> http://yoursite.com/2018/01/01/20171231/ 2017-12-31T22:03:00.502Z 2017-12-31T22:03:00.502Z d?Zinio 订阅了《WIRED》的电子版,最q空闲时间比较多Q就开始一本一本读?/p>

《WIRED》中文名是“连U쀝,q本杂志的主~和作者里一大堆名hQ比如著名的凯文凯利。如果你q没看过的话Q强烈推荐。Zinio 订阅地址Q一q?12 期,按年订也׃癑֤人民币,直白菜h?/p>

WIRED 主要x新兴U技Ҏ化、经和政治的媄响。我个h觉得QWIRED 的目标读者是国中年白领Q就是U每天衬衫西服,开车上班,I闲旉边喝咖啡边看杂志的h。在q种背景下,WIRED 的作者就需要非常强的写作功底,把晦涩难懂的U技内容用容易理解的方式讲述出来?/p>

在最C期的 WIRED 中我d了一非常棒的文章。ؓ了学习作者的文章l构和写作手法,我准备在q篇文章中对它进行分析?/p>

要分析的q篇文章?THE OVERWATCH VIDEOGAME LEAGUE AIMS TO BECOME THE NEW NFL。这文章很长,你先d再往下看?/p>

好的Q假设你已经d了文章。想必你已经产生了一些和我一L感想。作者用q么长的幅从各个角度对守望先锋做了介绍Q最隑־的是内容一炚w不枯燥,读v来就像小_实在是太厉害了。堆字数不难Q讲故事不难Q下定义不难Q但是把三者结合v来确实不Ҏ?/p>

我从两个斚wҎ章进行分析,一个是文章l构Q一个是写作手法?/p>

文章l构

文章一共有 113 个自然段Q下面是每段的主体内容:

自然D늼?/th> 内容 备注
1 主角是职业运动员 引出主角Q让人想往下阅?/td>
2 主角每天的日E?/td>
3 你可能从没听q他。介l电子竞技的特?/td>
4 Ƣ迎来到未来的体?/td>
5 电子竞技是一个新东西
6 但是对于主角q类职业玩家来说Q不新Q同时说明主角对其他东西都不感兴?/td>
7 但是主角对一个东西很感兴?/td>
8 Z么选择守望先锋
9 q不是因为喜Ƣ游戏才?/td>
10 他ؓ了成业玩家投入的旉和牺?/td>
11 他ƈ不像你想的那栯?/td>
12 他在游戏上的发展Q有公司想签
13 妈妈担心未来发展
14 游戏开发负责h视角Q已l有了多ƾ游戏,下一N什么背景?
15 地球
16 团队开始开发这个游?/td>
17 q类游戏目前的现Ӟ有点黑暗
18 开发团队确定游戏基调:乐观
19 游戏背景介绍
20 游戏人物介绍
21 游戏模式介绍
22 游戏受欢q,快速发?/td>
23 游戏官方人员介绍Z么受Ƣ迎
24 官方人员发现守望先锋的竞技潜力Q顺便介l电子竞技的现?/td>
25 游戏初期开始有很多人组l比赛,官方认ؓ可以考虑丑֊官方比赛
26 守望先锋联赛p栯生了
27 暴雪宣布官方联赛Q以及粉丝的参与Ҏ
28 联赛负责q会是新sportQ如果你怀疑,联赛丑֊权售价两亿美?/td>
29 负责的两句话Q小孩会很自豪看守望先锋比赛
30 联赛团队有h来自传统体育行业Q介l他的看?/td>
31 l箋补充他的看法
32 和传lsportҎQ新sport一般免费观?/td>
33 观众体q龄Ҏ
34 介绍联赛场地
35 详细介绍场地配置
36 l箋介绍场地
37 l箋介绍场地Q同时介l解?/td>
38 介绍OB
39 Ml团队h敎ͼ同时回顾sport刚出现时候的批评
40 作者第一ơ玩守望先锋的感受,有两炚w惊,W一Ҏ同时需要处理的信息非常?/td>
41 W二Ҏȝơ数很多
42 描述了一个场景,在玩的时候死掉了Q不知道Z么,然后引出M回放
43 M回放
44 介绍M回放的作?/td>
45 需要思考队伍配|,敌我ҎQ信息量很大
46 l箋介绍Q提出问题,q么难要怎么成ؓ职业玩家Q带着问题M角居住的地方L{案
47 到达的时?看到的景?/td>
48 介绍居住的房?/td>
49 团队每天要锻Dn体。我到的时候他们在准备W一个scrim
50 介绍什么是scrimQ一U训l模?/td>
51 队伍训练时候的喊话
52 队伍训练时候的喊话
53 队伍训练时候的喊话
54 队伍训练时候的喊话
55 队伍训练时候的喊话
56 厨师同时在做?/td>
57 大家不叫真名Q叫ID
58 队伍来自各个国家
59 队伍负责人在观察成员
60 队伍都是q轻人,戉K很ؕ
61 卫生间更?/td>
62 介绍负责人对此的看法
63 在休息时间问出问?/td>
64 队员解答
65 介绍q位队员
66 问什么是flick
67 介绍flick
68 成功不只是天?/td>
69 午饭之后l箋训练
70 队伍训练时候的喊话
71 队伍训练时候的喊话
72 队伍训练时候的喊话
73 队伍训练时候的喊话
74 队伍训练时候的喊话
75 介绍什么是monkey
76 主角Ҏ赛的期待
77 介绍主角所在的战队
78 介绍工资待遇和合?/td>
79 现在的合同正式多?不会随便解雇
80 战队待遇 q有比赛奖金
81 队员对合同变化的看法
82 没有x队?/td>
83 介绍一个知名女性玩?/td>
84 她对游戏环境的看?/td>
85 女玩家处境恶?/td>
86 骂女玩家的话
87 骂女玩家的话
88 骂女玩家的话
89 骂女玩家的话
90 省略了很?/td>
91 她的评h和感?/td>
92 很多女玩安是这L感受Q列丑֥玩家保护自己的方式,包括采访对象假名防止之后求职被发现她的这些言?/td>
93 她的感受
94 官方Ҏ的解x案,但是问题q是存在
95 另一个女玩家的体验,队友不敢批评?/td>
96 Ҏ有成业玩Ӟ但是开始D办比赛,惌官方工作
97 她对q类事g的评?/td>
98 官方的措?/td>
99 官方支持的作?/td>
100 官方的发a
101 官方的考虑Q其实官方也很难?/td>
102 回到训练地点Q已l晚上了Q最后一个scrim
103 介绍两队的队员对?/td>
104 Ҏ战队的训l策?/td>
105 电子竞技对年龄要求很?/td>
106 主角也说q类似的?/td>
107 主角成ؓ职业玩家时候有很多不确定因素,前途ƈ不明?/td>
108 那ؓ什么他q要做职业玩Ӟ主角说是惌明自?/td>
109 作者同意,q和音乐人、演员和作家一?/td>
110 同时Q队员找C应对Ҏ
111 赢了
112 负责?/td>
113 天黑?/td>

l箋整理Q全文按照大主题可以划分成如下几块:

主题 自然D?/th>
开?/td> 1-4
介绍主角和电子竞技 5-13
介绍游戏开发过E?/td> 14-18
介绍游戏 19-21
游戏受欢q,介绍联赛和执行团?/td> 22-33
介绍联赛场地 34-39
作者游戏感?/td> 40-46
描述训练场地和训l过E?/td> 47-75
介绍职业选手现状Q和q去Ҏ 76-81
x玩家少Q相兌论,官方措施和观?/td> 82-101
l尾 102-113

从结构上可以看到Q作者从很多个角度进行了描写。全文穿插了职业选手?strong>游戏官方?strong>作者自?/strong>三个角色Q每个角色里又从不同人的角度q行描写Q让读者能从多个角度了解守望先锋?/p>

q里面,作者自׃表的是读者,一个从来没有接触过电子竞技的h。他自己的采访和描写Q就是读者了解电子竞技和守望先锋的q程?/p>

从结构上也可以学习描q方法。对一个事物进行描q有多个角度Q但是文章本w是U性的Q所以描q顺序就很重要?/p>

本文的顺序是q到线Q由U到面。先从主角讲P引出电子竞技Q然后引出开发公司,到这里算是完成了背景介绍。接着介绍游戏发售后很受欢q,官方产生做联赛的xQ然后引赛场圎ͼq时读者已l对电子竞技有了一个比较直观的感受Q能和传l体育进行对比。到q里是完成了整体介l,下面作者从自己游戏体验开始,介绍了很多游戏细节,让读者对游戏有更深入的理解。同时引出新问题Ql采ѝ在采访q程中,也描写了战队的生zL况和训练方式Q又加深了读者对职业选手的理解。最后提到性别问题Q描q完成后回到训练场地Q简z有力的收尾?/p>

M来说Q要介绍一个东襉K?strong>扑֥切入?/strong>Q一般是一个h。由q个人引Zpd背景介绍Q让读者徏立整体印象。然后l引讨论的大主题Q从多个角度讨论Q最好有详细的数据。接着讲自q体验Q把视角拉回ChQ补充更多细节内宏V最后补充讨论几个独立的问题Q然后收?/p>

q样完成了一有意思、有深度、多角度的介l性文章?/p>

时刻谨记Q你的读者没有Q何相兌景知识?/p>

写作手法

写作手法是一个比较玄的东西,每个人看都能ȝ出来不同的手法,我只说我看到的?/p>

人物说的话很重要

文章多次引用被采访对象的发言Q有三个好处?/p>

W一个好处是直观Qh对于其他的话有本能的重视Q读者看到双引号׃佛听到对方在说话Q比起^铺直叙更能让读者仔l阅诅R?/p>

W二个好处是客观Q把你想表达的东西放到对话背后,让读者自己去品位Q这样不仅更能获得读者认同,读v来也更有意思?/p>

W三个好处是对话能承上启下。文章中多次用对话承上启下,引出新的内容?/p>

长短自然D늻合,以短Z

U观全文Q长自然D늚数量非常,而且主要出现在开头部分。读者的注意力是在持l下降的Q一开始的背景介绍可以适当NQ但是后面的描写部分量拆成短自然段Q方侉K诅R另外,很多对话都可以单独成D,一斚w让读者喘口气Q另一斚w让对话更有力。非对话的单句自然段大多用来Q或者强行ȝQ比如“这p生了守望先锋联赛”)?/p>

d?Zinio 订阅了《WIRED》的电子版,最q空闲时间比较多Q就开始一本一本读?/p>

《WIRED》中文名是“连U쀝,q本杂志的主~和作者里一大堆名hQ比如著名的凯文凯利。如果你q没看过的话Q强烈推荐。Zinio 一直想找个手机上最合适的看书工具。前D|间买?Safari Books Online 的包q服务,但是 SFO 大部分都是技术书Q手机又不能边看边写代码Q所以一直在找替代品?/p>

之前q常看 Tinyfool 老师推荐 kindle 的英文电子书Q看了一下确实有不少好书Q于是决定折腾一下,搞个亚账号C?/p>

q程不算复杂Q不q也是一波三折,记录下来供大家参考?/p>

准备工作

要在亚CQ你需要:

  • 一张带 Visa/MasterCard/JCB/银联 标志的信用卡
  • 一台可以上|的电脑
  • 能看懂英?/li>

国亚马?/a>注册一个̎受注意这个̎h好不要和你的中国亚马逊相同,如果使用同一个邮注册,要设|不同的密码。最好是用两个不同的邮箱?/p>

注册完毕之后会自动登录,鼠标Ud到菜单栏右侧的“Your Account”,点击下拉列表中的“Your Account”,如下图所C?/p>

Your Account

扑ֈ下图所C的模块Q点几ZManage Payment Options”?/p>

Manage Payment Options

然后点击“Manage 1-Click settings”,如下图所C。这个是一键付ƾ,讄好之后看到想买的电子书点一下就可以直接下单付款?/p>

Manage 1-Click settings

点击“Enter a new address”,如下图所C?/p>

Enter a new address

q里是亚C西最重要的一步——填写地址。美亚会验证地址是否可用Q所以瞎写是不行的。虽然我们买电子书不需要邮寄,但是如果不设|地址没有办法下单付ƾ?/p>

怎么办呢Q很单,我找C一个随机生成可用美国地址的网站:Random Valid US AddressQ打开之后׃看到一个随机地址Q如下所C:

随机地址

我已l标注了对应的字D,把地址填写C马逊的面中:

填写地址

“Full name?写你的名字,“Phone number?随便写写pQ我q里是写了我的手机号Q前面的 86 是国家编码?/p>

填完之后点下面的“Save & Continue”,可以看到提交成功:

提交成功

地址d完了Q下一步是d付款方式。在同一个页面下方,点击“Edit”,如下图所C?/p>

Edit

q里正常填你的信用卡信息卛_Q填完点左下方的“Use this address”,q样p|完毕了?/p>

接下来需要设|一下国家?/p>

首先q是点击右上角的“Your Account”,然后一直往下翻Q找到“Manage Your Content and Devices”,点击Q如下所C?/p>

Manage Your Content and Devices

会进入新面。中间有三个大按钮,点击最双的“Settings”,会看C个“Country Settings”,点“Change”,会弹Z个地址选择框,点第一个下拉列表,选择你刚才添加的那个地址Q然后点“Update”。这样你的“Current country”就会变成“United States”。之后如果想换到其他Z是同LҎQ先创徏地址Q然后到q里切换国家?/p>

现在你已l可以买书了Q但是书不会自动发到你的讑֤Q因个新账号q没有绑?kindle 讑֤?/p>

在你的手Z下蝲一?kindle 应用Q中国区的就可以Q然后用新注册的账号d。登陆之后在讄里可以看C个“【发送至KINDLE】电子邮”,在网中把这个邮p|成自动发送即可(如果不知道怎么讄可以搜一下,中文版和英文版设|方法一P?/p>

现在你就可以C了!L一?kindle 电子书,直接点“Buy now with 1-Click”就会自动下单付ƾ,{几分钟׃自动同步到手Z?/p> ]]>

一直想找个手机上最合适的看书工具。前D|间买?Safari Books Online 的包q服务,但是 SFO 大部分都是技术书Q手机又不能边看边写代码Q所以一直在找替代品?/p>

之前q常看 Tinyfool 老师推荐 kindle 的英文电子书Q看了一下确实]]>

<![CDATA[?Docker 快速配|前端开发环境]]> http://yoursite.com/2016/09/26/20160926_?Docker 快速配|前端开发环? 2016-09-26T00:00:00.000Z 2019-05-05T12:25:57.201Z Docker

1
/*
我不是 Docker 专家
文章有错误之处欢迎指出,欢迎各种交流讨论
*/

q篇文章写于三年前,有些内容已经q时Q大家在阅读旉点参考思\卛_Q具体的实现Ҏ和技术最好再搜烦一下相兌料?/p>

Samba 部分用评Z提到?Volume 功能替换Q更加方ѝ?/p>

文章l尾的招聘信息已l失效?/p>

—?019.5.5

今天是你入职W一天?/p>

你v了个大早Q洗漱干净带着材料d职?/p>

{了合同Q领了机器,坐到工位Q一杯袋装红Ӟ按下开机键Q输入密码,

然后Q下?Chrome、Postman、Sublime、盗?PS、NodeJS、配|?NODE_PATH、安?cnpm、安?gulp、安?webpack、安?browserify、安?LessSassStylus、安?JadeCoffeePostCSS、安?BabelExpressKoa、安?gitpm2forever…?/p>

此处省略一万个插g?/p>

如果利的话q个时候你应该已经准备下班了,当然Q通常来说都不利?/p>

在这个过E中Q你可能会遇到网l问题环境问题兼定w题权限问题配|问题配|问题配|问题配|问题配|问题配|问题配|问题?/p>

ChW一周周报:

  • 本周工作Q配|环境,熟悉目

大公司的解决Ҏ

“开发机?/strong>?/p>

开发机模式

大公司的思\很简单:既然你自己搞q么ȝQ那我帮你搞好,l你个̎P直接d上去开发?/p>

实没毛病,不过q个Ҏ必须解决三个问题Q?/p>

  1. 怎么在本机预览网?/li>
  2. 怎么在本机编辑文?/li>
  3. 怎么在外|访问开发机

解决Ҏ有很多,q里只说一U:Nginx + Samba + VPN?/p>

Nginx 可以解决W一个问题。每个工E师分配一个̎P每个账号对应一个域名,Nginx 会把域名解析到对应用L目录下,q样开发就可以在自q脑上用域名预览网(需要配|好 hostQ。D个例子,我的账号?liangjieQ项目的域名?www.wisdomtmt.comQ那我访?liangjie.wisdomtmt.com 可以预览开发机?liangjie 账号下的目?/p>

Samba 可以解决W二个问题。你可以把它理解?Windows 中的“共享文件夹”。在开发机上配|好 SambaQ然后在自己机器上连接开发机Q把׃n文gҎ到编辑器中就可以写代码了?/p>

VPN 可以解决W三个问题。大公司除了专用的YӞq会配套使用g来提高安全系数。VPN gcM U 盾,上面昄一串动态数字密码,定时hQ每ơ外|登?VPN 都需要附加动态密码?/p>

q样p决了问题Q开发h员可以在自己机器上写代码Q然后在览器中直接预览Q遇到意外情况也可以外网d开发机修复?/p>

_略来看Q这套方案没什么技术问题。但是对于中型公司来说Q搭建整套开发机环境、规范开发流E、规?VPN 使用程、全公司切到开发机Q这一套走下来需要的旉和h力成本都不低。通常来说也只有大公司才玩得v?/p>

那小公司呢?N每个新员工都必须费旉来配|环境?

当然不是?/p>

主角d?/p>

什么是 DockerQ我不是 Docker 专家Q所以这里不?Docker 做专业介l。如果你q不知道 Docker 是什么,把它看成虚拟机就可以了?/p>

在引?Docker 之前Q我对它做了一些调研,主要x清楚以下几个问题Q?/p>

  1. Docker 能否跨^収ͼQ毕竟你不能要求公司l所有h?MacQ?/li>
  2. 如何预览 Docker 里的|页Q?/li>
  3. 如何~辑 Docker 里的文gQ?/li>
  4. Docker 能否实现一ơ配|多处用?

׃ Docker q行在每个h的机器上Q因此不存在外网讉K问题?/p>

l过调研Q上q问题理Z都可以解冻I下面是初步确定的解决ҎQ?/p>

  1. ?Kitematic 客户端实现跨q_q行 Docker
  2. 用端口映预?Docker 里的|页
  3. ?Samba + 端口映射~辑 Docker 里的文g
  4. 配置一个通用?ImageQ镜像)

q里面有几个概念需要解释?/p>

首先QKitematic 是一?Docker GUIQ有了它你就不用和命令行打交道,会方便不?/p>

其次QDocker 中最重要的三个概忉| ContainerQ容器)、ImageQ镜像)?VolumeQ卷Q?/p>

Image 是静态内容,如果你要把某?Image 跑v来,那就需要一?Container。这里面有一点很重要Q?strong>Container 中所做的改动不会保存?Image。D个例子,你跑h一?Ubuntu ImageQ然?touch wisdomtmt 创徏一个新文gQ这时候如果直接重?ContainerQ文件就没了。那怎么保存改动Q很单,执行 docker commit ContainerID TAG 卛_。这里的 commit ?git commit cMQ执行之后会把当前状态保存ؓ一个新 Image?/p>

有同学就要问了,如果每次做改动都?commitQ我写v代码来岂不是很不方便Q万一写到一半不心重启 Docker 怎么办?

q确实是个问题,Docker 也有对应的解x法:使用 Volume?/p>

单来_Volume 是专门存放数据的文件夹Q启?Image 时可以挂载一个或多个 VolumeQVolume 中的数据独立?ImageQ重启不会丢失。我们创Z?VolumeQ挂载到pȝ的一个目录下Q然后把代码都放q去可以了?/p>

最后说端口映射。前面说q,Docker 可以看做一个虚拟机Q你的所有文仉在里面。如果你?Container 中运行一个服务器Q监?127.0.0.1:8000Q从你自q机器上直接访?http://127.0.0.1:8000 是不行的Q因?Container 和你的机器是两个不同的环境?/p>

那怎么办呢Q我们先来看一个大安熟悉的问题?/p>

日常开发中我们l常需要让同事预览|页效果Q常用的Ҏ是监?0.0.0.0:8000Q然后让同事q接同一个局域网Q访?http://你的机器IP:8000 卛_?/p>

Container 的问题非常相|只不q我们自己变成了“同事”,需要访?Docker 内部的网c看h只要拿到 Container ?IP 问题p决了?/p>

q运的是QContainer 实?IP?/p>

通常情况下这?IP ?192.168.99.100Q只能从 Container 的宿LQ也是q行 Docker 的机器)讉K。不q?Container 的情冉|些特别,它只兌?IPQ没有关联端口。因此如果想要访?Container 内部的端口(比如 8000Q,你需要手动配|端口映,?Container 内部的端口映到 IP 上?/p>

好了Q枯燥的概念讲完了,理解不了也不用着急,跟着下一章走一遍流E就懂了?/p>

动手

正式开工之前,先看看我们都要做什么?/p>

目标Q配|一个通用 ImageQ支持预览网,支持 Samba ׃n文gQ预装开发过E中可能用到的包?/p>

q程Q?/p>

  1. 下蝲q安?Docker Toolbox
  2. 下蝲q运?Ubuntu 镜像
  3. 做常规的初始化工作(换源、安装常用工P
  4. 安装前端开发工?/li>
  5. 安装和配|?Samba
  6. 配置端口映射
  7. 导出镜像

Let’s rock!

1. 下蝲q安?Docker Toolbox

Docker Toolbox ?Docker 官方开发的 Docker 套装Q里面有全套 Docker 环境Q也有图形化工具 KitematicQ直接下载安装即可?/p>

Docker Toolbox 支持 Windows ?Mac OSQ可以到官网下蝲安装Q这一步如果没?VPN 会比较耗时Q最好把两个q_的安装包都下载好Q之后直接复制给同事安装Q?/p>

Linux 环境配置可以参考这:Installation on Ubuntu?/p>

下文?Mac OS ZQWindows 操作ҎcM?/p>

安装完毕之后打开 KitematicQ注册一?Docker Hub 账号Q方便之后的操作?/p>

注册 Docker Hub 账号

2. 下蝲q运?Ubuntu 镜像

Docker Hub 上有现成?Ubuntu 镜像Q在 Kitematic 中点d上角的“NEW”,搜烦 UbuntuQ选择W二排第一个即可?/p>

Ubuntu 镜像

q个 Ubuntu 镜像是超U精版,只有一癑֤兆,不过国内|络下蝲hq是很痛苦。没办法Q等着吧,反正只需要下载一ơ?/p>

下蝲完成后,?Kitematic 左侧?Container 列表中选择 ubuntuQ然后点M方的“START”按钮执行。点几ZEXEC”可以进入系l命令行Q输?su 开?root 权限。这个过E下文不再赘qͼl称“打开 Ubuntu 命o行”?/p>

打开 Ubuntu 命o行后Q试着执行几个命o看看效果Q比?lsQ?code>cd /。玩完之后,点击 Kitematic 右上角的“Settings”,点击“Ports”,你会看到一?IP 地址Q通常情况下是 192.168.99.100。打开宿主机(你自q电脑Q命令行Q输?ping 192.168.99.100Q应该是通的?/p>

ping

q样我们准备好?Ubuntu 镜像Q可以开始配|了?/p>

官方换源教程Q也可以直接打开 Ubuntu 命o行(如果你忘了怎么做,看上一节)Q执行下面的命oQ?/p>
1
sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
apt-get update

换源完毕Q之?apt-get 都会从中U大源下载Y件?/p>

前面说过Q这?Ubuntu Image 是超U精版,很多不重要的工具都被删掉了,包括常用?vim、curl、ipconfig、ping。除此之外,Linux 最常用?TAB 补全路径也没有,所以下面先安装必要的编辑器和\径补全:

1
apt-get install vim bash-completion

q样完成了基础配置QUbuntu 可以正常用了?/p>

1
apt-get install npm

然后安装 cnpmQ之后所?npm 操作都改?cnpmQ从淘宝源下载,速度会快很多?/p>

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

接着安装 nQTJ 大神?NodeJS 版本理工具Q可以安装多个版本,一键切换。n 需要用?curlQ所以先安装 curlQ?/p>

1
apt-get install curl

然后安装 nQ?/p>

1
cnpm install -g n

最后?n 安装目前的稳定版 NodeJSQ?/p>

1
n stable

q样准备好了前端开发需要的基本工具?/p>

我们的项目目前在使用 VueQ所以我q安装了 vue-cli、browserify、gulp、babel 以及相关的库Q你可以Ҏ你的目需求安装对应的库?/p>

5. 安装和配|?Samba

Samba 是文件共享工P用于在宿L中编?Docker 内部的文件?/p>

q里?a target="_blank" rel="external">完整配置教程Q下面是我整理的简z版?/p>

首先安装 SambaQ?/p>

1
apt-get install samba

Samba 的用Ll比较特别,单来_Samba 的用L实是pȝ的用P但是 Samba 的密码和pȝ的密码不一栗也是_同一个用户在pȝ?Samba 中密码需要单独设|,q没有打通?/p>

Docker ?Ubuntu Image 用户?rootQ我们给 root 讄 Samba 密码Q?/p>

1
smbpasswd -a root

讄好密码之后,需要创?Samba 的配|文Ӟ讄׃n文g夹和权限Q?/p>

1
vim /etc/samba/smb.conf

下面是我的配|示例:

1
[web]
path = /web
available = yes
valid users = root
read only = no
browsable = yes
public = yes
writable = yes

q里面的重点?pathQ指定需要共享的文g夹,q里我共享了 /web 目录Q你可以选择一个不同的目录。我?/web 目录是一?VolumeQ用来存放代码,重启 Docker 也不会丢失数据。Volume 的配|方法在后文介绍?/p>

写好配置之后重启 Samba 服务Q?/p>

1
service smbd restart
service nmbd restart

q样完成了 Samba 的配|?/p>

不过现在你还不能从宿Lq接׃n文g夹,因ؓ我们q没有配|端口映?/p>

6. 配置端口映射

首先明确需要映的端口?/p>

Samba 需要用到的端口Q?37?38?39?45?/p>

日常开发可能用到的端口Q?000?123Qhot-reload 用)?000?080?/p>

接着配置端口映射?/p>

注意QWindows ?Kitematic 有严?bugQ改?Settings 下的M选项都会D所有配|项丢失Q解x法看下一?/p>

如果你是 Mac pȝQ可以直接在 Kitematic 中进行配|?/p>

配置端口映射

如图所C,直接?Settings -> Ports 中添加映即可?/p>

到这里就已经完成?Docker Image 的配|,你可以做一些测试,看看׃n文g夹和端口映射工作是否正常?/p>

试一Q?/p>

  1. 打开 Ubuntu 命o行,随便 cd C个目录(比如 cd /webQ?/li>
  2. 执行 python -m SimpleHTTPServerQ启动一个静态服务器
  3. 在宿L中访?http://192.168.99.100:8000Q应该能看到 /web 目录下的所有文?/li>

试二:

  1. 如果?Mac pȝQ打开 FinderQ按??KQ输?smb://192.168.99.100Q回车,输入 root ?Samba 密码Q应该能看到׃n文g夹(我设|的?/webQ?pre>![q接服务器](http://static.zybuluo.com/numbbbbb/xif6i8s3gwwg0rd6si1wb79b/%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E5%99%A8.png) ![选择׃n文g夹](http://static.zybuluo.com/numbbbbb/m7nc3vbmxgycxtxrkj67prti/%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6%E5%A4%B9.png)
  2. 双击׃n文g夹,应该能在 Finder 中看?/web 下的所有文?/li>

q样完成了 Docker Image 的所有配|,下面完成最后一件事Q导出镜像,供其他h使用?/p>

7. 导出镜像

别忘了前面的提醒Q如果不 commitQ重启之后所有改动都会丢失!

所以先 commit。点?Kitematic 左下?“DOCKER CLI”,执行Q?/p>

1
docker ps

会看C面这L输出Q?/p>

1
➜  ~ docker ps
CONTAINER ID        IMAGE                  COMMAND             CREATED             STATUS              PORTS                                                                                                                                                  NAMES
c5c131f108b1        numbbbbb/ubuntu-test   "/bin/bash"         15 hours ago        Up 50 seconds       0.0.0.0:137-139->137-139/tcp, 0.0.0.0:445->445/tcp, 0.0.0.0:3123->3123/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:32773->49201/tcp   dev

复制 Container IDQ我q里?c5c131f108b1Q然后执行:

1
docker commit c5c131f108b1 username/imagename

username 换成你的 Docker Hub 用户名,imagename 换成你的镜像名称。我q里是 numbbbbb/ubuntu-test?/p>

commit 之后可以把当前 Container 导出 Image 了:

1
docker export c5c131f108b1 -o ubuntu

执行完后Q在你的个h目录下(Mac 上是 /Users/你的用户名)可以扑ֈ ubuntu 文gQ这是我们的最l目标:一个完成所有配|的 Image?/p>

E微村֏气,下面看看新同事入职时如何使用q个 Image?/p>

Ch使用程

我整理的Ch入职配置程Q?/p>

  1. 准备?Docker Toolbox 安装包和 Ubuntu Image
  2. 安装 Docker Toolbox
  3. 打开 KitematicQ注册一?Docker Hub 账号q登?/li>
  4. ?Kitematic 中点d下角“DOCKER CLI”打开 Docker 命o?/li>
  5. 输入命odocker importQ从文g夹中直接?ubuntu 文g拖拽到命令行中(注意 ubuntu 文g路径中不能有中文Q如果有Q先把文件移动到另一个纯英文路径的文件夹中)
  6. 输入命odocker imagesQ复制出镜像?IMAGE IDQ类?code>54184b993d46Q?/li>
  7. 输入命o

    docker run -t -i --privileged -p 137-139:137-139/tcp \
        -p 445:445/tcp -p 3000:3000/tcp -p 3123:3123/tcp \
        -p 8000:8000/tcp -p 8080:8080/tcp -d --name dev -v /web IMAGEID \
        /bin/bash
    

    把其中的 IMAGEID 替换Z一步复制的内容

  8. 回到 KitematicQ应该可以看到左侧多了一个容器,此时环境已经搭徏完毕

2016.08.04 Windows ?Kitematic ?bugQ如果在界面中修改设|会D volume 丢失Q所以不要在 Kitematic 中修改Q何设|,如果要改׃命o行执?/p>

上一节提到过QWindows ?Kitematic ?bugQ手动添加端口映会丢失所有配|,所以我们直接用命odQ只要不?Kitematic 里修攚w|就没问题?/p>

W?7 步的命oq有一个重要内容,是 -v /web。这会创建ƈ挂蝲一?VolumeQ挂载目录是 /webQ把代码攑ֈq个目录下,׃会因为重?Docker 丢失数据?/p>

没有银弹

说了很多优点Q下面来聊聊?Docker 做开发环境的~点?/p>

首先QDocker 本nq不够成熟?/p>

Docker 实很强大,能支持三大操作系l,性能斚w也远传l虚拟机Q但是仍然不够成熟。D一个小例子QKitematic ?Windows 上丢失配|的 bug dq底有人报q,到现在都没解冟?/p>

其次QDocker q套体系使用成本q不低?/p>

试想一下,作ؓ一个开发h员,在写代码之前必须q行 Kitematic、启?Ubuntu 镜像、连接共享文件夹、进入镜像启动静态服务器。这个流E太重,理想的开发环境应该是透明的,打开电脑p写代码。或怸一步可以考虑在这斚w做一些自动化脚本来辅助开发?/p>

?Docker 做前端开发环境确实可??我们团队已经投入使用 ?但是q套Ҏq远q谈不上完美Q需要l优化?/p>

如果你还是不知道怎么选:

  • 有h有钱有时_上标准开发机Q各大公叔Rq么搞,肯定没问?/li>
  • 否则Q可以试?DockerQ目前没有发现致命问题?/li>

One more thing

插播一则招聘信息?/p>

智美q动U技有限公司Q坐标深圻I初创但是不差钱?/p>

没猫没狗没下午茶没饮料没高大上办公室没弹性工作制Q老板说有Ҏ工作制Q,有什么呢Q有靠谱老板Q有靠谱同事Q有钱。相信我Q猫狗零食弹性工作不能帮你融资,也不能帮你买ѝ?/p>

我们q在招前端,你不需要是大牛Q只要脑子灵zL潜力能带hp。技术不会可以学Q经验不_以练Q主要看潜力?/p>

如果你相信我的选择Q可以来和我聊聊。我的邮:ljie@wisdomtmt.com?/p>

我的博客Q最q才开始重建,内容不多Q不q绝Ҏ?/li>
  • GitHubQ或怽点开׃发现“哦原来是你Q?/li> ]]> Docker

  • 讀書共和國Q不用翻墙,体验很好Q但是书U类没有博客來多
  • 在讀書共和國C很简单,先挑好要买的书,然后l客服发邮g说你在大陆,要买q些书,他会问你具体的邮寄方式,然后帮你生成订单Q用信用卡付Ƒְ行了。下面主要说下博客來的购买方法?/p>

    博客?></p>
<p>图ؓ博客來首c?/p>
<p>q个|站主要有三个坑Q?/p>
<ol>
<li>订购人的联系方式只能填港澛_座机/Ud电话Q我找了一个台湾朋友帮忙,理论上来说随便填一个也行,但是不推荐这样做Q万一出问题需要联pM很麻烦。收件h填你自己信息p</li>
<li>收g人的信息全部用繁体中文填Q简体中文似乎存不进数据库,我试了几ơ,全部被截断了Q换了繁体就好了</li>
<li>W一ơ付ƾ之后,需要验证银行卡Q你需要访?a  target=客服中心Q填写订单号q上传你的银行卡正面照片。这里的坑是Q无论怎么?VPN 都会提交p|Q哪怕我什么都不写只写一个字都会p|Q最后没办法Q找台湾朋友帮忙上传才搞定。个人推是后台做了极其严格的限?/li>

    其他程没啥说的Q加购物车、下单、填信息、付ƾ,然后{着书寄q来p?/p>

    至于关Q这是一个很奇的存在,我买了这么多ơ书都没被vxq,但是微博上的几个朋友反映说v关会扣书Q有时候交钱就行,有时候直接按非法韛_制品没收……看h是一个随ZӞ看运气了?/p>

    杂谈

    亚快递很慢(如果你和我一样选择的是比较慢但是比较便宜的那种Q,半个月一个月是常事,别着急?/p>

    英文原版和台版印L的很,拿到q么_的书多花׃值得?/p>

    多读书没坏处Q书应该是性h比最高的东西之一?/p>

    有条件的话多学几门外语,从书的角度来说多学一门外语就可以打开C界的大门Q我最q就在学日语?/p>

    最后,Ƣ迎各种评论Q希望通过大家的反馈不断完善内容,更好地帮助其他读者?/p>

    我的博客Q最q才开始重建,内容不多Q不q绝Ҏ?/li>
  • GitHubQ或怽点开׃发现“哦原来是你Q?/li> ]]> 我工位上的英文原版书和台版书

    图ؓ我工位上的英文原版书和台版书?/p>

    我是一个读书狂人,也是一个买书狂人。在C的过E中学到了一些新知识Q也t了一些坑Q在此做一个ȝQ给其他喜欢书的Z参考?/p>]]>

    <![CDATA[我如何用二十天刷?SICP]]> http://yoursite.com/2016/03/28/20160328_我如何用两周旉刷完 SICP/ 2016-03-28T02:37:48.217Z 2016-03-28T02:37:48.217Z SICP

    背景

    SICP 全称 Structure and Interpretation of Computer ProgramsQ翻译过来叫《计机E序的构造和解释》。我看的是英文版Q所以下面都?SICP ~写Q后面解释ؓ什么要看英文版Q?/p>

    最初看 SICP 我是拒绝的,因ؓq书太厚Q而且感觉没啥用。带着q种xQ看了八十多就攑ּ了?/p>

    那ؓ什么这ơ又开始看 SICP 了呢Q很单,无聊了……我发现无聊的时候真的很适合看这U深奥的东西Q虐一虐自q大脑?/p>

    好的Q那么在一个无聊的周五Q我打开?SICPQ就q样学v来了?/p>

    我的所有习题解{全部放?GitHub 上,仅供参考,仅供参考,仅供参考?/p>

    W一道题

    p样学啊学……学啊学…?/p>

    Q我写了的)最后一道题

    今天下午Q终于看完了全书Q因此写文章,说说我是怎么L。对我来说算是个U念+ȝQ如果对大家也有帮助那就更好了?/p>

    看完全书

    SICP 好处都有啥?

    一千个人心中有一千个 SICP

    |上能搜到太多太多答案,不过q里我要写的Q是我自׃自看完学完之后的体会?/p>

    两个字ȝ SICPQ?strong>内功?/p>

    看过说的都知道Q什么刀法剑法往往都不重要Q重要的是内功,是修炼方法。在~程界,SICP 毫无疑问是一本顶U内功?/p>

    q本书教你的q不是“函数命名要有意义”、“不要编写超q一屏的函数”、“如何安装和配置 Xcode”、“如何编写年Mh的第一?Hello World”,学完q本书后Q还是原来的 PMQ还是原来的需求,q是原来不换行的大括Pq些都不会变?/p>

    变的是你的思维方式?/p>

    SICP 要教你的不是那些l枝末节的东西,而是把你拉到一个极高的视角Q一边分解程序,一Ҏ你如?strong>正确的构建和~写E序。具体来_SCIP 教你如何熟练q用抽象以及E序如何q行?/p>

    有些同学看到q里可能要说了,抽象不就是封装函数吗Q不是隐藏实现吗?E序不就是解释或者编译运行吗Q?/p>

    其实q样说也没错Q但是要真正理解和掌握这些东襉K要大量的训练?strong>知道?strong>掌握是两个截然不同的概念Q在q个时代我们知道的太多,掌握的太?/p>

    说完了好处,也要聊聊坏处?/p>

    SICP 的最大缺点就?strong>长得太丑?/p>

    什么叫长得丑?打开书随便一d是各U数学公式、加法器、数理逻辑Q还没看吓跑一批h?/p>

    不过q其实是U老虎Qؓ什么呢Q咱们下一节l说?/p>

    SICP 怎么学?

    作ؓ长者,我有必要告诉你们一点学习的l验

    首先Q不要慌

    很多Z?SICP 的各U公式吓跑,但是在我学习的过E中发现Q这些东襉K是纸老虎Q?/p>

    一个非常简单的道理Q?strong>作者的目的是教你一些知识,而不是ؓ了难住你。这是“SICP W一定律”,在学习过E中一定要牢记q句话?/p>

    据我自己l计QSICP 里面涉及到的知识有:

    • 向量
    • 矩阵
    • 各种数学公式Q求qx栏V立Ҏ、导数、不动点、微U分……)
    • 数字电\
    • 数理逻辑
    • 机器语言
    • q发
    • 解释?/li>
    • ~译?/li>

    在学习的q程中,l常是上一还在实现微U分Q下一就开始讲电\Q上一还在解数理逻辑Q下一就开始写~译器,内容跨度之大令h发指?/p>

    但是大家不要慌,先默念十遍第一定律Q然后往下看?/p>

    q些东西其实都是l你举例子,真正的目的是教你~程思想。只不过呢,SICP ?MIT 的教材,MIT 里众云集,l他们写的教材自然也不能太简单?/p>

    普通的教材举例子会_

    1
    小明有三个苹果,小张有四个苹果,俩人一共几个苹果?

    SICP 会说Q?/p>

    1
    x = 3, y = 4, x + y = ?

    说白了,无论是电路还是公式,你就当它们是明红Q照着要求d现就行?/p>

    然后Q不要停

    先来个错误示范:

    明想看 SICPQ下载电子书Q发C?883 c小明想两个月看完,打开计算器做一个简单的除法再取个整Q每天看 15 c小明一惻I15 这不是L搞定嘛!哪怕一늜五分钟,也就一个多时Q更何况一不可能看五分钟?/p>

    于是明开心的ȝ了?/p>

    两周后,明攑ּQ游戏结束?/p>

    问题出在哪里Q?/strong>

    在学 SICP 的过E中Q我收获了一个重要的l验Q那是Q?strong>一鼓作?/strong>?/p>

    看v来完的计划Z么Lp|Q不是你计划得不好,不是你除法用得不溜,而是因ؓ战线拖的太长?/p>

    生活中有太多无法预料的事情,公司加班、感冒发烧、朋友聚、外包、技术大会、租ѝ蟩槽……你的计划只考虑了理x况,但凡有点物理知识的同学就知道Q真实世界中不存在理x况,R的空气阻力不可能为零?/p>

    战线长的W二个问题就是低效。每?15 ,看似分摊了Q务,无Ş之中增加了很多上下文切换和环境初始化的开销。每天你都需要先回忆之前的内容,然后l箋看。如果题目用C之前的知识(q在 SICP 中很常见Q,你不得不q回ȝl阅诅R这反过来又增加了失败的概率?/p>

    因此Q不要再费旉做无用的计划Q从现在开始,一鼓作气,用尽一切时间去学!

    我可以说说我是怎么学的?/p>

    每天早晨到公司吃完早Ҏ九点Q我会从九点一直学C午六点半下班。吃饭和公司需求会占用一D|_不过通常来说白天在公司我会用七个时学习QM可能一q到头加班吧Q难道你不用{设计师出图Q不用等产品扯皮Q)。晚上回家之后我q会在睡觉前学习一个小Ӟq样下来我一天会学习臛_八个时?/p>

    q种状态我持箋了两周?/p>

    也就是说Q这两周旉从早晨睁眼到晚上睡觉Q绝大部分时间我都在看书和做题,?SICP 占用所有缓存?/p>

    Z么能坚持下来Q很单,坚持不下来的时候,再努力一下就好了。中间有几次我也觉得很烦w,不过睡一觉v来,q是坐在电脑前面l箋看书做题。我qh脾气不好Q说了要看完Q就是要看完Q就是和自己较劲?/p>

    ȝ下来Q我?SICP 学习l验是Q首先理解作者思\Q把一切看做纸老虎Q然后坚持到底?/strong>

    如何开始?

    开发一个项目,臛_?50% 旉在配|环?/p>

    如果你看Cq里Qƈ且决定开始学?SICPQ下面是一个简单的 setup 步骤Q?/p>

    1. 下蝲 英文?SICP Qؓ什么是英文版,看下一?FAQQ,qƈ不是盗版Q是 Lytha Ayth Z官方公开?HTML 制作?PDF ?/li>
    2. 参?q个回答 安装 MIT-Scheme。Scheme ?Lisp 的一U方aQ也?SICP 使用的语a。MIT-Scheme ?MIT 实现?Scheme 解释器,?MIT 教材 SICP 更配?/li>
    3. 打开一个你最喜欢的编辑器Q我用的 Sublime Text 3Q,~写一D?Scheme 代码q保存成 testQ可以没有后~?/li>
    4. 打开命o行,输入 scheme < testQ即可执行程?/li>

    现在你已l准备好了一切,JUST READ THAT FUCKING BOOK!

    FAQ

    当我沉默著的时候,我觉得充实;我将开口,同时感到I

    有些题我不会怎么办?

    单,跌它?/p>

    学习的目的不是做Ҏ有题Q而是学到你本来不会的知识。SICP 里面有不难度很大的题,有些我自׃没有做出来,所以不要太在意题?/p>

    当然Q首先你要尽力去做,然后在万不得已的情况下蟩q?/p>

    你的{案正确吗?

    仅供参考?/p>

    我做了大?90% 的题Q有些实在太难或者太复杂没有做。不q?SICP 到后面就开始意识流了,很多E序也都只是Z理解思想Q所以真的仅供参考?/p>

    能运行的E序一般都是对的,有些题只是要求补充片D,没法独立q行Q我也就没法验证了?/p>

    @梁杰_numbbbbbQ也可以l我发邮Ӟlj925184928@gmail.com?/p>

    我的博客Q最q才开始重建,内容不多Q不q绝Ҏ?/li>
  • GitHubQ或怽点开׃发现“哦原来是你Q?/li> ]]> SICP

    背景

    SICP 全称 Structure and Interpretation of Computer ProgramsQ翻译过来叫《计机E序的构造和解释》。我看的是英文版Q所以下面都?SICP ~写Q后面解释ؓ什么要看英文版Q?/p>

    最初看 SICP 我是拒绝的,因ؓq书太厚Q而且感觉没啥用。带着q种xQ看了八十多就攑ּ了?/p>

    那ؓ什么这ơ又开始看 SICP 了呢Q很单,无聊了……我发现无聊的时候真的很适合看这U深奥的东西Q虐一虐自q大脑?/p>]]>

    <![CDATA[C Steam 所有游戏要花多钱Q]]> http://yoursite.com/2016/02/15/20160215_如何计算 Steam 游戏MhQ? 2016-02-15T10:30:13.740Z 2016-02-15T10:30:13.740Z 先来看效果展C:C Steam 所有游戏要花多钱Q?/a>?/p>

    背景

    最q?Steam 玩得比较多,早晨H然惛_一个有的问题Q买?Steam 所有游戏要花多钱Q?/p>

    ?Google 了一下,发现国外有个|站做了计算Q但?2014 q底停止更C。研I了一下代码和 Steam APIQ自己做了一个网站来玩?/p>

    虽然没什么技术含量,但是很好的展CZ如何把一个点子变成现?/strong>Q所以记录下来?/p>

    技能和工具

    q个|站非常单,涉及到的技术只要初步掌握即可实现?/p>

    以下是我用到的技能和工具Q你可以Ҏ自己情况调整

    技能:

    • Python
    • Node.js
    • 基本?HTML、CSS ?JS
    • 基本?Linux 技?/li>
    • 基本?Nginx 技?/li>
    • d能力
    • 会用 GitHub

    工具Q?/p>

    • 一?VPS
    • 一个域?/li>
    • 一个编辑器Q我用的 Sublime Text 3Q?/li>

    调查

    首先?Google 一下“How much to buy all steam games”,搜到q个|站Q?a target="_blank" rel="external">Buy All of SteamQ截囑֦?/p>

    |站截图

    哇,九万多美元!真不?/p>

    再往下看Q最后一ơ更新时间是 2014 q光节?/p>

    ARE YOU KIDDING ME?

    是不是作者在光棍节脱单了所以放弃了 SteamQ?/p>

    l箋往下看Q网站还l出了计方法,非常单:

    1
    2
    3
    4
    5
    6
    7
    8
    from steamapiwrapper.SteamGames import Games
    games = Games()
    full_price = 0.0
    discounted_price = 0.0
    for game in games.get_all('US'):
    if game.price != 0:
    discounted_price += game.discounted_price
    full_price += game.full_price

    哇真的好单!

    然后我去看了一下这?code>steamapiwrapper库,

    steamapiwrapper

    2 years ago

    2 years ago

    2 years ago

    ?/p>

    ?/p>

    ?/p>

    ?/p>

    ?/p>

    ?/p>

    ?/p>

    掀?></p>
<p>q就是网站作者自己写的库吧!一定是脱团之后弃坑了吧Q!Q?/p>
<p>好吧Q关掉网,回到 Google l箋往下看?/p>
<p>嗯……没了?/p>
<p>其他的网都是一些统计性质的文章,Steam 更新频率极高Q这cL章基本上是一发表p时?/p>
<p>怎么办?</p>
<p>作ؓ无所不能的程序员Q当然是自己写一个啦Q既然两q前能实玎ͼ两年后一定也能搞定!</p>
<p><img src=

    看看我们攉C什么有用的东西Q?/p>

    • 一D计代?/li>
    • 一?Steam API ?/li>

    那就从这里开始吧?/p>

    修改代码

    以下代码不包?/strong>M最佛_践,Just For FunQ?/p>

    首先来看看这D两q前的代码还能否q行Q如果能Q那我们只要写个|页展示可以了?/p>

    steamapiwrapper没有上传?pipQ所以我们只能下载代码到本地?/p>

    首先登陆 VPS:

    1
    ssh root@xxx.xxx.xx.x

    提示Q本文的命o和代码是意识,重在介绍思想和流E,具体的细节请自行 GoogleQ别癑ֺQ百度一下你p坑)?/p>

    然后?code>virtualenv创徏 Python 虚拟环境Q不影响本机?Python 配置Q?/p>

    1
    2
    3
    4
    5
    $ mkdir /steamtuhao
    $ cd /steamtuhao
    $ pip install virtualenv
    $ virtualenv venv
    $ virtualenv -p /usr/bin/python2.7 venv

    执行完会在根目录下的steamtuhao目录中创Z?Python 虚拟环境Qƈ且指?Python 版本?2.7Q?code>steamapiwrapperZ Python 2.x 开发)?/p>

    然后开启虚拟环境,下蝲W三方库Q?/p>

    1
    2
    3
    4
    5
    $ source venv/bin/activate
    $ git clone git@github.com:naiyt/steamapiwrapper.git
    $ cp -avr steamapiwrapper/steamapiwrapper ./temp
    $ rm -rf steamapiwrapper
    $ mv temp steamapiwrapper

    最后三行是不是看懵了?GitHub 克隆下来的库q不能直接导?Python 中,需要把里面真正?Python 包复制出来。所以这里的操作其实是:复制出来我们要用的包、删掉整个项目、重命名包?/p>

    最后新Z个文Ӟ把网站中提到的那D代码复制进去:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 需要复制的代码
    from steamapiwrapper.SteamGames import Games
    games = Games()
    full_price = 0.0
    discounted_price = 0.0
    for game in games.get_all('US'):
    if game.price != 0:
    discounted_price += game.discounted_price
    full_price += game.full_price
    1
    2
    3
    $ vim calTotalPrices.py
    # q入 vim
    # _脓上面的代码ƈ保存

    OKQ运行一下试试:

    1
    $ python calTotalPrices.py

    报错了?/p>

    具体的错误信息我忘了保存Q大概就是说 JSON 不能解析None。打开出错?code>SteamGames.py定位q去看下Q发现调用了一?code>_open_url函数Q搜索一下这个函数看看………?/p>

    没找到?/del>

    q哥们绝Ҏ恋爱了,否则不可能犯q么弱智的错误?/del>

    l过@Ralph-Wang 提醒Q发?code>_open_url是承自SteamBase.py中的SteamAPIcR那应该和下面提到的问题一P因ؓ URL 里面~码了参敎ͼDhq回 null?/p>

    好吧Q看上下文,q里应该是请求一?URL q解析返回的 JSON 内容?/p>

    那我们直接用requestsq个库就行?/p>

    1
    $ pip install requests

    然后修改SteamGames.py文gQ?/p>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 文g头部 import q来
    import requests

    ...

    # 把两?_open_url 都改q来
    def _get_games_from(self, url):
    """Generator to create the actual game objects"""
    page = requests.get(url).json() # ←第一?/span>

    ...

    def get_ids_and_names(self):
    """
    Returns two dicts: one mapping appid->game name, and one game name->appid
    TODO: Refactor the code so we don't need to seperate dicts

    """

    url = "http://api.steampowered.com/ISteamApps/GetAppList/v2"
    url_info = requests.get(url).json() # ←第二处

    OKQ现在再来跑一下看看:

    1
    $ python calTotalPrices.py

    又报错了?/p>

    具体的错误信息我没保存(Z么这句话q么眼熟Q,反正大概意思就?JSON 不能解析None。什么?刚才不就是这个错误吗Q!

    仔细看了一下,错误位置和上ơ一P到底是怎么回事Q?/p>

    回答q个问题之前先来了解下请?URL 时到底发生了什么:

    • 讉K URL
    • 服务器返?JSON 数据
    • 拿到q回的数据ƈ解析

    我们刚才解决的是W一步,讉K URL。现在又出错了,那就说明q回?JSON 数据有问题?/p>

    可以在代码里加一?code>print page看下Q果然是NoneQ也是说根本就没拿到数据?/p>

    怎么回事呢?我们?code>print url一下,我看到的是这个:

    1
    http://store.steampowered.com/api/appdetails/?cc=US&appids=5%2C262150%2C7%2C8%2C10%2C20%2C393240%2C30%2C40%2C262190%2C50%2C393270%2C60%2C262210%2C70%2C393290%2C80%2C262230%2C90%2C92%2C262240%2C100%2C393320%2C393330%2C262260&l=english&v=1

    q?code>appids肯定有问题啊Q?/p>

    print all_idsQ从里面拿出来一?idQ手动拼接到上面?URL 中:

    1
    http://store.steampowered.com/api/appdetails/?appids=218620&cc=US&l=english&v=1

    讉Kl果

    拿到了数据,看来是 URL 拼接时候出问题了?/p>

    看下拼接函数Q?/p>

    1
    2
    3
    4
    5
    def _create_url(self, appids, cc):
    """Given a list of appids, creates an API url to retrieve them"""
    appids = ','.join([str(x) for x in appids])
    data = {'appids': appids, 'cc': cc, 'l': 'english', 'v': '1'}
    return "http://store.steampowered.com/api/appdetails/?{}".format(urllib.urlencode(data))

    Z么要urlencode呢?删掉Q直接手动拼接:

    1
    2
    3
    4
    5
    def _create_url(self, appids, cc):
    """Given a list of appids, creates an API url to retrieve them"""
    appids = ','.join([str(x) for x in appids])
    data = (appids, cc, 'english')
    return "http://store.steampowered.com/api/appdetails/?appids=%s&cc=%s&l=%s&v=1" % data

    再执行一下,q是报错?/p>

    好吧Q就是这LQ现在你知道两年前的目是什么概念了?/p>

    刚才我们在浏览器里不是拿到数据了吗?怎么又出问题了?

    仔细看下拼接?URLQ发现有个区别:拼接?URL 里有多个appidQ我们刚才只试了一个?/p>

    修改试 URLQ?/p>

    1
    http://store.steampowered.com/api/appdetails/?appids=218620,441600&cc=US&l=english&v=1

    试

    果然Q返?null?/p>

    到底是怎么回事Q?/p>

    再次阅读steamapiwrapper的文,发现作者提C一文章,说他用文章里的方法重构了 APIQ我们去看看那篇文章?/p>

    打开一看,说的是我们q个 API 啊!往下翻Q看到好多两q前的评论,再往下翻Q最底部的一条评论是五个月前的,看看说了什么:

    评论

    热泪盈眶Q兄弟你是个好h啊!Q不仅发Cq个问题Q还l出了解x法!

    ?code>&filters=price_overview加到 URL l尾看看Q?/p>

    1
    http://store.steampowered.com/api/appdetails/?appids=218620,441600&cc=US&l=english&v=1&filters=price_overview

    试

    热泪盈眶 againQ数据出来了Q而且正是我们惌的h格数据!

    q里做个W记Q返回的数据?code>currency表示货币U类Q?code>initial表示原hQ?code>final表示折扣仗哎q游戏怎么q么贵?1999 元Q打开 Steam 搜了一下,?19.99 元Q明白了Q这个数字要除以 100 才是实际h?/p>

    U普Qؓ什?Steam 要乘?100Q?/p>

    在很多语a?0.1 + 0.1 都不{于 0.2Q这是因机本n的设计缺P无法准确保存点敎ͼ也就是小敎ͼQ因此对点数做q算会有误差。最单的解决办法是把QҎ变成整数q行q算Q最l需要展C时再除回小数?/p>

    如果你想了解更多点数内容,可以阅读g上的{案?/p>

    下面l箋修改代码Q?/p>

    1
    2
    3
    4
    5
    def _create_url(self, appids, cc):
    """Given a list of appids, creates an API url to retrieve them"""
    appids = ','.join([str(x) for x in appids])
    data = (appids, cc, 'english')
    return "http://store.steampowered.com/api/appdetails/?appids=%s&cc=%s&l=%s&v=1&filters=price_overview" % data

    再次q行Q又报错了,错误提示不一样了Q可喜可贺?/p>

    具体的错误提C我忘了Q……)Q反正大概是?code>Gamecd始化时候有问题?/p>

    看一下出错位|的代码Q?/p>

    1
    2
    3
    4
    for appid in page:
    game = Game(page[appid], appid)
    if game.success:
    yield game

    q里?code>page是一个解析后?JSON 内容Q也是说它是一个字典。用for循环去遍历的时候,拿到?code>appid是字典的键,传入Gamecȝ成实例的时候出错了。蟩q去看了一?code>Gamecȝ实现代码Q好ȝQ懒得改了,反正已经拿到h数据Q直接返回得了?/p>

    1
    2
    3
    4
    5
    6
    def _get_games_from(self, url):
    """Generator to create the actual game objects"""
    page = requests.get(url).json()
    for game in page:
    if page[game]['success'] and page[game]['data']:
    yield page[game]['data']['price_overview']

    再重复一遍,page 是字典,所以要用方括号去获取内宏V?/p>

    试的时候发现有时候请求成功但?code>data是空Q所?code>if中加了一个判断条件?/p>

    ׃q回的内Ҏ变,我们q需要修?code>calTotalPrices.py里面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from steamapiwrapper.SteamGames import Games
    games = Games()
    full_price = 0.0
    discounted_price = 0.0
    for game in games.get_all('US'):
    if game['initial'] != 0:
    discounted_price += game['final']
    full_price += game['initial']
    print full_price, discounted_price

    再次q行E序Q这ơ没有报错,q且一直在输出hQ大功告成!

    q一节写了好长,l于能结束了?/p>

    验证

    代码跑通了Q下面就是要查数据是否正?/p>

    执行Q?/p>

    1
    $ python calTotalPrices.py

    一开始没问题Q过了一会又报错了?/p>

    ARE YOU KIDDING ME?

    不是没问题了吗?

    q时候,l验丰富的同学应该已l想C一U可能性:API 调用频率限制?/p>

    没错QSteam 不是慈善ӞAPI 资源不可能给你无限用。经q一番研IӞ发现实是触发了 API 的限制。一旦访问频率过快,Steam 会直接返?null?/p>

    那么 Steam 的限制到底是多少Q?/p>

    Google 一番之后,发现 Steam 官方没有M说明。聪明的|友们自己ȝ出几条规则:

    • 10 U内最多调?10 ?/li>
    • 5 分钟内最多调?200 ?/li>
    • x 分钟内…?/li>

    好了好了我明白了QM一U调用一ơ肯定没问题是吧Q简单,加个sleep(1)Q?/p>

    1
    2
    3
    4
    5
    6
    7
    8
    import time

    ...

    for url in urls:
    for game in self._get_games_from(url):
    yield game
    time.sleep(1)

    加完之后Q经验丰富的同学应该又想C另一个问题:要抓多久Q?/p>

    print len(all_ids)Q大概有 23000 ?idQ代码中self.num = 25Q每ơ请求查?25 个,需要查?23000/25 = 1000 ơ。每ơ请求睡眠一U,那就?1000 多秒Q大?17 分钟。再加上h本n需要的旉Q可能要几十分钟吧?/p>

    看v来也可以接受Q不q还能优化吗Q?/p>

    仔细看代码中的注释:

    1
    2
    3
    4
    5
    6
    7
    def __init__(self,num=None):
    """
    args:
    num -- number of games to query per call. The default 150 should work in most cases.

    """

    self.num = 25 if num is None else num

    原来默认值是 150 啊,那我们就Ҏself.num = 150Q一下快?6 倍,好开心?/p>

    下面来正式q行一下,看看能否拿到数据Q?/p>

    1
    $ nohup python calTotalPrices.py > result &

    咦,怎么出来一?code>nohupQ这是一个新命oQ简单来说就是后台执行。这条命令把输出写到result文g中,l尾?code>&会让q程在后台持l运行,哪?ssh 断掉q程也不会中止?/p>

    然后{就可以了,什么时候程序执行完了,什么时候拿到结果?/p>

    {几分钟p完了Q看看MhQ?/p>

    1
    15031825 14903412

    哇,真不啊Q十五万元Q?/p>

    现在已经解决了我的问题,出了Mh。不q我q想做得更多Q能不能让其他h也看到这个数据呢Q?/p>

    当然能,做个|站可以了?/p>

    展示

    现在已经拿到数据了,接下来要做的是展C数据?/p>

    我们从用L角度来思考,他们如何查看数据Q?/p>

    • 讉K一?URLQ因此需?strong>注册一个域?/strong>
    • h会发送到后端服务器,因此需?strong>准备一?VPS
    • VPS 需要处理请求,因此需?strong>配置 Nginx
    • Nginx 拿到h之后要反向代理给具体的处理者,因此需?strong>~写一?Node.js E序
    • Node.js E序需要返回一个页面,因此需?strong>~写一?HTML 面

    OKQ就是这些,涉及到很多东西,但是都不难。具体实施的时候顺序稍有不同,我们一步一步说?/p>

    GoDaddyQ?a target="_blank" rel="external">Name?/p>

    买好域名之后Q把域名解析到自q VPS IP 地址可以了?/p>

    准备一?VPS

    VPS 是另一个话题,你问我资词哪个?我主要用 Linode 和阿里云。不q要注意Q大陆的L要求域名备案Q不备案的域名不能解析到大陆L。所以如果你域名没备案,M香港或者新加坡的主机,阉K云有QUCloud 也有Q很多家都有。还可以买日本和Ƨ美LQ不q速度比较慢?/p>

    ~写一?HTML 面

    ׃只需要展C数字,所以直接编写一个带占位W的单页面就可以Q?/p>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <meta charset="UTF-8">
    <title>C Steam 所有游戏要花多钱Q?span class="tag"></title>
    <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
    <style type="text/css">
    ... 省略Q可以直接查看我的网站源?/span>
    </style>

    </head>
    <body>
    <div class="main">
    <h2>CSteam所有游戏需?span class="tag"></h2>

    <h1>${dollar} ?K?#123;cny}</h1>
    <h4>共有</h4>
    <h1>{us_number}(区),{cn_number}(中区)个游戏和 DLCQ?span class="tag"></h1>
    <p class="date">更新日期Q?#123;date}</p>
    <p><a href="http://www.boshaotao.cn/2016/02/15/20160215_%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%20Steam%20%E6%B8%B8%E6%88%8F%E6%80%BB%E4%BB%B7%EF%BC%9F/">原理详解</a></p>
    </div>
    <div class="footer">
    <span>
    <a href="http://www.boshaotao.cn">作者@梁杰_numbbbbb</a>
    </span>
    </div>
    </body>
    </html>

    注意到里面有几个奇怪的东西Q那些是占位W,Node.js 中会d Python 执行出来的结果ƈ替换掉,用户看到的网|C的是实际数字?/p>

    你可以根据自q喜好调整面样式?/p>

    ~写一?Node.js E序

    首先配置?Node.js 环境以及 npmQ不会的自行 Google?/p>

    q里用到?code>hapiQ一?Node.js 服务端框Ӟ专门用来处理|络h。还用到?code>pm2Q你可以把它理解成一个监控程序,它会帮你监控q程是否正常q行Qƈ在必要的时候重启进E,q样你的服务׃会轻易狗带。我喜欢 ES6Q所以需要安?code>babel-cli

    1
    2
    $ sudo npm install pm2 babel-cli -g
    $ sudo npm install hapi

    ׃babel-cli?code>pm2都需要执行命令行命oQ所以全局安装?/p>

    下面创徏 Node.js E序Q?/p>

    1
    2
    $ touch index.js
    $ vim index.js

    拯q去下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #!/usr/bin/env babel-node
    import Hapi from 'hapi'
    import fs from 'fs'

    let server = new Hapi.Server()
    server.connection({
    port: 3003,
    routes: {
    cors: {
    origin: ['*']
    }
    }
    })

    function numberWithCommas(x) {
    var parts = x.toString().split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
    }

    server.route({
    method: 'GET',
    path: '/',
    handler: (request, reply) => {
    fs.readFile("finalResult", (err, data) => {
    if (err) throw err
    let rawData = data.toString().split('\n')
    fs.stat("finalResult", (err, data) => {
    let mtime = data.mtime
    fs.readFile("index.html", (err, data) => {
    var result = data.toString()
    result = result.replace("{dollar}", numberWithCommas(parseInt(rawData[1]) / 100))
    result = result.replace("{cny}", numberWithCommas(parseInt(rawData[4]) / 100))
    result = result.replace("{us_number}", numberWithCommas(rawData[2]))
    result = result.replace("{cn_number}", numberWithCommas(rawData[5]))
    result = result.replace("{date}", mtime.toISOString())
    reply(result).code(200)
    })
    })
    })
    }
    })

    server.start((err) => {
    console.log(err)
    console.log('Server running at:', server.info.uri)
    })

    再次重复Q本文的代码不包?/strong>M最佛_践,Just For FunQ?/p>

    q段代码很简单,启动一个服务器监听 3003 端口Q如果有hq来Q就直接d上面?HTML 文gQ用最新的数据替换?HTML 中的占位W,然后q回?/p>

    配置 Nginx

    ?VPS 上安装和配置 Nginx。别问我怎么安装Q问 Google?/p>

    打开配置文gQ?/p>

    1
    $ vim /etc/nginx/nginx.conf

    d一D内容:

    1
    server {
      listen 80;
      server_name steamtuhao.com www.steamtuhao;    # ←写你的域名
    
      location / {
        proxy_pass http://127.0.0.1:3003;    # ←写你的端口
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;      
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
      }
    }

    注意两个地方Q一个是域名Q一个是端口?/p>

    当然Q我们还没说到域名,先往下翻Q看域名那一节,搞定域名再来q里配置?/p>

    写完之后重启 NginxQ?/p>

    1
    $ service nginx restart

    看到输出[OK]pC重启成功,配置没问题。如果不写域名这里会出错?/p>