前两天一个朋友神神秘秘地跟我说,有个叫“微杏视频”的网站,号称“se资源365天天更新”,问我能不能搞个脚本自动抓一下更新列表,我寻思着这名字听着就不太正经,但架不住他反复念叨,加上我最近正好在琢磨Go语言的网络编程,就想着拿这个练练手,结果一查,好家伙,这网站的结构比我想象的乱多了,不过倒是让我把Go的并发和HTML解析给彻底玩明白了。
别急着写代码,先搞懂Go的“脾气”
你要是直接用net/http去GET那个页面,八成会碰一鼻子灰,这网站反爬做得还挺“灵活”,一会儿要求带Cookie,一会儿又要特定的User-Agent,我用Go写的时候,第一步就是得把http.Client配置得像真人浏览器一样:
client := &http.Client{
Timeout: 10 * time.Second,
}
req, _ := 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/120.0.0.0 Safari/537.36")
req.Header.Set("Referer", "https://www.weixing.com/")
resp, err := client.Do(req)
这块儿有个坑,就是重定向处理,默认情况下Go会自动跟进重定向,但有些页面会给你跳转到一个验证中间页,这时候你得手动判断resp.StatusCode是不是200,不然抓回来就是一坨登录页面的HTML,解析半天啥也拿不到。
解析HTML,别用正则硬刚,除非你想给自己找麻烦
一开始我图省事,想用正则直接抠出视频标题和链接,结果那个页面结构啊,一层套一层,div里面套span,span里面又套a标签,正则写到后来自己都看吐了,后来换成了goquery,这玩意儿简直像是为Go定制的jQuery,选择器一写就明白:

doc, err := goquery.NewDocumentFromReader(resp.Body)
doc.Find(".video-item").Each(func(i int, s *goquery.Selection) {:= s.Find("h2 a").Text()
link, _ := s.Find("h2 a").Attr("href")
updateTime := s.Find(".update-time").Text()
fmt.Printf("第%d条: %s | 更新:%s | %s\n", i+1, title, updateTime, link)
})
这里要注意的是,选择器一定要先用手头的浏览器F12看一眼,别上来就猜类名,我那天看到.video-item这个class,以为就是视频卡片,实际打开一看是两个不同的类名。
365天天更新?那我们就用并发去跑
“365天天更新”这个宣传语,其实就是说它每天都发新资源,如果我们要抓历史数据,就得一页一页翻,单线程跑太慢了,Go的goroutine这时候就派上用场了:
var wg sync.WaitGroup
pageChan := make(chan int, 5) // 控制并发数,别一下把人家服务器打挂了
for i := 1; i <= 50; i++ {
wg.Add(1)
pageChan <- i
go func(page int) {
defer wg.Done()
defer func() { <-pageChan }()
fetchPage(fmt.Sprintf("https://www.weixing.com/list-%d.html", page))
}(i)
}
wg.Wait()
这个并发模型看着简单,但有个隐藏问题:如果某页请求失败了,你可能就漏掉那一整天的资源了,所以我加了个简单的重试机制,失败三次就跳过,并且记录日志,回头再手动补齐。
人家更新,你存储——表结构别设计得太死
抓下来的数据你得存吧,一开始我用的SQLite,字段就title、link、update_date三个,后来发现同一个链接可能对应多个画质版本,我那个link字段存一个就丢了另一个,后来改成把整个解析到的信息塞进一个JSON字段里,虽然看着不正经,但实际用起来巨灵活:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | INTEGER | 主键自增 |
| raw_data | TEXT | 原始解析结果,JSON格式 |
| fetched_at | DATETIME | 抓取时间戳 |
| status | INTEGER | 0待处理,1已发布 |
那段时间我天天盯着这个表,发现它至少一天能更新出七八十条新条目,“365天天更新”这个口号倒也不是吹的,不过就是每条标题都带一堆乱码字符,还得用strings.ReplaceAll做清洗。
分享一个“边写边发现”的奇葩Bug
写爬虫的时候我犯了个低级错误,就是没注意页面编码,那个网站居然是GBK编码的,Go的默认http.DecodeReader是认UTF-8的,结果抓下来的中文全变成了“���”,后来我用golang.org/x/text/encoding/simplifiedchinese库做了个转换:
reader := transform.NewReader(resp.Body, simplifiedchinese.GBK.NewDecoder()) doc, err := goquery.NewDocumentFromReader(reader)
这一行代码改完之后,世界清净了,真的,我说这个点,是真心建议你以后抓国内站点,第一件事就是看Content-Type里的charset,别偷懒。
说点掏心窝子的
写了这么多,其实也是在记录我折腾两天遇到的各种小坑,你以为“微杏视频se资源365天天更新”这种站,内容有多丰富,其实扒下来一看,大部分都是重复的封面图、标题党文案,真正有信息量的就那几行更新列表,用Go写爬虫这件事,技术难度不在写代码本身,而在于容错设计——服务器随时可能断连、HTML结构随时可能改、编码随时可能坑你。
好了,我这Go代码还留着,但那个朋友后来也没再问我要结果,可能他自己都忘了这茬,不过无所谓了,至少现在再让我去抓任何奇怪网站,我心里都有底了,你们要是也想拿Go试试手,别一开始就奔着“资源”去,找个自己感兴趣的博客或新闻站练练,效果一样。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://hljbesthome.com/jiankang/2128.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Go语言写个爬虫,把微杏视频的每日更新目录扒下来?这事儿我试过》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:前两天一个朋友神神秘秘地跟我说,有个叫“微杏视频”的网站,号称“se资源365天天更新”,问我能不能搞个脚本自动抓一下更新列表,我寻思着...