一、前提
今天老板要我爬取一个网页table标签中的数据,我用golang中http包发起get请求,返回的body一堆的link标签,href指向js,例如:
<body>
<noscript>
<strong>We're sorry but vms doesn't work properly without JavaScript enabled. Please enable it to continue</strong>
</noscript>
<div id=app></div>
<script src=[static/js/chunk-vendors.d270d1df.js](http://www.xxxxxxxx.cn/static/js/chunk-vendors.d270d1df.js)></script>
<script src=[static/js/app.9c781232.js](http://www.bkhjewelry.cn/static/js/app.9c781232.js)></script>
</body>
即用chrome浏览器右击检查网页源代码的值和检查的值是不一样的。
百度了原因是因为页面中的数据是经过js渲染的。
这个页面如果没有登陆会自动跳转到登陆页面,想说在请求头带上Cookie,但是没有找到这个网页的Cookie(那这是怎么做到的呢,登陆成功之后我也没有在请求头中找到Cookie值,它是怎么判断我是否登陆的呢)
后来百度各种百度,知道了golang的一个库,chromedp,可以模拟浏览器操作。
二、初识Chromedp
三、爬取网页
这里的代码是新版本的Chromedp,网上很多例子都是老版本的,新版本和老版本之间不兼容,我下载的是最新版的Chromedp,百度上很多例子中的方法和库新版本中都没有,最后还是在知乎上找到了一篇可用的文章,感谢那位大佬。
// Command submit is a chromedp example demonstrating how to fill out and
// submit a form.
package main
import (
"context"
"fmt"
"github.com/chromedp/chromedp"
"log"
"strings"
"time"
)
// 定义全局变量,保存网爬取到的网页数据
var htmlContent string
func main() {
// 设置项,具体参照参考1
options := []chromedp.ExecAllocatorOption{
chromedp.Flag("headless", false), // debug使用
chromedp.Flag("blink-settings", "imagesEnabled=false"), // 禁用图片加载
chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
}
options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
// Chrome初始化代码如下:
c, _ := chromedp.NewExecAllocator(context.Background(), options...)
// create context
chromeCtx, cancel := chromedp.NewContext(c, chromedp.WithLogf(log.Printf))
// 执行一个空task, 用提前创建Chrome实例
chromedp.Run(chromeCtx, make([]chromedp.Action, 0, 1)...)
// 给每个页面的爬取设置超时时间
timeoutCtx, cancel := context.WithTimeout(chromeCtx, 30 * time.Second)
defer cancel()
//log.Printf("Chrome visit page %s\n", url)
// run task list
var res string
err := chromedp.Run(timeoutCtx, submit(`http://www.xxxxxxxx.cn/#/userAttention`, `//*[@id="app"]/div/div/form/div[1]/div/div[1]/input`, `wu001`, `//*[@id="app"]/div/div/form/div[2]/div/div[1]/input`,`123456`,&res))
fmt.Println("====res====",res)
log.Printf("got: `%s`", strings.TrimSpace(res))
if err != nil {
log.Fatal("出错了",err)
}
fmt.Println("====res====",res)
log.Printf("got: `%s`", strings.TrimSpace(res))
}
func submit(urlstr, sel, q,sel1,q1 string, res *string) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(urlstr), // 访问指定url
chromedp.WaitVisible(sel), // 等待html中某个元素出现
chromedp.OuterHTML(`document.querySelector("body")`, &htmlContent, chromedp.ByJSPath), // 最后获取到<body>标签里的全部HTML代码保存到htmlContent中
chromedp.SendKeys(sel, q), // 给选中的元素设置值,这里是填充form表单
chromedp.SendKeys(sel1, q1),
chromedp.Click("#app > div > div > form > div.login-btn > button",chromedp.NodeVisible), // 点击选中的元素
}
}
暂时只写到这里。后面的数据解析因为密码被修改所以没法登陆
总结一下:
1、代码中可以有多个chromedp.run()
2、获取指定元素的时候,可以通过浏览器的Copy selector和Copy XPath,但是我在填写表单数据的时候,使用selector不能找到指定元素,但是通过XPath可以找到。这个原因未知。
3、官方示例还是很有用的官方示例,示例稍微改动就可以用,前提是得百度一下看一下别人的示例,稍微了解一下chrome的用法,然后可以通过官方示例找到自己想要的功能,参考着写。
4、我还只懂了皮毛。往后该怎么学习这方面的内容呢,还请大家不吝赐教。
四、参考
参考1:https://zhuanlan.zhihu.com/p/139261122
参考2:https://github.com/chromedp/examples
有疑问加站长微信联系(非本文作者)