最近群里大伙好像学习欲望挺高,今天博主分享下自己爬虫的一点小技巧,希望能引领大家入门。
大伙可能比较常用python来写爬虫,我之前也用,不过总觉得python的依赖引入有点麻烦,每次得自己写(不知道有没有自动引入的),所以后来就换成go了。
不过go写起来肯定没python方便,毕竟python想要的功能基本都有现成的库,不需要再手撸一个了。
注意:本文仅供自己学习,不要随便爬别人网站,如果造成任何影响皆有使用者自己负责。
爬虫
个人觉得爬虫就是一个机器人,把你要干的活的流程一步步发给它,然后让它按照你的设想来一点点执行。
例如,我想要知道一个网页的标题是什么,那我可以打开浏览器访问到这个网页,然后看到这个标题。两个、三个、甚至是十个网页的话我们可以一个个点击来获取链接,但是成百上千个网址的话我们手点的话肯定要累死,这时候爬虫就派上用场了。
通常一个简单的爬虫只需要下面三步:
获取网页html
解析网页html
获取自己想要的信息
举个最简单的例子,获取百度的标签名也就是Title
res, _ := http.Get("https://www.baidu.com")
defer res.Body.Close()
doc, _ := goquery.NewDocumentFromReader(res.Body)
title := doc.Find("title").First().Text()
println(title)
第一步获取网页html,也就是res, _ := http.Get("https://www.baidu.com")
;第二步解析网页html,这里用开源的goquery来解析,我觉得非常好用,doc, _ := goquery.NewDocumentFromReader(res.Body)
;最后一步就是找到我们想要的信息了,title := doc.Find("title").First().Text()
。
上面就是一个很简单的例子,接下来稍微进阶一手。
进阶
当我们访问某些网站下载资源时,总有些网站为了防止机器人,让你登陆后发表评论才能看到隐藏的下载链接。
这种就需要多处理几步,按照人类的操作方式,让机器也操作一遍就可以了。
直接的http.Get
满足不了上面这个需求,这里介绍另一个开源库——chromdp
,功能更加全面。
这个开源库的使用教程大家可以上网查一下,用的前提是装一个chrom浏览器。就像python的Selenium一样,可能自动化测试用的比较多吧。
这种需要登录才能回复的网站,建议登陆后找到cookie写到程序了,用程序来每次登录的话会影响咱们的爬虫效率。
输入评论
F12打开控制面板,找到评论输入的区域。
可以看到评论输入这个组件有个id
,那这样等会我们找的时候就可以直接通过id来找到它了,部分代码如下。
func getDetail(url string, cookie string, zy *model.Kfzys) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Title(&zy.Title),
chromedp.ScrollIntoView(`#quick_reply_message`),
chromedp.Sleep(1 * time.Second),
chromedp.SetValue(`#message`, `看看`, chromedp.NodeReady),
chromedp.Sleep(1 * time.Second),
chromedp.Submit(`#quick_reply_form`, chromedp.NodeReady),
chromedp.Sleep(1 * time.Second),
chromedp.Navigate(url),
chromedp.Text(`div.alert.alert-success`, &zy.Url, chromedp.NodeVisible),
}
}
这是一个任务流程,大概逻辑就是先获取网页的Title
(这里因为要获取资源名称),然后滚动到网页最下面找到评论组件;chromedp.SetValue("#message", "看看", chromedp.NodeReady)
这个就是把看看
输入到评论区里面;提交评论,chromedp.Submit("#quick_reply_form", chromedp.NodeReady),
;最后刷新页面然后找到资源链接。
这个是爬完后的,网页端有咱们的评论了,并且链接也显示出来了。
程序也获取到了对应链接:
整体代码
最后放一个整体代码,具体爬的网站就不放了,可以自行找个网站试试。
func main() {
initialize.Init()
getZY("https://www.kuafuzys.com/thread-1061.htm")
}
func getZY(url string) {
// 禁用chrome headless
opts := append(chromedp.DefaultExecAllocatorOptions[:]) //chromedp.Flag("headless", false),
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()
ctx, cancel := chromedp.NewContext(
allocCtx,
)
defer cancel()
// create a timeout
ctx, cancel = context.WithTimeout(ctx, 300*time.Second)
defer cancel()
// navigate to a page, wait for an element, click
var cookies []*network.CookieParam
cookie := "你自己cookie"
cookieParams := strings.Split(cookie, ";")
for _, value := range cookieParams {
value = strings.TrimSpace(value)
value = strings.Trim(value, ";")
cookieParam := strings.SplitN(value, "=", 2)
cookies = append(cookies, &network.CookieParam{
Name: cookieParam[0],
Value: cookieParam[1],
})
}
var zy model.Kfzys
var length int
chromedp.Run(ctx, getDetailWithoutReply(url, cookie, &length))
if length == 0 {
chromedp.Run(ctx, getDetail(url, cookie, &zy))
} else {
chromedp.Run(ctx, chromedp.Title(&zy.Title), chromedp.Text(`div.alert.alert-success`, &zy.Url, chromedp.NodeVisible))
}
zy.Title = strings.Split(zy.Title, "-")[0]
println(zy.Title + "----" + zy.Url)
}
func getDetailWithoutReply(url string, cookie string, value *int) chromedp.Tasks {
return chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
// create cookie expiration
expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
// add cookies to chrome
var cookies []string
cookieParams := strings.Split(cookie, ";")
for _, value := range cookieParams {
value = strings.TrimSpace(value)
value = strings.Trim(value, ";")
cookieParam := strings.SplitN(value, "=", 2)
cookies = append(cookies, cookieParam[0])
cookies = append(cookies, cookieParam[1])
}
for i := 0; i < len(cookies); i += 2 {
err := network.SetCookie(cookies[i], cookies[i+1]).
WithExpires(&expr).
WithDomain("www.****.com").
WithHTTPOnly(true).
Do(ctx)
if err != nil {
return err
}
}
return nil
}),
chromedp.Navigate(url),
chromedp.EvaluateAsDevTools(`document.querySelectorAll("div.alert.alert-success").length`, value),
}
}
func getDetail(url string, cookie string, zy *model.Kfzys) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Title(&zy.Title),
chromedp.ScrollIntoView(`#quick_reply_message`),
chromedp.Sleep(1 * time.Second),
chromedp.SetValue(`#message`, `看看`, chromedp.NodeReady),
chromedp.Sleep(1 * time.Second),
chromedp.Submit(`#quick_reply_form`, chromedp.NodeReady),
chromedp.Sleep(1 * time.Second),
chromedp.Navigate(url),
chromedp.Text(`div.alert.alert-success`, &zy.Url, chromedp.NodeVisible),
}
}
闲聊
强烈推一波云边有个小卖铺