随着互联网的普及与信息化的加速发展,越来越多的数据被存放在互联网上,因此网络爬虫已经成为许多人不可或缺的工具。其中,golang爬虫由于其简洁、高效和可扩展性,成为了许多程序员首选的爬虫编写语言。
本文将介绍golang爬虫的基本组成部分和编写方法。
一、golang爬虫的基本组成部分
URL管理器主要负责管理需要爬取的URL队列,以及去重等相关操作。其主要包含以下功能:
网页下载器主要负责将URL对应的网页下载到本地。它可以根据URL的不同特点,采用不同的下载方式,如HTTP、HTTPS、FTP等。在golang中,可通过使用第三方库,如net/http来进行网页下载。
立即学习“go语言免费学习笔记(深入)”;
网页解析器主要负责对下载下来的网页进行解析,获取需要的数据并保存。golang中,可通过正则表达式、html5解析器、goquery等方法进行网页解析。
存储器主要负责将已经解析下来的数据进行存储,一般有数据库存储和本地文件存储两种方式。golang中可以使用第三方库如GORM、orm等进行数据存储。
二、golang爬虫的编写方法
URL管理器主要用来管理待爬取/已爬取的URL,提供添加URL、获取URL、判断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)
}网页下载器主要用来下载指定的URL对应的网页内容,并将其返回。
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
}网页解析器主要用来解析下载下来的网页内容,并提取需要的数据。下面是以goquery为例的解析器示例:
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
}存储器主要用来将解析后的数据存储到本地或数据库中,此处以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})
}
}爬虫控制器主要实现爬虫的调度与协调功能。其主要流程为:
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()
}三、总结
golang爬虫具有简洁、高效和可扩展性的特点,并且由于其天然的并发优势,可以大大提高爬取数据速度。本文通过介绍golang爬虫的基本组成和编写方法,希望能够对读者有所帮助,也欢迎读者们在实践中积累更多的经验。
以上就是golang爬虫的基本组成部分和编写方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号