纸上得来终觉浅,绝知此事要躬行。
这两天看到了掘金的GO征文活动,看着奖品有小册兑换码,我不禁心动了起来,不过转念一想,自己根本没接触过GO,怎么写得好征文呢?
想到这,我摇了摇头,男人怎么能说不行,既然我从不了解GO,我现学不就行了,把学完的感受与总结写下来,不是更贴合此次征文的主题?
可以参考的技术主题 : golang入门系列
说干就干,我直接打开百度搜索go浏览了第一页之后,找到两个入门级的教程和官网,就开始了我的Golang入门之旅。
- 安装
Golang官网小白学习第一步,装环境。
我首先打开官网用我初中的英语水平准确找到了windows环境安装包的下载链接,像现在的所有语言一样,双击 -> 安装 -> Next Step -> Finish一气呵成,安装就像喝水一样简单。
因为有着Java的安装经验,所以我熟练的打开DOS窗口,分别输入:go version
和 go env
命令进行测试。
看到这两个命令都输出了预想中的结果,我欣慰的笑了笑,安装,不过如此。
不过我注意到网上的教程都让我安装之后先设置一个叫GO-PATH
的东西,是熟悉的感觉,我仿佛又回到了四年前初学Java的下午,安装完JDK的第一步也是要设置一下JAVA-PATH
,现在的JDK已经不需要手动设置了,安装的时候就已经设置好了。
GO语言作为一门新兴语言总不能还有这种历史包袱吧,我怀着悲痛的心情点开了电脑的环境变量:
果然,系统已经帮我设置好了,不用我去手动设置了。
不过坑爹的是这个目录下我原先并没有go文件夹,它居然也没有帮我创建,而且根据GO的规定,你每个项目都要在这里指定一次的环境变量,也就是说如果电脑上有10个项目,你就要在GO-PATH
后面写10个项目的文件夹地址,一点也不自由了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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
好了不说这个,环境变量既然好了,那我们就可以编写我们的Hello-World了,Hello-World入门必敲。
2. Hello-World
--------------
[Golang官网](https://golang.org/)上面有一段代码,教你如何用GO输出Hello-World,我COPY下来就准备贴了。
但是转念一想,根据GO的规定要在go项目的文件夹下必须有`bin`,`pkg`,`src`目录,我直接用默认的go文件夹作为项目的根目录,所以我就在这下面又手动建了这三个文件夹。
建好了之后,我打开万能编辑器-VSCODE,下载一个go语言支持,就开写了。
准备写的时候呢,这个VSCODE又提醒我要安装一堆插件:

从这堆东西的名字看来,应该是go相关的工具包,不过因为是连GitHub下载我几次下载都失败了,最好在网上找了方法,可以用go-proxy来设置国内代理,不过我设置好了之后依旧是从GitHub下载,最后重启了一下VSCODE才慢吞吞的下载好(依旧是从GITHUB下载)。
这些准备工作做好之后,我在src包下编写了我的第一个GO程序-Hello-World,新建一个以go.go文件,然后把官网的代码copy进去如下:
```
go复制代码package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
```
这样我们的程序就编写好了,紧接着进行手动编译运行,go提供了`go build`和`go run`命令帮助我们编译运行。

`go build`命令是编译,`go run`是编译后运行,不过他俩还有其他区别,暂时可以只记这么多。
---
我可以再简要说说这段Hello-World代码,`package main`声明这是主函数的入口类,`import "fmt"`则是我们用到了go内置的`fmt`包,最后是定义了一个名为`main`的函数,使用`fmt`包下的`Println`进行字符串打印。
如果你有其他语言的基础,这点东西太小kiss了。
3. 巧遇拦路虎
--------
接下来我准备仗着自己有点Java基础,直接写一个爬虫来练练手,我看大家都是爬豆瓣电影TOP250练手,我就爬[豆瓣读书TOP250](https://book.douban.com/top250)吧。
在这之前,我没有看过任何关于GO的东西,仅仅看了如何定义变量,的确有点反常识,因为Go语言的变量定义是把类型放在后面,我给大家演示一下:
```
go复制代码var str string
```
第一次看到的时候的确一点也不喜欢,因为太有违我的习惯了,不过真正写起来之后发现还真不是这么回事,Go有点像JS,它的类型是可以直接推断的,加之GO定义变量有个简单写法:
```
go复制代码str := "和耳朵真棒!"
```
我们平常可以用这种简单写法来写,这代表变量赋值二合一。
在后面我写爬虫的时候基本都是用这种方式来定义变量的,根本轮不到自己去指定类型。
语法什么的都不是问题,我遇到的第一个问题是导包,因为要写爬虫,我起码要有一个DOM树解析的工具,不然自己正则写起来要累死了。
在最开始的时候我还在嘲笑GO居然非要把项目放在`GOPATH`下面,后来在导包这个问题上面我查了查资料发现自从GO引入了mod模块之后已经可以把项目放在任何一个文件夹了。
mod模块用我的理解就是一个包管理器,把平常项目中需要用到的包都下载起来,然后项目用到的时候直接导,没有的话就去远程下载,类似Java中的Maven和Gradle概念。
既然牵扯到包了,那远程的肯定慢啊,必须要加入国内镜像才能快起来:
```
go复制代码go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
```
加入国内镜像之后,就可以愉快的下载我们所需要的包了:
```
go复制代码go get github.com/PuerkitoBio/goquery
```
> goquery类似jquery,它是jquery的go版本实现,使用它,可以很方便的对HTML进行处理。
说白了就是一个方便操作DOM树的一个工具而已。
下载好依赖之后,我们就可以创建自己的项目了~
随便找一个文件夹,打开dos输入`go mod init xxx`,即可初始化自己的GO项目,这个XX指的是本项目的名字,然后这个文件夹下面就会出现go.mod文件,这个文件记录了项目中引入了那些依赖,慢慢还会出现go.sum文件,都是自动生成,不用理会,专注编码即可。
4. 爬取豆瓣读书TOP250
---------------
我在创建了一个`hello-go`文件夹,初始化之后,建立了一个go.go文件,编写好main函数之后,我们的程序主体就可以开始编写了。
```
go复制代码package main
import (
"fmt"
"log"
"net/http"
"os"
"strconv"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
// 创建我们要导出的TXT文件
file, err := os.Create("豆瓣读书TOP250.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
// 创建一个客户端对象,用于发送请求
var client = http.Client{}
for i := 0; i < 250; i += 25 {
// 发送一条新请求
req, _ := http.NewRequest("GET", "https://book.douban.com/top250?start="+strconv.Itoa(i), nil)
// 设置User-Agent 必须
req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
// 发送请求
resp, err := client.Do(req)
// 处理异常
if err != nil {
fmt.Println("http get error", err)
return
}
// 关闭流
defer resp.Body.Close()
// 通过goquery将流中的内容构建成一棵DOM树
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}
// 拿到所有标记的节点集合
// 并进行each循环,i = 序号,s = 节点本身
doc.Find("div.indent>table>tbody>tr.item").Each(func(i int, s *goquery.Selection) {
// 拿到节点集合中的Items
item := s.Find("td[valign=top]")
// 通过Item节点获取到我们所需要的数据
// 对数据进行去空格 去换行操作
bookName := strings.Replace(strings.Replace(item.Find("div.pl2>a").Text(), "\n", "", -1), " ", "", -1)
author := strings.Split(s.Find("p.pl").Text(), "/")[0]
quote := strings.Replace(strings.Replace(s.Find("p.quote").Text(), "\n", "", -1), " ", "", -1)
// 拿到我们已经处理好的数据之后 接下来就是往TXT里面填充了
//fmt.Print("TOP" + fmt.Sprint(i) + "-" + bookName + "-" + author + "-" + quote)
// 处理字符直接的空格长度,尽力对齐
bookName = bookName + strings.Repeat(" ", (120-len(bookName)))
author = author + strings.Repeat(" ", (50-len(author)))
content := "TOP" + strconv.Itoa(i) + "\t" + bookName + author + quote + "\n"
file.WriteString(content)
})
}
fmt.Print("程序执行完毕,请查看结果。")
}
```
小伙伴们可以直接粘贴到自己编辑器中,包什么的会自动导入的,然后运行此文件即可。
这里面的代码基本都是我到处搜索:
* `go 如何发送请求?`
* `go 如何去除字符串空格?`
* `go 如何拿到字符串长度?`
* `go 如何读写文件?`
我都是遇山开山,遇水搭桥一步步的找齐我自己需要用到的知识点,然后把他们凑到一块
给大家看看效果:
导出Excel的话就更完美了,对了,run大家应该会把: go run go.go
即可。
好了,今天的征文就到这里,总体看下来GO还是用起来挺方便的,就是时间太短,没有好好学习GO的并发的相关知识~
下期见。
本文转载自: 掘金