记一次Go定向爬虫
原始需求
原始需求:https://m.999xs.com/files/article/html/69/69208/index.html
在线看不方便,而且浏览器还有强制广告
ps: 在实战过程中,对m.999xs.com造成了非正常的访问,由此带来的服务端压力和问题在此说声Sorry。
分析
打开链接,我们发现一本被分成了很多章节,在菜单目录中20章节为一页。
每一章节又被分为多个子页。
分级关系描述如下:
page1,page2…->Chapter
Chapter1,Chapter2…(<=20)->Directory
Directory1,Directory2…->Book
实战
非常自然的,我们自顶向下的设计思路有出来了。
Workers
定义一个workers目录,按照分析过程中的层级关系,添加如下4个worker
BookerWorker
package workers
import (
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strings"
)
/*
Booker
职责:
1. 获取Title,书名即最终的文本文件名
2. 初始化 DirectoryWorker
3. 接收最终 DirectoryWorker 和 PageWorker 解析出来的内容,并生成文本文件
*/
/*
BookWorker.Contents的描述
[]byte ========>Chapter ========>每章中的内容,每个章节包含多页,在章节中合并,章节=章节名+页1+页2+...
[][]byte ========>Directory ========>每个菜单目录,[章节1,章节2...]
[][][]byte ========>Book ========>整本书,[目录1,目录2...]
*/
type BookWorker struct {
DefaultUrl string //初始url,https://m.999xs.com/files/article/html/69/69208/index.html
Contents [][][]byte //index页面获取到的html流,
FileName string //书名
PageContentChan chan PageContentItem //接收处理的Page结果
Host string
}
type PageContentItem struct {
Content []byte
PageNum int
SubPageNum int
}
func (b *BookWorker) Run() error {
defer log.Println("booker worker down")
//initial Receiver
downchan := make(chan int)
go b.ReceiveContents(downchan)
resp, err := http.DefaultClient.Get(b.Host + b.DefaultUrl)
if err != nil {
return err
}
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
b.getTitle(buf)
err = b.StartDirectoryWorker(buf, b.DefaultUrl)
if err != nil {
return err
}
close(b.PageContentChan)
<-downchan
return nil
}
func (b *BookWorker) getTitle(contents []byte) {
//处理BookTitle
titlepat := `id="