php可以抓取网页数据吗(简化HTTP请求、数据抽取、收集的视频数据应用)
优采云 发布时间: 2021-10-11 14:17php可以抓取网页数据吗(简化HTTP请求、数据抽取、收集的视频数据应用)
就像 Python 有 Scrapy 库一样,爬虫框架可以大大简化 HTTP 请求、数据提取和采集的过程,同时也提供了更多的工具来帮助我们实现更复杂的功能。
Golang爬虫框架-Goribot
是一个用Golang编写的轻量级爬虫框架,具有良好的扩展性和分布式支持能力,文档齐全。
获取 Goribot:
go get -u github.com/zhshch2002/goribot
使用Goribot实现上述代码的功能看起来简洁多了。
package main
import (
"fmt"
"github.com/zhshch2002/goribot"
)
func main() {
s := goribot.NewSpider()
s.AddTask(
goribot.GetReq("https://github.com"),
func(ctx *goribot.Context) {
fmt.Println(ctx.Resp.Text)
},
)
s.Run()
}
这样就实现了一个功能,就是访问“”并打印出结果。此类应用程序不足以使用框架。那么让我们从一个更复杂的爬虫应用程序开始。
使用Goribot爬取B站信息
下面我们来构建一个更复杂的爬虫应用,预计实现两个功能:
沿链接自动发现新的视频链接,提取标题、封面图、作者、视频数据(播放量、币种、采集夹等)研究B站页面
首先我们来研究一下B站的视频页面,比如按F12打开调试界面,切换到网络选项卡。
我们可以看到这个页面涉及的所有请求和资源。在调试界面选择XHR选项查看Ajax请求。
您可以点击不同的请求,在右侧的弹出面板中查看具体内容。单击新面板中的预览以查看服务器响应的内容。
所以,给你一个任务,依次查看XHR下的所有请求,找出服务器返回的点赞、采集、播放数据中最喜欢哪一个。
很好,看看你找到了吗?
您已经成功实现了爬虫工程师从 Ajax 请求中寻找目标数据的成就。
然后我们切换到Header选项来看看这个请求对应的参数。最好找到这个响应和视频 ID 之间的关系。
找到视频 Id-BV 编号。
我们解决了核心问题,得到了B站的视频数据。对于自动搜索视频,我们可以设置一个起始链接,然后搜索标签来扩展抓取。
构建爬虫
完整的代码在下面的文本中。
创建爬虫
s := goribot.NewSpider( // 创建一个爬虫并注册扩展
goribot.Limiter(true, &goribot.LimitRule{ // 添加一个限制器,限制白名单域名和请求速录限制
Glob: "*.bilibili.com", // 以防对服务器造成过大压力以及被B站服务器封禁
Rate: 2,
}),
goribot.RefererFiller(), // 自动填写Referer,参见Goribot(https://imagician.net/goribot/)关于扩展的部分
goribot.RandomUserAgent(), // 随机UA
goribot.SetDepthFirst(true), // 使用深度优先策略,就是沿着一个页面,然后去子页面而非同级页面
)
获取视频数据
var getVideoInfo = func(ctx *goribot.Context) {
res := map[string]interface{}{
"bvid": ctx.Resp.Json("data.bvid").String(),
"title": ctx.Resp.Json("data.title").String(),
"des": ctx.Resp.Json("data.des").String(),
"pic": ctx.Resp.Json("data.pic").String(), // 封面图
"tname": ctx.Resp.Json("data.tname").String(), // 分类名
"owner": map[string]interface{}{ //视频作者
"name": ctx.Resp.Json("data.owner.name").String(),
"mid": ctx.Resp.Json("data.owner.mid").String(),
"face": ctx.Resp.Json("data.owner.face").String(), // 头像
},
"ctime": ctx.Resp.Json("data.ctime").String(), // 创建时间
"pubdate": ctx.Resp.Json("data.pubdate").String(), // 发布时间
"stat": map[string]interface{}{ // 视频数据
"view": ctx.Resp.Json("data.stat.view").Int(),
"danmaku": ctx.Resp.Json("data.stat.danmaku").Int(),
"reply": ctx.Resp.Json("data.stat.reply").Int(),
"favorite": ctx.Resp.Json("data.stat.favorite").Int(),
"coin": ctx.Resp.Json("data.stat.coin").Int(),
"share": ctx.Resp.Json("data.stat.share").Int(),
"like": ctx.Resp.Json("data.stat.like").Int(),
"dislike": ctx.Resp.Json("data.stat.dislike").Int(),
},
}
ctx.AddItem(res) // 保存到蜘蛛的Item处理队列
}
这是一个自动解析响应中的Json数据的函数,也就是刚才看到的Ajax结果。解析完数据后,保存到spider的Item处理队列中。
发现新视频
var findVideo goribot.CtxHandlerFun
findVideo = func(ctx *goribot.Context) {
u := ctx.Req.URL.String()
fmt.Println(u)
if strings.HasPrefix(u, "https://www.bilibili.com/video/") { // 判断是否为视频页面
if strings.Contains(u, "?") {
u = u[:strings.Index(u, "?")]
}
u = u[31:] // 截取视频中的BV号
fmt.Println(u)
// 创建一个从BV号获取具体数据的任务,使用上一个策略
ctx.AddTask(goribot.GetReq("https://api.bilibili.com/x/web-interface/view?bvid="+u), getVideoInfo)
}
ctx.Resp.Dom.Find("a[href]").Each(func(i int, sel *goquery.Selection) {
if h, ok := sel.Attr("href"); ok {
ctx.AddTask(goribot.GetReq(h), findVideo) // 用同样的策略处理子页面
}
})
}
采集物品
我们在获取视频数据的过程中获取了Ajax数据,并保存到Item队列中。我们在这里处理这些项目是为了避免通过读写文件和数据库来阻塞抓取的主线程。
s.OnItem(func(i interface{}) interface{} {
fmt.Println(i) // 我们暂时不做处理,就先打印出来
return i
})
OnItem的具体使用可以参考Goribot文档的相关内容。
最后,让我们运行
// *敏*感*词*任务
s.AddTask(goribot.GetReq("https://www.bilibili.com/video/BV1at411a7RS"), findVideo)
s.Run()
完整代码如下
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"github.com/zhshch2002/goribot"
"strings"
)
func main() {
s := goribot.NewSpider(
goribot.Limiter(true, &goribot.LimitRule{
Glob: "*.bilibili.com",
Rate: 2,
}),
goribot.RefererFiller(),
goribot.RandomUserAgent(),
goribot.SetDepthFirst(true),
)
var getVideoInfo = func(ctx *goribot.Context) {
res := map[string]interface{}{
"bvid": ctx.Resp.Json("data.bvid").String(),
"title": ctx.Resp.Json("data.title").String(),
"des": ctx.Resp.Json("data.des").String(),
"pic": ctx.Resp.Json("data.pic").String(), // 封面图
"tname": ctx.Resp.Json("data.tname").String(), // 分类名
"owner": map[string]interface{}{ //视频作者
"name": ctx.Resp.Json("data.owner.name").String(),
"mid": ctx.Resp.Json("data.owner.mid").String(),
"face": ctx.Resp.Json("data.owner.face").String(), // 头像
},
"ctime": ctx.Resp.Json("data.ctime").String(), // 创建时间
"pubdate": ctx.Resp.Json("data.pubdate").String(), // 发布时间
"stat": map[string]interface{}{ // 视频数据
"view": ctx.Resp.Json("data.stat.view").Int(),
"danmaku": ctx.Resp.Json("data.stat.danmaku").Int(),
"reply": ctx.Resp.Json("data.stat.reply").Int(),
"favorite": ctx.Resp.Json("data.stat.favorite").Int(),
"coin": ctx.Resp.Json("data.stat.coin").Int(),
"share": ctx.Resp.Json("data.stat.share").Int(),
"like": ctx.Resp.Json("data.stat.like").Int(),
"dislike": ctx.Resp.Json("data.stat.dislike").Int(),
},
}
ctx.AddItem(res)
}
var findVideo goribot.CtxHandlerFun
findVideo = func(ctx *goribot.Context) {
u := ctx.Req.URL.String()
fmt.Println(u)
if strings.HasPrefix(u, "https://www.bilibili.com/video/") {
if strings.Contains(u, "?") {
u = u[:strings.Index(u, "?")]
}
u = u[31:]
fmt.Println(u)
ctx.AddTask(goribot.GetReq("https://api.bilibili.com/x/web-interface/view?bvid="+u), getVideoInfo)
}
ctx.Resp.Dom.Find("a[href]").Each(func(i int, sel *goquery.Selection) {
if h, ok := sel.Attr("href"); ok {
ctx.AddTask(goribot.GetReq(h), findVideo)
}
})
}
s.OnItem(func(i interface{}) interface{} {
fmt.Println(i)
return i
})
s.AddTask(goribot.GetReq("https://www.bilibili.com/video/BV1at411a7RS").SetHeader("cookie", "_uuid=1B9F036F-8652-DCDD-D67E-54603D58A9B904750infoc; buvid3=5D62519D-8AB5-449B-A4CF-72D17C3DFB87155806infoc; sid=9h5nzg2a; LIVE_BUVID=AUTO7815811574205505; CURRENT_FNVAL=16; im_notify_type_403928979=0; rpdid=|(k|~uu|lu||0J'ul)ukk)~kY; _ga=GA1.2.533428114.1584175871; PVID=1; DedeUserID=403928979; DedeUserID__ckMd5=08363945687b3545; SESSDATA=b4f022fe%2C1601298276%2C1cf0c*41; bili_jct=2f00b7d205a97aa2ec1475f93bfcb1a3; bp_t_offset_403928979=375484225910036050"), findVideo)
s.Run()
}
最后
爬虫框架只是一个工具,重要的是人们如何使用它。要了解这些工具,请参阅项目 _examples 和文档。
爬虫
本作品采用《CC协议》,转载须注明作者及本文链接