使用Go语言(golang)写个简单的爬虫
tt-0411 · · 10894 次点击 · · 开始浏览上次用Scala写了个爬虫。最近在闲工夫之时,学习Go语言,便用Go移植了那个用Scala写的爬虫,代码如下:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"regexp"
)
var (
ptnIndexItem = regexp.MustCompile(`<a target="_blank" href="(.+\.html)" title=".+" >(.+)</a>`)
ptnContentRough = regexp.MustCompile(`(?s).*<div class="artcontent">(.*)<div id="zhanwei">.*`)
ptnBrTag = regexp.MustCompile(`<br>`)
ptnHTMLTag = regexp.MustCompile(`(?s)</?.*?>`)
ptnSpace = regexp.MustCompile(`(^\s+)|( )`)
)
func Get(url string) (content string, statusCode int) {
resp, err1 := http.Get(url)
if err1 != nil {
statusCode = -100
return
}
defer resp.Body.Close()
data, err2 := ioutil.ReadAll(resp.Body)
if err2 != nil {
statusCode = -200
return
}
statusCode = resp.StatusCode
content = string(data)
return
}
type IndexItem struct {
url string
title string
}
func findIndex(content string) (index []IndexItem, err error) {
matches := ptnIndexItem.FindAllStringSubmatch(content, 10000)
index = make([]IndexItem, len(matches))
for i, item := range matches {
index[i] = IndexItem{"http://www.yifan100.com" + item[1], item[2]}
}
return
}
func readContent(url string) (content string) {
raw, statusCode := Get(url)
if statusCode != 200 {
fmt.Print("Fail to get the raw data from", url, "\n")
return
}
match := ptnContentRough.FindStringSubmatch(raw)
if match != nil {
content = match[1]
} else {
return
}
content = ptnBrTag.ReplaceAllString(content, "\r\n")
content = ptnHTMLTag.ReplaceAllString(content, "")
content = ptnSpace.ReplaceAllString(content, "")
return
}
func main() {
fmt.Println(`Get index ...`)
s, statusCode := Get("http://www.yifan100.com/dir/15136/")
if statusCode != 200 {
return
}
index, _ := findIndex(s)
fmt.Println(`Get contents and write to file ...`)
for _, item := range index {
fmt.Printf("Get content %s from %s and write to file.\n", item.title, item.url)
fileName := fmt.Sprintf("%s.txt", item.title)
content := readContent(item.url)
ioutil.WriteFile(fileName, []byte(content), 0644)
fmt.Printf("Finish writing to %s.\n", fileName)
}
}
代码行数比Scala版的有一定增加,主要原因有以下几方面原因:
1 golang 重视代码书写规范,或者说代码格式,很多地方写法比较固定,甚至比较麻烦。比如就算是if判断为真后的执行语句只有一句话,按照代码规范,也要写出带大括号的三行,而在Scala和很多其他语言中,一行就行;
2 golang 的strings包和regexp包提供的方法并不特别好用,特别是和Scala相比,使用起来感觉Scala的正则和字符串处理要舒服的多;
3 scala版的爬虫里面用到了Scala标准库中的实用类和方法,它们虽然不是语法组成,但用起来感觉像是语法糖,这里很多方法和函数式编程有关,golang的函数式编程还没有去仔细学习。
当然golang版的爬虫也有一个优势,就是编译速度很快,执行速度在现在的写法里面体现不出优势;golang的特性goroutine在这里没有用到,这段代码今后会不断改进。
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
上次用Scala写了个爬虫。最近在闲工夫之时,学习Go语言,便用Go移植了那个用Scala写的爬虫,代码如下:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"regexp"
)
var (
ptnIndexItem = regexp.MustCompile(`<a target="_blank" href="(.+\.html)" title=".+" >(.+)</a>`)
ptnContentRough = regexp.MustCompile(`(?s).*<div class="artcontent">(.*)<div id="zhanwei">.*`)
ptnBrTag = regexp.MustCompile(`<br>`)
ptnHTMLTag = regexp.MustCompile(`(?s)</?.*?>`)
ptnSpace = regexp.MustCompile(`(^\s+)|( )`)
)
func Get(url string) (content string, statusCode int) {
resp, err1 := http.Get(url)
if err1 != nil {
statusCode = -100
return
}
defer resp.Body.Close()
data, err2 := ioutil.ReadAll(resp.Body)
if err2 != nil {
statusCode = -200
return
}
statusCode = resp.StatusCode
content = string(data)
return
}
type IndexItem struct {
url string
title string
}
func findIndex(content string) (index []IndexItem, err error) {
matches := ptnIndexItem.FindAllStringSubmatch(content, 10000)
index = make([]IndexItem, len(matches))
for i, item := range matches {
index[i] = IndexItem{"http://www.yifan100.com" + item[1], item[2]}
}
return
}
func readContent(url string) (content string) {
raw, statusCode := Get(url)
if statusCode != 200 {
fmt.Print("Fail to get the raw data from", url, "\n")
return
}
match := ptnContentRough.FindStringSubmatch(raw)
if match != nil {
content = match[1]
} else {
return
}
content = ptnBrTag.ReplaceAllString(content, "\r\n")
content = ptnHTMLTag.ReplaceAllString(content, "")
content = ptnSpace.ReplaceAllString(content, "")
return
}
func main() {
fmt.Println(`Get index ...`)
s, statusCode := Get("http://www.yifan100.com/dir/15136/")
if statusCode != 200 {
return
}
index, _ := findIndex(s)
fmt.Println(`Get contents and write to file ...`)
for _, item := range index {
fmt.Printf("Get content %s from %s and write to file.\n", item.title, item.url)
fileName := fmt.Sprintf("%s.txt", item.title)
content := readContent(item.url)
ioutil.WriteFile(fileName, []byte(content), 0644)
fmt.Printf("Finish writing to %s.\n", fileName)
}
}
代码行数比Scala版的有一定增加,主要原因有以下几方面原因:
1 golang 重视代码书写规范,或者说代码格式,很多地方写法比较固定,甚至比较麻烦。比如就算是if判断为真后的执行语句只有一句话,按照代码规范,也要写出带大括号的三行,而在Scala和很多其他语言中,一行就行;
2 golang 的strings包和regexp包提供的方法并不特别好用,特别是和Scala相比,使用起来感觉Scala的正则和字符串处理要舒服的多;
3 scala版的爬虫里面用到了Scala标准库中的实用类和方法,它们虽然不是语法组成,但用起来感觉像是语法糖,这里很多方法和函数式编程有关,golang的函数式编程还没有去仔细学习。
当然golang版的爬虫也有一个优势,就是编译速度很快,执行速度在现在的写法里面体现不出优势;golang的特性goroutine在这里没有用到,这段代码今后会不断改进。