cmatrixprobe

发呆业务爱好者

从零开始Golang爬虫(一)| 预备知识

这几天我这学期选修的实训课开课了,实践内容是用python的scrapy框架实现爬虫,最后还要做数据展示。因为框架屏蔽了许多细节,不便于理解原理,而python又不熟悉,所以决定自己用Go原生实现一下。


首先需要掌握爬虫的预备知识,主要包括正则表达式、CSS选择器或XPath,可以通过它们从页面中提取有效信息,这些在菜鸟教程都可以查到,所以这里只列一些常用的规则以及如何在Go中调用。

正则表达式

字符描述
^以^后面字符开头
.任意字符
**前面字符出现任意次
$以$前面字符结尾
?非贪婪匹配(从前向后)
++前面字符出现至少一次
{2}前面字符出现2次
{2,}前面字符出现最少2次
{2,5}前面字符出现2-5次
|
[abcd]满足abcd任意一个
[A-Za-z0-9_]满足区间内任意一个
[^1]满足除1以外任意字符
\s[\t\n\f\r ]
\S与\s相反
\w[A-Za-z0-9_]
\W与\w相反
[\u4E00-\u9FA5]汉字
\d数字

regexp

Go标准库提供了专门的正则表达式库regexp,采用RE2语法,与python正则基本一致

regexp包的内容很简单,主要由Match、Compile、Find和ReplaceAll四部分组成,在爬虫中ReplaceAll一般用不到

Match

首先是以Match开头的3个函数:

func Match(pattern string, b []byte) (matched bool, err error)
func MatchString(pattern string, s string) (matched bool, err error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)

都用于检查是否存在匹配pattern的子序列,区别仅在于待匹配串的数据类型不同

Compile

Compile用于将模式串转换成Regexp对象,然后可以通过Regexp对象进行Match与Find

func Compile(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompilePOSIX(str string) *Regexp

Must表示解析失败会直接panic,POSIX会将匹配模式设置为leftmost-longest,这里一般只用MustCompile就好

Find

Find包括十多种方法,都由以下四种参数排列组合而成:

参数描述
String传入String,没有则传入[]byte
All返回所有结果,没有则只返回第一个
Submatch返回整串匹配以及所有子匹配的Silce
Index返回下标,没有则返回匹配到的字符串

CSS选择器

字符描述
*选择所有节点
#container选择id为container的节点
.container选择所有class包含container的节点
li a选择所有li下的所有a节点
ul + p选择ul后面的第一个p元素
div#container > ul选取id为container的div的第一个ul子元素
ul ~ p选取与ul相邻的所有p元素
a[title]选取所有有title属性的a元素
a[href=http://baidu.com]选取所有href属性为baidu.com的a元素
a[href*=baidu]选取所有href属性包含baidu的a元素
a[href^=http]选取所有href属性值以http开头的a元素
a[href$=.jpg]选取所有href属性值以.jpg结尾的a元素
input[type=radio]:checked选择选中的radio元素
div:not(#container)选取所有id非container的div元素
li:nth-child(3)选取第三个li元素
tr:nth-child(2n)选取第偶数个tr元素

goquery

goquery是github上的开源库,语法类似jQuery,除了提供CSS选择器还支持contains和has这样的内容过滤器,还能轻松地实现dom节点操作

doc, err := goquery.NewDocumentFromReader(body)
if err != nil {
    log.Fatalf("Parse error: %s", err)
}

NewDocumentFromReader函数接收一个io.Reader接口变量,返回Document指针,然后可以通过doc.Find基于CSS选择器查找,返回Selection指针表示html中的一个node,
而对于* Selection,goquery提供了诸如Next、Parent、Children、Each、Map等大量方法实现了节点操作,同样也可以通过Find进一步查找。

XPath

字符描述
article选取所有article元素的所有子节点
/article选取根元素article
article/a选取所有属于article的子元素的a元素
//div选取所有div子元素
article//div选取所有属于article元素的后代的div元素
//@class选取所有名为class的属性
/article/div[1]选取属于article子元素的第一个div元素
/article/div[last()]选取属于article子元素的最后一个div元素
/article/div[last()-1]选取属于article子元素的倒数第二个div元素
//div[@lang]选取所有拥有lang属性的div元素
//div[@lang=eng]选取所有lang属性为eng的div元素
/div/*选取属于div元素的所有子节点
//*选取所有元素
//div[@*]选取所有带属性的title元素
/div/a//div/p | 选取所有div元素的a和p元素
//span//ul | 选取文档中的span和ul元素
article/div/p//span | 选取所有属于article元素的div元素的p元素以及文档中所有的span元素

小结

至此,爬虫的预备知识就全部结束了,由于我对于CSS比较熟悉,所以将主要使用CSS选择器配合正则表达式进行数据的解析。

Golang传参slice函数中append的陷阱

上一篇

从零开始Golang爬虫(二)| 初步完成

下一篇
评论
头像 发表评论 说点什么
还没有评论
1825
0