闲来无事写了一个比较简陋的爬虫,跟大家分享一下, 写的可能有点啰嗦,本来写的是文档,但是这里没办法上传文件,只能以这种方式给大家展示了,下面有很清晰的目录,也可以直接复制到文档中查看,方便目录指引。
《教程:使用go语言编写简单爬虫工具》
目录
- 在使用go之前首先了解什么是go: 8
- 安装go以及相关工具 8
2.1. 安装go运行环境: 8
2.2 安装git : 13
2.3安装编译器VSCode: 18
安装完成 21 - 写一个简单go程序 22
- 使用colly 做一个简单的爬虫工具 23
4.1 最简单的爬虫,爬取网站的a链接内容: 23 - 功能扩展 25
5.1 使用os,io包将爬取到的数据写入到文件中存储 25
5.2 使用gin包将程序设置为一个web 服务 27
5.3 使用proxy包设置IP代理池: 30
5.4 使用sync包实现多线程: 33
5.5 使用cron包将数据抓取添加为计划任务,每半小时执行一次 37
5.6 使用gojieba包进分词管理,抓取指定内容 42
1.在使用go之前首先了解什么是go:
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pike)及肯·汤普逊(Ken Thompson)于2007年9月开始设计Go,稍后Ian Lance Taylor、Russ Cox加入项目。Go是基于Inferno操作系统所开发的。Go于2009年11月正式宣布推出,成为开放源代码项目,并在Linux及Mac OS X平台上进行了实现,后来追加了Windows系统下的实现。在2016年,Go被软件评价公司TIOBE 选为“TIOBE 2016 年最佳语言”。 目前,Go每半年发布一个二级版本(即从a.x升级到a.y)。
Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行模型是以东尼·霍尔的通信顺序进程(CSP)为基础,采取类似模型的其他语言包括Occam和Limbo,但它也具有Pi运算的特征,比如通道传输。在1.8版本中开放插件(Plugin)的支持,这意味着现在能从Go中动态加载部分函数。
与C++相比,Go并不包括如枚举、异常处理、继承、泛型、断言、虚函数等功能,但增加了 切片(Slice) 型、并发、管道、垃圾回收、接口(Interface)等特性的语言级支持。Go 2.0版本将支持泛型,对于断言的存在,则持负面态度,同时也为自己不提供类型继承来辩护。
不同于Java,Go内嵌了关联数组(也称为哈希表(Hashes)或字典(Dictionaries)),就像字符串类型一样。
2.安装go以及相关工具
2.1.安装go运行环境:
2.1.1 开始安装:
首先下载go安装包->https://studygolang.com/dl选择自己需要的版本进行下载,下载完成后进行安装
安装MSI文件或者zip压缩包版本解压,我下载的是:
https://studygolang.com/dl/golang/go1.12.5.windows-amd64.msi,下载完成后双击安装即可
点击Next下一步
选择I accept the terms in the License Agreement. 然后Next 下一步
选择安装目录
2.1.2. 安装完成后,设置环境变量:
打开我的电脑:
进入环境变量配置界面:
配置环境变量:
新建环境变量GOROOT(GOROOT变量值为go的安装目录,我安装的是D:\Go),根据自己的安装路径进行配置
配置path路径( win10 ),在后面path最后添加D:\Go\bin路径(必须是go安装目录下的bin文件):
如果是win7系统( 在路径最后面添加D:\Go\bin ),一定要注意,在添加路径之前一定要用“;”与前面的路径分隔(每个路径之间必须有“;”分隔),路径根据自己的安装路径修改:
2.1.3. 创建项目目录的环境变量:
接下来新建文件夹,作为自己的项目目录,我创建的目录是mygo:
然后继续新建环境变量GOPATH(此变量设置项目路径):
到此处环境变量就设置完成了,接下来测试是否全部设置成功,打开黑窗口(ctrl+r -> cmd) 输入 go env ,显示一下内容表示环境变量设置成功:
输入 go version,显示一下内容,go就可以安装完成了:
2.2 安装git :
如果不安装git 直接进行开发的话,在你引入github 包的时候你会发现出现以下错误:
go get github.com/gocolly/colly: git ls-remote -q
https://github.com/gocolly/colly In D:\mygo\pkg\mod\cache\vcs\eca8728ba98ac04ea7ee3526a26f0326ab6bc4f75745fbfbae6f13421595fd59: exec: “git”: executable file not found in %PATH%
因为github的包都是通过git管理,所以在 go get 包之前要先安装git:
下载git win64 安装包 :
https://github.com/git-for-windows/git/releases/download/v2.21.0.windows.1/Git-2.21.0-64-bit.exe下载完成后,双击安装程序,选择git 相关配置(默认即可):
点击install 开始安装程序,等待安装完成即可。
配置环境变量:打开环境变量配置页面(找不到重新看下上文第五页的打开方式),在path变量后面加上git 的安装路径下的bin目录,我的是D:\MyDownloads\Git\bin, 根据自己的安装目录添加即可。
测试是否安装完成, 打开黑窗口,输入git version查看git版本信息,到此git安装完成。
2.3安装编译器VSCode:
一个好的代码编译器可以极大地帮助我们进行很好的开发,比如Vscode.
首先去VsCode官网下载自己需要的版本,然后进行安装https://code.visualstudio.com/Download
选择我同意
选择安装路径
下一步
选择自己需要的功能后,下一步
点击安装
安装完成
3.写一个简单go程序
在开始写爬虫之前先写个小玩意测试一下,安装后的go是否可以正常编译,以确保后面的开发顺利。
首先在你的项目目录,也就是在安装go之后设置的环境变量GOPATH的目录,创建文件夹src,这个文件夹以后将存放你的所有项目。目录结构可以自己随意定义,但是一定要在src目录下
创建好文件夹后,开始写文件,创建文件main.go
文件中写一个简单的字符串输出(复制下面代码到你创建的文件):
逐行分析这段程序:
第一行是必须的。所有Go语言编写的文件都以package <*>开头,对于独立运行的执行文件必须是 package main;
第二行表示将fmt包加入main。一般非main的其他package(包)都被称为库,
第三行就是程序中的主函数。Go程序执行时候,首先调用的函数就是main函数。这个是从C中继承过来的。这里是main函数的函数定义。
第四行调用fmt包的函数打印字符串到屏幕。字符串由””包裹,并且可以包含非ASCII的字符。
一个独立的可执行的golang程序,package main是必须出现,紧跟在是引入的各种库,然后是各个函数,这里必须要有一个main函数。main函数是程序的入口。
package main // 定义包名
// 引入需要的包
import(
"fmt"
)
// 定义一个方法main
func main(){
// 打印字符串
fmt.Println("go运行环境初次测试,运行正常!")
}
打开黑窗口,进入你的项目目录,比如我项目的文件夹是在D:\mygo\src\test下,输入命令d: , 进入到D盘, 然后 cd D:\mygo\src\test,到项目目录下, 输入 go run main.go
go的一个简单操作就完成啦。接下来就开始正式使用colly实现爬虫吧!!!
4.使用colly 做一个简单的爬虫工具
4.1 最简单的爬虫,爬取网站的a链接内容:
package main // 定义一个包名
// 引入需要用到的包
import(
"log"
"github.com/gocolly/colly"
)
func main(){
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
getHref("https://www.163.com/")
}
// urls 参数为你要爬取的网站的地址
func getHref ( urls string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
href := e.Text // 获取到的a链接的内容
log.Println(href)
})
c.Visit(urls) // 访问网站
}
打开黑窗口 输入 go run main.go,发现出现了如下问题,这是因为你还未从github拉取到colly包,所以在编译的时候找不到。
打开黑窗口 输入 go get github.com/gocolly/colly,等待抓取完成即可,
抓取完成后,在继续 go run main.go 回车 ,至此,一个简单的通过colly爬取网站a链接内容的爬虫工具就做好了。
5.功能扩展
5.1 使用os,io包将爬取到的数据写入到文件中存储
package main
import(
"log"
"github.com/gocolly/colly"
"os"
"io"
)
func main(){
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
getHref("https://www.163.com/")
}
func getHref ( urls string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
href := e.Text
log.Println(href)
filename := "hrefText.txt"
var f *os.File
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if checkFileIsExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close() // 关闭文件
if n == 0 {
return
}
})
c.Visit(urls) // 访问被抓取的网站url
}
func checkFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
复制代码到main.go ,打开黑窗口,到项目目录,输入 go run main.go,文件写入成功
5.2 使用gin包将程序设置为一个web 服务
实现功能:在exe文件运行后,可在浏览器访问,代码如下:
package main
import(
"log"
"github.com/gocolly/colly"
"os"
"io"
"github.com/gin-gonic/gin"
"net/http"
)
func main(){
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
}
func WebRoot(context *gin.Context) {
getHref("https://www.163.com/")
context.String(http.StatusOK, "hello, world")
}
func getHref ( urls string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
href := e.Text
log.Println(href)
filename := "hrefText.txt"
var f *os.File
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if checkFileIsExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close() // 关闭文件
if n == 0 {
return
}
})
c.Visit(urls) // 访问被抓取的网站url
}
func checkFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
打开黑窗口,进入项目目录,输入 go run main.go ,发现又出现了如下错误:
因为你没有gin包,所以使用命令 go get github.com/gin-gonic/gin 去github拉取包下来即可,拉取完毕后,
继续 go run main.go 结果如下:
打开浏览器,访问“本机IP:端口”,我设置的端口是9205(127.0.0.1:9205):
查看文件数据是否生成成功:
到此处结束,说明设置生效。
5.3 使用proxy包设置IP代理池:
设置一个数组变量,变量中装有n个IP地址,每次取一个,可用IP执行,不可用IP删除,代码如下:
package main
import(
"os"
"io"
"log"
"bytes"
"net/http"
"github.com/gocolly/colly"
"github.com/gin-gonic/gin"
"github.com/gocolly/colly/proxy"
)
func main(){
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
}
func WebRoot(context *gin.Context) {
co := colly.NewCollector(colly.AllowURLRevisit())
var ipArray = []string{"http://157.230.232.130:80", "http://213.23.122.170:83", "http://91.205.218.33:80"}
for i := 0; i < len(ipArray); i++ {
if ipArray == nil {
log.Printf( "无可用IP..." )
break
}
rp, err := proxy.RoundRobinProxySwitcher(ipArray[i])
if err != nil {
log.Fatal(err)
}
co.SetProxyFunc(rp)
co.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
})
err = co.Visit("https://httpbin.org/ip")
if err != nil {
log.Printf( ipArray[i] )
ipArray = remove( ipArray, i )
}else{
break
}
}
getHref("https://www.163.com/")
context.String(http.StatusOK, "hello, world")
}
func getHref ( urls string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
href := e.Text
filename := "hrefText.txt"
var f *os.File
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if checkFileIsExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close() // 关闭文件
if n == 0 {
return
}
})
c.Visit(urls) // 访问被抓取的网站url
}
func checkFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
func remove(ipArray []string, i int) []string {
returnArray := append(ipArray[:i], ipArray[i+1:]...)
return returnArray
}
因为是在网上找的免费的代理IP,所以不稳定,有些IP经常会用不了,运行结果如下图:
5.4 使用sync包实现多线程:
在项目目录创建文件domain.txt, 写入想要抓取的网站URL:比如我想要抓取的是
获取文件中的URL,把每个网站的抓取操作分别加入线程,同时进行抓取操作,并将数据写入不同的文件存储,代码如下:
package main
import(
"os"
"io"
"log"
"sync"
"time"
"bytes"
"bufio"
"strings"
"net/http"
"github.com/gocolly/colly"
"github.com/gin-gonic/gin"
"github.com/gocolly/colly/proxy"
)
var wg sync.WaitGroup
func main(){
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
}
func WebRoot(context *gin.Context) {
co := colly.NewCollector(colly.AllowURLRevisit())
var ipArray = []string{"http://157.230.232.130:80", "http://213.23.122.170:83", "http://91.205.218.33:80"}
for i := 0; i < len(ipArray); i++ {
if ipArray == nil {
log.Printf( "无可用IP..." )
break
}
rp, err := proxy.RoundRobinProxySwitcher(ipArray[i])
if err != nil {
log.Fatal(err)
}
co.SetProxyFunc(rp)
co.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
})
err = co.Visit("https://httpbin.org/ip")
if err != nil {
log.Printf( ipArray[i] )
ipArray = remove( ipArray, i )
}else{
break
}
}
checkUrl("./domain.txt");
context.String(http.StatusOK, "hello, world")
}
// 获取文件内的所有url,然后进行数据抓取
func checkUrl( filePath string){
fi, err := os.Open(filePath)
if err != nil {
log.Printf("Error: %s\n", err)
return
}
defer fi.Close()
br := bufio.NewReader(fi)
for {
a, _, c := br.ReadLine()
if c == io.EOF {
break
}
Splitstring := strings.Split(string(a), ".")
// 调用方法将抓取到的数据写入文件
wg.Add(1)
go getHref( string(a), Splitstring[1])
}
wg.Wait()
}
func getHref ( urls string, filename string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
var filename string = filename
var f *os.File
href := e.Text
path := ""
time := time.Now().Format("2006-01-02")
path = "record/" + filename + "/"
filename = path + time + "---" + filename + ".txt"
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if !isExist(path) {
err := os.MkdirAll(path,os.ModePerm)
f, _ = os.Create(filename) //创建文件
if err != nil{
log.Println(err)
}
}else{
if isExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close()
if n == 0 {
return
}
})
c.Visit(urls) // 访问被抓取的网站url
}
// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func remove(ipArray []string, i int) []string {
returnArray := append(ipArray[:i], ipArray[i+1:]...)
return returnArray
}
打开黑窗口,进入项目目录,输入 go run main.go 等程序运行结束,打开项目文件夹 你会发现所有文件已经写入到相关文件内
5.5 使用cron包将数据抓取添加为计划任务,每半小时执行一次
添加定时任务,每半小时执行一次,我为了看效果这里设置的是随意设置的秒,自己根据需求自行修改spec的值,具体参数说明请查看官方文档
https://godoc.org/github.com/robfig/cron
具体实现代码如下:
package main
import(
"os"
"io"
"log"
"sync"
"time"
"bytes"
"bufio"
"strings"
"net/http"
"github.com/robfig/cron"
"github.com/gocolly/colly"
"github.com/gin-gonic/gin"
"github.com/gocolly/colly/proxy"
)
var wg sync.WaitGroup
func main(){
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
}
func WebRoot(context *gin.Context) {
co := colly.NewCollector(colly.AllowURLRevisit())
var ipArray = []string{"http://157.230.232.130:80", "http://213.23.122.170:83", "http://91.205.218.33:80"}
for i := 0; i < len(ipArray); i++ {
if ipArray == nil {
log.Printf( "无可用IP..." )
break
}
rp, err := proxy.RoundRobinProxySwitcher(ipArray[i])
if err != nil {
log.Fatal(err)
}
co.SetProxyFunc(rp)
co.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
})
err = co.Visit("https://httpbin.org/ip")
if err != nil {
log.Printf( ipArray[i] )
ipArray = remove( ipArray, i )
}else{
break
}
}
var i int = 0
c := cron.New()
spec := "*/50 * * * * ?"
c.AddFunc(spec, func() {
i++
log.Printf("这是第%d次执行!", i)
checkUrl("./domain.txt");
})
c.Start()
context.String(http.StatusOK, "hello, world")
}
// 获取文件内的所有url,然后进行数据抓取
func checkUrl( filePath string){
fi, err := os.Open(filePath)
if err != nil {
log.Printf("Error: %s\n", err)
return
}
defer fi.Close()
br := bufio.NewReader(fi)
for {
a, _, c := br.ReadLine()
if c == io.EOF {
break
}
Splitstring := strings.Split(string(a), ".")
// 调用方法将抓取到的数据写入文件
wg.Add(1)
go getHref( string(a), Splitstring[1])
}
wg.Wait()
}
func getHref ( urls string, filename string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
var filename string = filename
var f *os.File
href := e.Text
path := ""
time := time.Now().Format("2006-01-02")
path = "record/" + filename + "/"
filename = path + time + "---" + filename + ".txt"
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if !isExist(path) {
err := os.MkdirAll(path,os.ModePerm)
f, _ = os.Create(filename) //创建文件
if err != nil{
log.Println(err)
}
}else{
if isExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close()
if n == 0 {
return
}
})
c.Visit(urls) // 访问被抓取的网站url
}
// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func remove(ipArray []string, i int) []string {
returnArray := append(ipArray[:i], ipArray[i+1:]...)
return returnArray
}
打开黑窗口,进入项目目录,输入go run main.go提示如下:
提示没有cron包,执行go get github.com/robfig/cron
继续执行 go run main.go 提示如下:
去浏览器输入127.0.0.1:9205
此时计划任务已经成功生成,任务会根据spec 配置在规定时间执行任务
5.6 使用gojieba包进分词管理,抓取指定内容
当前爬取的是所有数据,但很多时候我们并不需要所有数据,gojieba就可以帮我们解决,在使用之前首先要先获取gojieba 包,打开黑窗口,输入 go get github.com/yaniwu/gojieba
具体代码如下:
package main
import(
"os"
"io"
"log"
"sync"
"time"
"bytes"
"bufio"
"strings"
"net/http"
"github.com/robfig/cron"
"github.com/gocolly/colly"
"github.com/gin-gonic/gin"
"github.com/yanyiwu/gojieba"
"github.com/gocolly/colly/proxy"
)
var wg sync.WaitGroup
func main(){
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
// 调用getHref()方法,传一个字符串类型的参数,进行相关网址的a链接内容抓取
}
func WebRoot(context *gin.Context) {
co := colly.NewCollector(colly.AllowURLRevisit())
var ipArray = []string{"http://157.230.232.130:80", "http://213.23.122.170:83", "http://91.205.218.33:80"}
for i := 0; i < len(ipArray); i++ {
if ipArray == nil {
log.Printf( "无可用IP..." )
break
}
rp, err := proxy.RoundRobinProxySwitcher(ipArray[i])
if err != nil {
log.Fatal(err)
}
co.SetProxyFunc(rp)
co.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
})
err = co.Visit("https://httpbin.org/ip")
if err != nil {
log.Printf( ipArray[i] )
ipArray = remove( ipArray, i )
}else{
break
}
}
var i int = 0
c := cron.New()
spec := "*/50 * * * * ?"
c.AddFunc(spec, func() {
i++
log.Printf("这是第%d次执行!", i)
checkUrl("./domain.txt");
})
c.Start()
context.String(http.StatusOK, "hello, world")
}
// 获取文件内的所有url,然后进行数据抓取
func checkUrl( filePath string){
fi, err := os.Open(filePath)
if err != nil {
log.Printf("Error: %s\n", err)
return
}
defer fi.Close()
br := bufio.NewReader(fi)
for {
a, _, c := br.ReadLine()
if c == io.EOF {
break
}
Splitstring := strings.Split(string(a), ".")
// 调用方法将抓取到的数据写入文件
wg.Add(1)
go getHref( string(a), Splitstring[1])
}
wg.Wait()
}
func getHref ( urls string, filename string ) {
c := colly.NewCollector()
visited := false
c.OnResponse(func(r *colly.Response) {
// log.Println(string(r.Body))
if !visited {
visited = true
r.Request.Visit("/get?q=2")
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
var filename string = filename
var f *os.File
href := e.Text
path := ""
time := time.Now().Format("2006-01-02")
path = "record/" + filename + "/"
filename = path + time + "---" + filename + ".txt"
var s string
var words []string
use_hmm := true
x := gojieba.NewJieba()
defer x.Free()
s = "中国美国"
words = x.Cut(s, use_hmm)
var words_string string
length := len( words )
num := 0
for {
words_string = words[num]
if strings.Contains(href, words_string) == true{
/***************************** 第一种方式: 使用 io.WriteString 写入文件 ***********************************************/
if !isExist(path) {
err := os.MkdirAll(path,os.ModePerm)
f, _ = os.Create(filename) //创建文件
if err != nil{
log.Println(err)
}
}else{
if isExist(filename) { //如果文件存在
f, _ = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件
}else {
f, _ = os.Create(filename) //创建文件
}
}
n, _ := io.WriteString(f, href +"\n", ) //写入文件(字符串).
f.Close()
if n == 0 {
return
}
}
num++
if num >= length{
break
}
}
})
c.Visit(urls) // 访问被抓取的网站url
}
// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func remove(ipArray []string, i int) []string {
returnArray := append(ipArray[:i], ipArray[i+1:]...)
return returnArray
}
你会发现获取到的数据都是我们需要的,包含“中国”,“美国”的标题,运行结果如下图:
到此为止,一个简单的爬虫就已经完成搭建完成。