Maison  >  Article  >  développement back-end  >  Les composants de base et les méthodes d'écriture du robot d'exploration Golang

Les composants de base et les méthodes d'écriture du robot d'exploration Golang

PHPz
PHPzoriginal
2023-04-25 16:19:25656parcourir

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

  1. URL Manager (UrlManager)

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 :

  • Ajouter une URL : ajoutez l'URL qui doit être explorée à la file d'attente ;
  • Obtenir l'URL : obtenez l'URL à explorer à partir de la file d'attente d'URL
  • URL de stockage : ajoutez l'URL qui doit être explorée ; a été exploré Stockez-le ;
  • Déduplication : empêche l'exploration répétée de la même URL.
  1. Webpage Downloader (Downloader)

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.

  1. Webpage Parser (Parser)

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.

  1. Stockage

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

  1. Créer un gestionnaire d'URL

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)
}
  1. Créer un téléchargeur de page Web

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
}
  1. Créer un analyseur de page Web

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
}
  1. Créer du stockage

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})
    }
}
  1. . Contrôleur de chenilles

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 :

  • Initialiser le gestionnaire d'URL, le téléchargeur de pages Web, l'analyseur de pages Web et le stockage ;
  • Ajouter l'URL à explorer à la file d'attente du gestionnaire d'URL ;
  • Boucler pour obtenir l'URL à explorer ; si l'URL a été explorée, si elle a été explorée, ignorez l'URL ;
  • Téléchargez la page Web correspondant à l'URL ;
  • Analysez la page Web et récupérez les données ;
  • Stockez les données dans la base de données ; Ajoutez l'URL à la liste des URL analysées.
  • 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)
        }
    }
  • Code complet
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()
}
    3. Résumé
  1. golang crawler a les caractéristiques de simplicité, d'efficacité et d'évolutivité, et en raison de ses avantages naturels de concurrence, il peut considérablement augmenter la vitesse d'exploration des données. Cet article présente la composition de base et la méthode d'écriture du robot d'exploration Golang, dans l'espoir d'être utile aux lecteurs. Les lecteurs sont également invités à accumuler plus d'expérience dans la pratique.

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn