内网有个网页用了HTTP基本认证机制,想用gocolly爬取,不知道怎么登录,只好研究HTTP基本认证机制

参考这里:https://www.jb51.net/article/89070.htm

下面开始参考作者dotcoo了:-)

看了<<http权威指南>>第12章HTTP基本认证机制(本站下载地址://www.jb51.net/books/93254.html),感觉讲的蛮详细的,写了一个小小例子测试.

请求响应过程:

==>
GET /hello HTTP/1.1
Host: 127.0.0.1:
<==
HTTP/1.1 Unauthorized
WWW-Authenticate: Basic realm="Dotcoo User Login"
==>
GET /hello HTTP/1.1
Host: 127.0.0.1:
Authorization: Basic YWRtaW46YWRtaW5wd2Q=
<==
HTTP/1.1 OK
Content-Type: text/plain; charset=utf-

golang HTTP基本认证机制的实现代码

package main
import (
"fmt"
"io"
"net/http"
"log"
"encoding/base64"
"strings"
)
// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
auth := req.Header.Get("Authorization")
if auth == "" {
w.Header().Set("WWW-Authenticate", `Basic realm="Dotcoo User Login"`)
w.WriteHeader(http.StatusUnauthorized)
return
}
fmt.Println(auth)
auths := strings.SplitN(auth, " ", )
if len(auths) != {
fmt.Println("error")
return
}
authMethod := auths[]
authB64 := auths[]
switch authMethod {
case "Basic":
authstr, err := base64.StdEncoding.DecodeString(authB64)
if err != nil {
fmt.Println(err)
io.WriteString(w, "Unauthorized!\n")
return
}
fmt.Println(string(authstr))
userPwd := strings.SplitN(string(authstr), ":", )
if len(userPwd) != {
fmt.Println("error")
return
}
username := userPwd[]
password := userPwd[]
fmt.Println("Username:", username)
fmt.Println("Password:", password)
fmt.Println()
default:
fmt.Println("error")
return
}
io.WriteString(w, "hello, world!\n")
}
func main() {
http.HandleFunc("/hello", HelloServer)
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

试验了上面的例子后,基本明白了HTTP基本认证的过程。但是怎么用gocolly访问呢?

参考:https://stackoverflow.com/questions/50576248/using-colly-framework-i-cant-login-to-the-evernote-account

但是答复者Matías Insaurralde提供的模拟浏览器访问的例子编译不通过,不明白其中的hptsKey的意思。代码放在下面供参考(可跳过):

package evernote

import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
) const (
evernoteLoginURL = "https://www.evernote.com/Login.action"
) var (
evernoteJSParamsExpr = regexp.MustCompile(`document.getElementById\("(.*)"\).value = "(.*)"`)
evernoteRedirectExpr = regexp.MustCompile(`Redirecting to <a href="(.*)">`) errNoMatches = errors.New("No matches")
errRedirectURL = errors.New("Redirect URL not found")
) // EvernoteClient wraps all methods required to interact with the website.
type EvernoteClient struct {
Username string
Password string
httpClient *http.Client // These parameters persist during the login process:
hpts string
hptsh string
} // NewEvernoteClient initializes a new Evernote client.
func NewEvernoteClient(username, password string) *EvernoteClient {
// Allocate a new cookie jar to mimic the browser behavior:
cookieJar, _ := cookiejar.New(nil) // Fill up basic data:
c := &EvernoteClient{
Username: username,
Password: password,
} // When initializing the http.Client, copy default values from http.DefaultClient
// Pass a pointer to the cookie jar that was created earlier:
c.httpClient = &http.Client{
Transport: http.DefaultTransport,
CheckRedirect: http.DefaultClient.CheckRedirect,
Jar: cookieJar,
Timeout: http.DefaultClient.Timeout,
}
return c
} func (e *EvernoteClient) extractJSParams(body []byte) (err error) {
matches := evernoteJSParamsExpr.FindAllSubmatch(body, -)
if len(matches) == {
return errNoMatches
}
for _, submatches := range matches {
if len(submatches) < {
err = errNoMatches
break
}
key := submatches[]
val := submatches[] if bytes.Compare(key, hptsKey) == {
e.hpts = string(val)
}
if bytes.Compare(key, hptshKey) == {
e.hptsh = string(val)
}
}
return nil
} // Login handles the login action.
func (e *EvernoteClient) Login() error {
// First step: fetch the login page as a browser visitor would do:
res, err := e.httpClient.Get(evernoteLoginURL)
if err != nil {
return err
}
if res.Body == nil {
return errors.New("No response body")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
err = e.extractJSParams(body)
if err != nil {
return err
} // Second step: we have extracted the "hpts" and "hptsh" parameters
// We send a request using only the username and setting "evaluateUsername":
values := &url.Values{}
values.Set("username", e.Username)
values.Set("evaluateUsername", "")
values.Set("analyticsLoginOrigin", "login_action")
values.Set("clipperFlow", "false")
values.Set("showSwitchService", "true")
values.Set("hpts", e.hpts)
values.Set("hptsh", e.hptsh) rawValues := values.Encode()
req, err := http.NewRequest(http.MethodPost, evernoteLoginURL, bytes.NewBufferString(rawValues))
if err != nil {
return err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("x-requested-with", "XMLHttpRequest")
req.Header.Set("referer", evernoteLoginURL)
res, err = e.httpClient.Do(req)
if err != nil {
return err
}
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return err
}
bodyStr := string(body)
if !strings.Contains(bodyStr, `"usePasswordAuth":true`) {
return errors.New("Password auth not enabled")
} // Third step: do the final request, append password to form data:
values.Del("evaluateUsername")
values.Set("password", e.Password)
values.Set("login", "Sign in") rawValues = values.Encode()
req, err = http.NewRequest(http.MethodPost, evernoteLoginURL, bytes.NewBufferString(rawValues))
if err != nil {
return err
}
req.Header.Set("Accept", "text/html")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("x-requested-with", "XMLHttpRequest")
req.Header.Set("referer", evernoteLoginURL)
res, err = e.httpClient.Do(req)
if err != nil {
return err
} // Check the body in order to find the redirect URL:
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return err
}
bodyStr = string(body)
matches := evernoteRedirectExpr.FindAllStringSubmatch(bodyStr, -)
if len(matches) == {
return errRedirectURL
}
m := matches[]
if len(m) < {
return errRedirectURL
}
redirectURL := m[]
fmt.Println("Login is ok, redirect URL:", redirectURL)
return nil
}
After you successfully get the redirect URL, you should be able to send authenticated requests as long as you keep using the HTTP client that was used for the login process, the cookie jar plays a very important role here. To call this code use: func main() {
evernoteClient := NewEvernoteClient("user@company", "password")
err := evernoteClient.Login()
if err != nil {
panic(err)
}
}

只好自己写,经反复试验,发现对于本文开头自己写的server,只需以下代码即可通过验证,输出了hello,world!(将访问方式改为POST也一样。)

package main

import (
"fmt" "io/ioutil"
"net/http"
) // Login handles the login action.
func Login() {
//生成client 参数为默认
client := &http.Client{}
//要访问的url
url := "http://localhost:8000/hello"
//要提交的请求
req, _ := http.NewRequest("GET", url, nil)
//最重要的一句,用户名和密码可随意写
req.SetBasicAuth("aa", "bb")
fmt.Println("POST访问")
//返回结果
res, _ := client.Do(req)
defer res.Body.Close()
fmt.Println("header:")
header := res.Header
fmt.Println(header)
fmt.Println("realm:")
basicRealm := res.Header.Get("Www-Authenticate")
fmt.Println(basicRealm)
fmt.Println("body:")
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(body)) } func main() {
Login()
}

查看SetBasicAuth的定义为(liteide中在光标位置按Ctrl+shift+J):

func (r *Request) SetBasicAuth(username, password string) {
r.Header.Set("Authorization", "Basic "+basicAuth(username, password))
}

而basicAuth的定义为

func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}

那么,用gocolly访问的代码如下:

package main

import (
"encoding/base64"
"fmt"
"net/http" "github.com/gocolly/colly"
) func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}
func main() {
c := colly.NewCollector()
h := http.Header{}
h.Set("Authorization", "Basic "+basicAuth("aaaa", "bbbb")) c.OnResponse(func(r *colly.Response) {
//fmt.Println(r)
fmt.Println(string(r.Body))
}) c.Request("GET", "http://localhost:8000/hello", nil, nil, h)
}

注:对于其他网站,也许要用Fiddler抓包,设置相应的header和cookie才行。

(golang)HTTP基本认证机制及使用gocolly登录爬取的更多相关文章

  1. Golang+chromedp+goquery 简单爬取动态数据

    目录 Golang+chromedp+goquery 简单爬取动态数据 Golang的安装 下载golang软件 解压golang 配置golang 重新导入配置 chromedp框架的使用 实际的代 ...

  2. Atitit HTTP 认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结

    Atitit HTTP认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结 1.1. 最广泛使用的是基本验证 ( ...

  3. WPS 认证机制

    WPS 认证机制 WPS(Wi-Fi Protected Setup,Wi-Fi保护设置)(有的叫做AOSS.有的叫做QSS,不过功能都一致.)是由Wi-Fi联盟组织实施的认证项目,主要致力于简化无线 ...

  4. 基于Token的WEB后台认证机制

    几种常用的认证机制 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RES ...

  5. HTTP中的摘要认证机制

    引子: 指定和服务器端交互的HTTP方法,URL地址,即其他请求信息: Method:表示http请求方法,一般使用"GET","POST". url:表示请求 ...

  6. USB Type-C 应用面临安全性考验,USB-IF 将推动新认证机制

    USB 应用已经达到空前盛况,横跨电脑.移动设备.周边设备.影音器材等范畴,是一个极为普遍常见的界面.进入 USB Type-C 世代由于一并推动 USB-PD,过去没有严格执行的认证要求,基于安全性 ...

  7. 一个NB的安全认证机制

    这是一个NB的安全认证机制. 1.这是一个安全认证机制 2.可以防止黑客截获到客户端发送的请求消息,避免了黑客冒充客户端向服务器发送操作的请求. 原理与步骤: 1.客户端与服务器端都会放着一份验证用的 ...

  8. 【pac4j】OAuth 认证机制 入门篇

    1,pac4j是什么? pac4j是一个支持多种支持多种协议的身份认证的Java客户端. 2,pac4j的12种客户端认证机制:目前我只有用过第一和第八种. OAuth (1.0 & 2.0) ...

  9. web安全认证机制知多少

    如今web服务随处可见,成千上万的web程序被部署到公网上供用户访问,有些系统只针对指定用户开放,属于安全级别较高的web应用,他们需要有一种认证机制以保护系统资源的安全,本文将探讨五种常用的认证机制 ...

随机推荐

  1. SpringBoot入门教程(五)Java基于MySQL实现附近的人

    “附近的人”这个功能估计都不陌生,与之类似的功能最开始是在各大地图应用上接触过,比如搜附近的电影院,附近的超市等等.然而真正让附近的人火遍大江南北的应该是微信"附近的人"这个功能, ...

  2. Docker最全教程——从理论到实战(六)

    托管到腾讯云容器服务 托管到腾讯云容器服务,我们的公众号“magiccodes”已经发布了相关的录屏教程,大家可以结合本篇教程一起查阅.   自建还是托管? 在开始之前,我们先来讨论一个问题——是自建 ...

  3. windows powershell一些操作

  4. iOS 循环引用讲解(中)

    谈到循环引用,可能是delegate为啥非得用weak修饰,可能是block为啥要被特殊对待,你也可能仅仅想到了一个weakSelf,因为它能解决99%的关于循环引用的事情.下面我以个人的理解谈谈循环 ...

  5. 第30章 部署 - Identity Server 4 中文文档(v1.0.0)

    您的身份服务器只是一个标准的ASP.NET Core应用程序,包括IdentityServer中间件.首先阅读有关发布和部署的官方Microsoft 文档(尤其是有关负载平衡器和代理的部分). 30. ...

  6. 杭电ACM2015--偶数求和

    偶数求和 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  7. demo_3

    ## 控制器层 需求分析: 访问路径:`/user/reg.do`请求参数:`username=xx&password=xx&&phone=xx&email=xx`请求 ...

  8. C# List 集合 交集、并集、差集、去重, 对象集合、 对象、引用类型、交并差补、List<T>

    关键词:C#  List 集合 交集.并集.差集.去重, 对象集合. 对象.引用类型.交并差.List<T> 有时候看官网文档是最高效的学习方式! 一.简单集合 Intersect 交集, ...

  9. Java开发笔记(四十)日期与字符串的互相转换

    前面介绍了如何通过Date工具获取各个时间数值,但是用户更喜欢形如“2018-11-24 23:04:18”这种结构清晰.简洁明了的字符串,而非啰里八唆依次汇报每个时间单位及其数值的描述.既然日期时间 ...

  10. Java学习笔记——String与StringBuffer

    String与StringBuffer String.substring(start,end); 范围为[start,end) StringBuffer.delete(start,end) 范围也是为 ...