引言
之前用Python写过一个解析网页的脚本,最近开始研究golang,所以准备用golang将其重构,但是这个脚本中使用了到了python中的xpath库,所以研究了下,golang也有对应的库,这个库比我们使用正则从网页中获取我们需要的内容更简单些。
实例
我们以解析网页中的ip+端口为例:网站:https://www.kuaidaili.com/free/inha
1、引入包
github.com/antchfx/htmlquery v1.2.5
2、获得网页内容
func getHtml(url_ string) string {
req, _ := http.NewRequest("GET", url_, nil)
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3776.0 Safari/537.36")
client := &http.Client{Timeout: time.Second * 5}
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil && data == nil {
log.Fatalln(err)
}
return fmt.Sprintf("%s", data)
}
3、解析内容
func main() {
urlTemplate := "https://www.kuaidaili.com/free/inha/%d/"
for i := 1; i < 4000; i++ {
var proxies []string
html := getHtml(fmt.Sprintf(urlTemplate, i))
root, _ := htmlquery.Parse(strings.NewReader(html))
tr := htmlquery.Find(root, "//*[@id='list']/table/tbody/tr")
for _, row := range tr {
item := htmlquery.Find(row, "./td")
ip := htmlquery.InnerText(item[0])
port := htmlquery.InnerText(item[1])
//type_ := htmlquery.InnerText(item[3])
p := ip + ":" + port
proxies = append(proxies, p)
}
}
}
通过上面代码我们就可以从页面中将我们需要的ip+port内容获取到,我们可以根据这种格式解析我们自己想要的网页内容。
4、xpath语法
5、其它是实现
golang中多个包来实现xpath,我们再看下libxml2
包引入
go get github.com/lestrrat-go/libxml2
解析内容
<ol class="grid_view">
<li>
<div class="item">
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1292052/" class="">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港) / 刺激 1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
</div>
</div>
</li>
....
</ol>
golang代码
func parseUrls(url string, ch chan bool) {
doc := fetch(url)
defer doc.Free()
nodes := xpath.NodeList(doc.Find(`//ol[@class="grid_view"]/li//div[@class="hd"]`))
for _, node := range nodes {
urls, _ := node.Find("./a/@href")
titles, _ := node.Find(`.//span[@class="title"]/text()`)
log.Println(strings.Split(urls.NodeList()[0].TextContent(), "/")[4],
titles.NodeList()[0].TextContent())
}
time.Sleep(2 * time.Second)
ch <- true
}
这种方式比第一种方式使用起来麻烦一些,并且接口和文档都不是非常的完善。