本系列整理了10个工作量和难度适中的Golang小项目,适合已经掌握Go语法的工程师进一步熟练语法和常用库的用法。
问题描述:
实现一个网络爬虫,以输入的URL为起点,使用广度优先顺序访问页面。
要点:
- 实现对多个页面的并发访问,同时访问的页面数由参数 -concurrency 指定,默认为 20。
使用 -depth 指定访问的页面深度,默认为 3。
注意已经访问过的页面不要重复访问。
扩展:
- 将访问到的页面写入到本地以创建目标网站的本地镜像,注意,只有指定域名下的页面需要采集,写入本地的页面里的元素的href的值需要被修改为指向镜像页面,而不是原始页面。
实现:
import (
"bytes"
"flag"
"fmt"
"golang.org/x/net/html"
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
type URLInfo struct {
url string
depth int
}
var base *url.URL
func forEachNode(n *html.Node, pre, post func(n *html.Node)){
if pre != nil{
pre(n)
}
for c := n.FirstChild; c != nil; c = c.NextSibling{
forEachNode(c, pre, post)
}
if post != nil{
post(n)
}
}
func linkNodes(n *html.Node) []*html.Node {
var links []*html.Node
visitNode := func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "a" {
links = append(links, n)
}
}
forEachNode(n, visitNode, nil)
return links
}
func linkURLs(linkNodes []*html.Node, base *url.URL) []string {
var urls