内网有个网页用了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. Eclipse工具常用快捷键

    Eclipse工具常用快捷键 一丶文件菜单常用快捷键 新建  Alt + shift + N 关闭当前编辑器 Ctrl +W 全部关闭 Ctrl + shift + w 保存  Ctrl + s 刷新 ...

  2. Mybatis源码解析 - mapper代理对象的生成,你有想过吗

    前言 开心一刻 本人幼教老师,冬天戴帽子进教室,被小朋友看到,这时候,有个小家伙对我说:老师你的帽子太丑,赶紧摘了吧.我逗他:那你好好学习,以后给老师买个漂亮的?这孩子想都没想立刻回答:等我赚钱了,带 ...

  3. 脚本检测Kafka和Zookeeper

    Java测试环境中Kafka最近总是自动停止,所有写了一个简单的脚本来监听Kafka和Zookeeper,其中Kafka监听端口为9092,Zookeeper监听端口为2181,脚本如下: #!/bi ...

  4. 利用BGP虚拟下一跳实现链路负载均衡

    最近针对BGP链路负载均衡方案“虚拟下一跳”进行了总结,现将总结的PPT贴上来.

  5. nginx基础

    常见的能够提供web服务的程序有apache.IIS,nginx等,LLS是windows系统中的,nginx和apache是linux系统中的,nginx是一款高性能的http和反向代理的服务器. ...

  6. DSAPI多功能组件编程应用-使用外部字体(包括资源文件)

    在软件开发过程中,尤其是比较个性化的程序,有时会需要使用非安装字体文件,比如发布的时候附带了一个专用字体,或者该字体文件直接被放入项目资源,当不希望把这个字体安装到用户的操作系统但又想使用它时,本示例 ...

  7. Vue在ASP.NET MVC中的进行前后端的交互

    Vue在ASP.NET MVC中的进行前后端的交互 Preface: 由于最近在研究前端相关的技术,作为前端非常优秀的框架Vue,个人在学习的过程中遇到一些问题,网上相关资料有限,所以在这这里总结一下 ...

  8. [Go] golang的接口合约

    接口类型1.接口类型具体描述了一系列方法的集合,实现这些方法的具体类型是这个接口类型的实例2.一个类型如果拥有一个接口需要的所有方法,那么这个类型就实现了这个接口 package main impor ...

  9. PhpStorm 安装ApiDebugger

    ApiDebugger,是一个开源的接口调试IntelliJ IDEA插件,具有与IDEA一致的界面,无需切换程序即可完成网络API请求,让你的code更加沉浸式. 安装 File->Setti ...

  10. Java基础:一个100%会发生死锁的程序

        多线程是Java工程师进阶所必须掌握的一项技能,也是面试中绕不过的一个环节,而死锁又是多线程同步失败的经典案例,对于复杂的系统,死锁是很难通过代码层面来做静态检测和排查的,所以有的面试官会从反 ...