纸上得来终觉浅,绝知此事要躬行。
这两天看到了掘金的GO征文活动,看着奖品有小册兑换码,我不禁心动了起来,不过转念一想,自己根本没接触过GO,怎么写得好征文呢?
想到这,我摇了摇头,男人怎么能说不行,既然我从不了解GO,我现学不就行了,把学完的感受与总结写下来,不是更贴合此次征文的主题?
可以参考的技术主题 : golang入门系列
说干就干,我直接打开百度搜索go浏览了第一页之后,找到两个入门级的教程和官网,就开始了我的Golang入门之旅。
1. 安装
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个项目的文件夹地址,一点也不自由了~~~~
好了不说这个,环境变量既然好了,那我们就可以编写我们的Hello-World了,Hello-World入门必敲。
2. Hello-World
Golang官网上面有一段代码,教你如何用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进去如下:
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吧。
在这之前,我没有看过任何关于GO的东西,仅仅看了如何定义变量,的确有点反常识,因为Go语言的变量定义是把类型放在后面,我给大家演示一下:
var str string
复制代码
第一次看到的时候的确一点也不喜欢,因为太有违我的习惯了,不过真正写起来之后发现还真不是这么回事,Go有点像JS,它的类型是可以直接推断的,加之GO定义变量有个简单写法:
str := "和耳朵真棒!"
复制代码
我们平常可以用这种简单写法来写,这代表变量赋值二合一。
在后面我写爬虫的时候基本都是用这种方式来定义变量的,根本轮不到自己去指定类型。
语法什么的都不是问题,我遇到的第一个问题是导包,因为要写爬虫,我起码要有一个DOM树解析的工具,不然自己正则写起来要累死了。
在最开始的时候我还在嘲笑GO居然非要把项目放在GOPATH
下面,后来在导包这个问题上面我查了查资料发现自从GO引入了mod模块之后已经可以把项目放在任何一个文件夹了。
mod模块用我的理解就是一个包管理器,把平常项目中需要用到的包都下载起来,然后项目用到的时候直接导,没有的话就去远程下载,类似Java中的Maven和Gradle概念。
既然牵扯到包了,那远程的肯定慢啊,必须要加入国内镜像才能快起来:
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
复制代码
加入国内镜像之后,就可以愉快的下载我们所需要的包了:
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函数之后,我们的程序主体就可以开始编写了。
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的并发的相关知识~~~
下期见。