Avec la popularisation d'Internet et le développement accéléré de l'informatisation, de plus en plus de données sont stockées sur Internet, les robots d'exploration Web sont donc devenus un outil indispensable pour de nombreuses personnes. Parmi eux, Golang Crawler est devenu le langage d’écriture de robots préféré de nombreux programmeurs en raison de sa simplicité, de son efficacité et de son évolutivité.
Cet article présentera les composants de base et les méthodes d'écriture du robot d'exploration Golang.
1. Les composants de base de Golang Crawler
URL Manager est principalement responsable de la gestion de la file d'attente d'URL qui doit être explorée, ainsi que des opérations associées telles que la déduplication. Il comprend principalement les fonctions suivantes :
Webpage Downloader est principalement responsable du téléchargement de la page Web correspondant à l'URL vers le local. Il peut utiliser différentes méthodes de téléchargement en fonction des différentes caractéristiques de l'URL, telles que HTTP, HTTPS, FTP, etc. Dans Golang, les pages Web peuvent être téléchargées à l'aide de bibliothèques tierces telles que net/http.
Webpage Parser est principalement responsable de l'analyse de la page Web téléchargée, de l'obtention des données requises et de sa sauvegarde. En Golang, les pages Web peuvent être analysées via des expressions régulières, un analyseur HTML5, goquery et d'autres méthodes.
Le stockage est principalement responsable du stockage des données analysées. Il existe généralement deux méthodes de stockage de base de données et de stockage de fichiers locaux. Dans Golang, des bibliothèques tierces telles que GORM, orm, etc. peuvent être utilisées pour le stockage de données.
2. Comment écrire un robot d'exploration golang
Le gestionnaire d'URL est principalement utilisé pour gérer les URL à explorer/explorer et fournit des opérations telles que l'ajout d'URL, l'obtention d'URL et la détermination de l'existence d'URL. .
type UrlManager struct { Urls map[string]bool } // 新建URL管理器 func NewUrlManager() *UrlManager { return &UrlManager{Urls: make(map[string]bool)} } // 添加URL到管理器队列 func (um *UrlManager) AddUrl(url string) bool { if um.Urls[url] { // URL已经存在 return false } um.Urls[url] = true return true } // 添加URL列表到管理器队列 func (um *UrlManager) AddUrls(urls []string) bool { added := false for _, url := range urls { if um.AddUrl(url) { added = true } } return added } // 判断URL是否存在 func (um *UrlManager) HasUrl(url string) bool { return um.Urls[url] } // 获取待爬取的URL func (um *UrlManager) GetUrl() string { for url := range um.Urls { delete(um.Urls, url) return url } return "" } // 获取URL数量 func (um *UrlManager) UrlCount() int { return len(um.Urls) }
Le téléchargeur de page Web est principalement utilisé pour télécharger le contenu de la page Web correspondant à l'URL spécifiée et le renvoyer.
type Downloader struct { client *http.Client } // 新建网页下载器 func NewDownloader() *Downloader { return &Downloader{client: &http.Client{}} } // 网页下载 func (d *Downloader) Download(url string) ([]byte, error) { req, err := http.NewRequest("GET", url, nil) req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36") resp, err := d.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // 读取响应正文内容 contents, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } return contents, nil }
L'analyseur de page Web est principalement utilisé pour analyser le contenu de la page Web téléchargée et extraire les données requises. Voici un exemple d'analyseur utilisant goquery comme exemple :
type Parser struct{} // 新建网页解析器 func NewParser() *Parser { return &Parser{} } // 网页解析 func (parser *Parser) Parse(content []byte) []string { doc, err := goquery.NewDocumentFromReader(bytes.NewReader(content)) if err != nil { log.Fatal(err) } var urls []string doc.Find("a").Each(func(i int, s *goquery.Selection) { href, exists := s.Attr("href") if exists && !strings.HasPrefix(href, "javascript") && len(href) > 1 { // 绝对路径和相对路径都考虑 u, err := url.Parse(href) if err != nil { return } if u.IsAbs() { urls = append(urls, href) return } // 补全相对路径,例如:./abc --> http://example.com/abc base, _ := url.Parse(contentUrl) urls = append(urls, base.ResolveReference(u).String()) } }) return urls }
Le stockage est principalement utilisé pour stocker les données analysées localement ou dans une base de données. Voici un exemple de base de données MySQL :
type Storage struct { db *gorm.DB } //新建数据存储器 func NewStorage() *Storage{ db, _ := gorm.Open("mysql", "root:password@tcp(localhost:3306)/mydb?charset=utf8&parseTime=True&loc=Local") return &Storage{db:db} } // 保存数据到数据库 func (storage *Storage) SaveData(data []string) { for _, item := range data { storage.db.Create(&MyModel{Name: item}) } }
Le contrôleur de chenilles implémente principalement les fonctions de planification et de coordination des robots d'exploration. Le processus principal est le suivant :
func Run() { // 初始化URL管理器、网页下载器、网页解析器、存储器 urlManager := NewUrlManager() downLoader := NewDownloader() parser := NewParser() storage := NewStorage() // 添加待爬取的URL urlManager.AddUrl("http://example.com") // 爬虫运行 for urlManager.UrlCount() > 0 { // 获取待爬取的URL url := urlManager.GetUrl() // 判断URL是否已爬取过 if downLoader.IsCrawled(url) { continue } // 下载网页 contents, err := downLoader.Download(url) if err != nil { continue } // 解析网页 urls := parser.Parse(contents) // 存储数据 storage.SaveData(urls) // 将URL添加到已爬取过的URL列表 downLoader.AddCrawled(url) // 将解析出来的URL添加到URL队列中 urlManager.AddUrls(urls) } }
package main import ( "bytes" "github.com/PuerkitoBio/goquery" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" "io/ioutil" "log" "net/http" "net/url" "strings" ) type UrlManager struct { Urls map[string]bool } // 新建URL管理器 func NewUrlManager() *UrlManager { return &UrlManager{Urls: make(map[string]bool)} } // 添加URL到管理器队列 // 添加URL到管理器队列 func (um *UrlManager) AddUrl(url string) bool { if um.Urls[url] { // URL已经存在 return false } um.Urls[url] = true return true } // 添加URL列表到管理器队列 func (um *UrlManager) AddUrls(urls []string) bool { added := false for _, url := range urls { if um.AddUrl(url) { added = true } } return added } // 判断URL是否存在 func (um *UrlManager) HasUrl(url string) bool { return um.Urls[url] } // 获取待爬取的URL func (um *UrlManager) GetUrl() string { for url := range um.Urls { delete(um.Urls, url) return url } return "" } // 获取URL数量 func (um *UrlManager) UrlCount() int { return len(um.Urls) } type Downloader struct { client *http.Client crawledUrls map[string]bool } // 新建网页下载器 func NewDownloader() *Downloader { return &Downloader{client: &http.Client{}, crawledUrls: make(map[string]bool)} } // 网页下载 func (d *Downloader) Download(url string) ([]byte, error) { req, err := http.NewRequest("GET", url, nil) req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36") resp, err := d.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // 读取响应正文内容 contents, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } return contents, nil } // 判断URL是否已爬取 func (d *Downloader) IsCrawled(url string) bool { return d.crawledUrls[url] } // 将URL添加到已爬取列表中 func (d *Downloader) AddCrawled(url string) { d.crawledUrls[url] = true } type Parser struct{} // 新建网页解析器 func NewParser() *Parser { return &Parser{} } // 网页解析 func (parser *Parser) Parse(content []byte,contentUrl string) []string { doc, err := goquery.NewDocumentFromReader(bytes.NewReader(content)) if err != nil { log.Fatal(err) } var urls []string doc.Find("a").Each(func(i int, s *goquery.Selection) { href, exists := s.Attr("href") if exists && !strings.HasPrefix(href, "javascript") && len(href) > 1 { // 绝对路径和相对路径都考虑 u, err := url.Parse(href) if err != nil { return } if u.IsAbs() { urls = append(urls, href) return } // 补全相对路径 base, _ := url.Parse(contentUrl) urls = append(urls, base.ResolveReference(u).String()) } }) return urls } type MyModel struct { gorm.Model Name string } type Storage struct { db *gorm.DB } //新建数据存储器 func NewStorage() *Storage{ db, _ := gorm.Open("mysql", "root:password@tcp(localhost:3306)/mydb?charset=utf8&parseTime=True&loc=Local") db.AutoMigrate(&MyModel{}) return &Storage{db:db} } // 保存数据到数据库 func (storage *Storage) SaveData(data []string) { for _, item := range data { storage.db.Create(&MyModel{Name: item}) } } func Run() { // 初始化URL管理器、网页下载器、网页解析器、存储器 urlManager := NewUrlManager() downLoader := NewDownloader() parser := NewParser() storage := NewStorage() // 添加待爬取的URL urlManager.AddUrl("http://example.com") // 爬虫运行 for urlManager.UrlCount() > 0 { // 获取待爬取的URL url := urlManager.GetUrl() // 判断URL是否已爬取过 if downLoader.IsCrawled(url) { continue } // 下载网页 contents, err := downLoader.Download(url) if err != nil { continue } // 解析网页 urls := parser.Parse(contents,url) // 存储数据 storage.SaveData(urls) // 将URL添加到已爬取过的URL列表 downLoader.AddCrawled(url) // 将解析出来的URL添加到URL队列中 urlManager.AddUrls(urls) } } func main(){ Run() }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!