Rumah >pembangunan bahagian belakang >Golang >Komponen asas dan kaedah penulisan golang crawler

Komponen asas dan kaedah penulisan golang crawler

PHPz
PHPzasal
2023-04-25 16:19:25692semak imbas

Dengan pempopularan Internet dan pembangunan pemformatan yang dipercepatkan, semakin banyak data disimpan di Internet, jadi perangkak web telah menjadi alat yang sangat diperlukan untuk ramai orang. Antaranya, perangkak golang telah menjadi bahasa penulisan perangkak pilihan ramai pengaturcara kerana kesederhanaan, kecekapan dan kebolehskalaannya.

Artikel ini akan memperkenalkan komponen asas dan kaedah penulisan crawler golang.

1. Komponen asas perangkak golang

  1. Pengurus URL (UrlManager)

Pengurus URL bertanggungjawab terutamanya untuk menguruskan baris gilir URL yang perlu dirangkak, serta operasi yang berkaitan seperti penyahduplikasian. Ia terutamanya termasuk fungsi berikut:

  • Tambah URL: tambahkan URL untuk dirangkak ke baris gilir
  • Dapatkan URL: dapatkan URL untuk dirangkak dari baris gilir URL; 🎜>
  • URL Storan: Simpan URL yang dirangkak;
  • Penyahduplikasi: Elakkan merangkak berulang bagi URL yang sama.
    Pemuat Turun Halaman Web (Pemuat Turun)
Pemuat Turun Halaman Web bertanggungjawab terutamanya untuk memuat turun halaman web yang sepadan dengan URL ke setempat. Ia boleh menggunakan kaedah muat turun yang berbeza mengikut ciri URL yang berbeza, seperti HTTP, HTTPS, FTP, dll. Dalam golang, laman web boleh dimuat turun dengan menggunakan perpustakaan pihak ketiga seperti net/http.

    Penghurai halaman web (Penghurai)
Penghurai halaman web bertanggungjawab terutamanya untuk menghuraikan halaman web yang dimuat turun, mendapatkan data yang diperlukan dan menyimpannya. Dalam golang, halaman web boleh dihuraikan melalui ungkapan biasa, penghurai html5, goquery dan kaedah lain.

    Storan
Storan bertanggungjawab terutamanya untuk menyimpan data yang dihuraikan Secara amnya terdapat dua kaedah storan pangkalan data dan storan fail setempat. Di golang, perpustakaan pihak ketiga seperti GORM, orm, dll. boleh digunakan untuk penyimpanan data.

2. Cara menulis perangkak golang

    Buat pengurus URL
Pengurus URL digunakan terutamanya untuk mengurus URL yang akan dirangkak/dirangkak , menyediakan operasi seperti menambah URL, mendapatkan URL dan menentukan sama ada URL wujud.

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)
}
    Buat pemuat turun halaman web
Pemuat turun halaman web digunakan terutamanya untuk memuat turun kandungan halaman web yang sepadan dengan URL yang ditentukan dan mengembalikannya.

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
}
    Buat penghurai halaman web
Penghurai halaman web digunakan terutamanya untuk menghuraikan kandungan halaman web yang dimuat turun dan mengekstrak data yang diperlukan. Berikut ialah contoh parser menggunakan goquery sebagai contoh:

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
}
    Cipta storan
Storan digunakan terutamanya untuk menyimpan data yang dihuraikan secara setempat atau dalam pangkalan data . Di sini, ambil pangkalan data MySQL sebagai contoh:

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})
    }
}
    Pengawal Crawler
Pengawal Crawler terutamanya melaksanakan fungsi penjadualan dan penyelarasan perangkak. Proses utama ialah:

    Memulakan pengurus URL, pemuat turun halaman web, penghurai halaman web dan storan
  • Tambahkan URL untuk dirangkak ke baris gilir pengurus URL; >
  • Gelung untuk mendapatkan URL yang hendak dirangkak;
  • Tentukan sama ada URL telah dirangkak, jika ia telah dirangkak, langkau URL
  • Muat turun halaman Web URL yang sepadan;
  • Parsing halaman web dan keluarkan data;
  • Simpan data dalam pangkalan data
  • Tambahkan URL pada senarai URL yang dirangkak.
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)
    }
}
Kod lengkap
3 Ringkasan
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()
}

rangkak golang mempunyai ciri-ciri kesederhanaan, kecekapan dan kebolehskalaan , dan disebabkan kelebihan konkurensi semula jadinya, kelajuan data merangkak boleh dipertingkatkan dengan ketara. Artikel ini memperkenalkan komposisi asas dan kaedah penulisan golang crawler, dengan harapan dapat membantu pembaca juga dialu-alukan untuk mengumpul lebih banyak pengalaman dalam amalan.

Atas ialah kandungan terperinci Komponen asas dan kaedah penulisan golang crawler. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn