简介
- 模拟账号密码登录
- cookie登录
- 以及字符串cookie登录
- csrf_token 处理
demo
package main
import (
"fmt"
"github.com/gocolly/colly"
"github.com/gocolly/colly/extensions"
"log"
"net/http"
"os"
"strings"
"time"
)
/*
请求执行之前调用
- OnRequest
响应返回之后调用
- OnResponse
监听执行 selector
- OnHTML
监听执行 selector
- OnXML
错误回调
- OnError
完成抓取后执行,完成所有工作后执行
- OnScraped
取消监听,参数为 selector 字符串
- OnHTMLDetach
取消监听,参数为 selector 字符串
- OnXMLDetach
*/
// 声明结构类型
type Session struct {
session *colly.Collector
file *os.File
}
// 初始化
func (c *Session) Init() *colly.Collector {
// 实例化默认收集器
c.session = colly.NewCollector()
// 仅访问域
c.session.AllowedDomains = []string{"quotes.toscrape.com"}
// 允许重复访问
c.session.AllowURLRevisit = true
// 表示抓取时异步的
// c.session.Async = true
// 模拟浏览器
c.session.UserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36"
// 随机UserAgent
extensions.RandomUserAgent(c.session)
// 限制采集规则
/*
在Colly里面非常方便控制并发度,只抓取符合某个(些)规则的URLS
colly.LimitRule{DomainGlob: "*.douban.*", Parallelism: 5},表示限制只抓取域名是douban(域名后缀和二级域名不限制)的地址,当然还支持正则匹配某些符合的 URLS
Limit方法中也限制了并发是5。为什么要控制并发度呢?因为抓取的瓶颈往往来自对方网站的抓取频率的限制,如果在一段时间内达到某个抓取频率很容易被封,所以我们要控制抓取的频率。
另外为了不给对方网站带来额外的压力和资源消耗,也应该控制你的抓取机制。
*/
err := c.session.Limit(&colly.LimitRule{
// Filter domains affected by this rule
// 筛选受此规则影响的域
DomainGlob: "quotes.toscrape.com/*",
// Set a delay between requests to these domains
// 设置对这些域的请求之间的延迟
Delay: 1 * time.Second,
// Add an additional random delay
// 添加额外的随机延迟
RandomDelay: 1 * time.Second,
// 设置并发
Parallelism: 5,
})
if err != nil {
fmt.Println(err)
}
return c.session
}
// 设置 headers
func (c *Session) setHeaders() {
header := map[string]string{
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Connection": "keep-alive",
"Host": "quotes.toscrape.com",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
}
// 在提出请求之前打印 "访问…"
c.session.OnRequest(func(r *colly.Request) {
// fmt.Println("Visiting: ", r.URL.String())
for key, value := range header {
r.Headers.Add(key, value)
}
})
}
// 获取csrf_token
func (c *Session) getCsrfToken() (string, error) {
url := "http://quotes.toscrape.com/login"
csrfToken := ""
c.session.OnHTML("form input[name=\"csrf_token\"]", func(e *colly.HTMLElement) {
// text
text := e.Attr("value")
csrfToken = text
// fmt.Println("csrfToken: ", csrfToken)
})
// fmt.Println("csrfToken: ", csrfToken)
// 收到响应后
// c.session.OnResponse(func(r *colly.Response) {
// if r.StatusCode != 200 {
// fmt.Println("访问失败: ", url)
// return
// }
// fmt.Println(string(r.Body))
// })
err2 := c.session.Visit(url)
if err2 != nil {
fmt.Println(err2)
return "", err2
}
return csrfToken, nil
}
// 登录
func (c *Session) login(csrfToken string) {
// 访问地址
url := "http://quotes.toscrape.com/login"
// 认证
err := c.session.Post(url, map[string]string{
"username": "qqq",
"password": "qqq",
"csrf_token": csrfToken,
})
if err != nil {
log.Fatal(err)
}
// 收到响应后
c.session.OnResponse(func(r *colly.Response) {
if r.StatusCode != 200 {
fmt.Println("访问失败: ", url)
}
// fmt.Println(r.StatusCode)
// fmt.Println(r.Headers.Get("Custom-Header"))
})
// 开始爬取 url
err2 := c.session.Visit(url)
if err2 != nil {
fmt.Println(err2)
}
}
// cookie 登录
func (c *Session) cookieLogin() {
url := "http://quotes.toscrape.com/"
// 获取cookies
// fmt.Println(c.session.Cookies(url))
// 在提出请求之前打印 "访问…"
c.session.OnRequest(func(r *colly.Request) {
// 可以添加多个cookie
cookies := []*http.Cookie{
{
Name: "session",
Value: "eyJjc3JmX3Rva2VuIjoiR3doU0FqTG5RV3pkTkp2RE1vS1lCZmdPeFJ0VFZGaVVFQ2xYYmtadW1yYVBzeXFwY2VISSIsInVzZXJuYW1lIjoicXFxIn0.EmH1iA.wk6GNffYi6R2vaBhZPLYLBZfwpY",
},
}
err := c.session.SetCookies(url, cookies)
if err != nil {
fmt.Println(err)
}
})
}
// cookie 登录2
func (c *Session) cookieLogin2() {
url := "http://quotes.toscrape.com/"
// 获取cookies
// fmt.Println(c.session.Cookies(url))
// 在提出请求之前打印 "访问…"
c.session.OnRequest(func(r *colly.Request) {
cookie := "session=eyJjc3JmX3Rva2VuIjoiR3doU0FqTG5RV3pkTkp2RE1vS1lCZmdPeFJ0VFZGaVVFQ2xYYmtadW1yYVBzeXFwY2VISSIsInVzZXJuYW1lIjoicXFxIn0.EmHo_w.pMG9x7Vdwd2INAw1O25NLw6saRk"
err := c.session.SetCookies(url, setCookieRaw(cookie))
if err != nil {
fmt.Println(err)
}
})
}
// set cookies raw
func setCookieRaw(cookieRaw string) []*http.Cookie {
// 可以添加多个cookie
var cookies []*http.Cookie
cookieList := strings.Split(cookieRaw, "; ")
for _, item := range cookieList {
keyValue := strings.Split(item, "=")
// fmt.Println(keyValue)
name := keyValue[0]
valueList := keyValue[1:]
cookieItem := http.Cookie{
Name: name,
Value: strings.Join(valueList, "="),
}
cookies = append(cookies, &cookieItem)
}
return cookies
}
// 首页验证
func (c *Session) getIndex() {
url := "http://quotes.toscrape.com/"
c.session.OnHTML(".row.header-box .col-md-4 p a", func(e *colly.HTMLElement) {
// text
text := e.Text
fmt.Println("Logout flag: ", text)
})
// 收到响应后
c.session.OnResponse(func(r *colly.Response) {
if r.StatusCode != 200 {
fmt.Println("访问失败: ", url)
}
// fmt.Println(string(r.Body))
// fmt.Println(r.StatusCode)
// fmt.Println(r.Headers.Get("Custom-Header"))
})
err2 := c.session.Visit(url)
if err2 != nil {
fmt.Println(err2)
}
}
func main() {
s := &Session{}
// 初始化
s.Init()
// 设置 headers
s.setHeaders()
// 获取 csrfToken
// csrfToken, err1 := s.getCsrfToken()
// if err1 != nil {
// return
// }
// fmt.Println("csrf_token: ", csrfToken)
// 登录1
// s.login(csrfToken)
// cookie 登录2
// s.cookieLogin()
// cookie 登录3
s.cookieLogin2()
// 首页验证
s.getIndex()
// 采集等待结束
s.session.Wait()
fmt.Println("程序运行结束!")
}
/*
URL already visited
// 允许重复访问
c.session.AllowURLRevisit = true
*/