(golang)HTTP基本认证机制及使用gocolly登录爬取
内网有个网页用了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登录爬取的更多相关文章
- Golang+chromedp+goquery 简单爬取动态数据
目录 Golang+chromedp+goquery 简单爬取动态数据 Golang的安装 下载golang软件 解压golang 配置golang 重新导入配置 chromedp框架的使用 实际的代 ...
- Atitit HTTP 认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结
Atitit HTTP认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结 1.1. 最广泛使用的是基本验证 ( ...
- WPS 认证机制
WPS 认证机制 WPS(Wi-Fi Protected Setup,Wi-Fi保护设置)(有的叫做AOSS.有的叫做QSS,不过功能都一致.)是由Wi-Fi联盟组织实施的认证项目,主要致力于简化无线 ...
- 基于Token的WEB后台认证机制
几种常用的认证机制 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RES ...
- HTTP中的摘要认证机制
引子: 指定和服务器端交互的HTTP方法,URL地址,即其他请求信息: Method:表示http请求方法,一般使用"GET","POST". url:表示请求 ...
- USB Type-C 应用面临安全性考验,USB-IF 将推动新认证机制
USB 应用已经达到空前盛况,横跨电脑.移动设备.周边设备.影音器材等范畴,是一个极为普遍常见的界面.进入 USB Type-C 世代由于一并推动 USB-PD,过去没有严格执行的认证要求,基于安全性 ...
- 一个NB的安全认证机制
这是一个NB的安全认证机制. 1.这是一个安全认证机制 2.可以防止黑客截获到客户端发送的请求消息,避免了黑客冒充客户端向服务器发送操作的请求. 原理与步骤: 1.客户端与服务器端都会放着一份验证用的 ...
- 【pac4j】OAuth 认证机制 入门篇
1,pac4j是什么? pac4j是一个支持多种支持多种协议的身份认证的Java客户端. 2,pac4j的12种客户端认证机制:目前我只有用过第一和第八种. OAuth (1.0 & 2.0) ...
- web安全认证机制知多少
如今web服务随处可见,成千上万的web程序被部署到公网上供用户访问,有些系统只针对指定用户开放,属于安全级别较高的web应用,他们需要有一种认证机制以保护系统资源的安全,本文将探讨五种常用的认证机制 ...
随机推荐
- Lucene 04 - 学习使用Lucene的Field(字段)
目录 1 Field的特性 2 常用的Field类型 3 常用的Field种类使用 3.1 准备环境 3.2 需求分析 3.3 修改代码 3.4 重新建立索引 1 Field的特性 Document( ...
- kubernetes的安装方法
背景 自己学习k8s集群,无奈屌丝一枚,没钱配置vpn服务,安装k8s花费的时间太久了.为了小伙伴们可以快速安装k8s,我花了点时间整理了这篇博客,提供一个不用FQ就可以愉快安装k8s集群的方法. 主 ...
- 老代码多=过度耦合=if else?阿里巴巴工程师这样捋直老代码
简介 在业务开发的过程中,往往存在平台代码和业务代码耦合严重难以分离.业务和业务之间代码交织缺少拆解的现象.平台和业务代码交织导致不易修改,不同业务的代码交织增加了不同负责团队之间的协同成本.因此不论 ...
- Tapestry3.0开发概论
一.TAPESTRY技术的综述. tapestry是平行于struts/Spring MVC/webwork /jsf等开发工具的语言.tapestry是基于组件的开发工具.它具有组件的可重用性.因为 ...
- VS2015安装水晶报表
最近在做一个打印功能,本来是不想用水晶报表的.想直接用微软原生的报表rdlc完成,但是整了一个上午老是打印乱码,且网上找资料找也找不出. 无奈放弃,然后就想到用水晶报表了,以前用过水晶报表,不过一直都 ...
- Lambda表达式资料整理
重温委托,匿名方法,Lambda,泛型委托,表达式树 第一:委托 有些教材,博客说到委托都会提到事件,虽然事件是委托的一个实例,但是为了理解起来更简单,今天只谈委托不谈事件.先上一段代码: 下边的 ...
- 基于C#&.net2.0的windows服务创建与安装
起因:一台服务器中部署的程序,停电后未按照计划任务正常启动. 一.创建并配置Windows服务程序 开发工具VS2015 Framework版本2.0 1.新建Windows服务 2.在Service ...
- Android开发——绘图基础
前言: Android中绘图基本三个类,分别是Paint(画笔),Path(路径),Canvas(画布),这三个也是自定义View经常会使用到的类 个人理解,Canvas画布这个翻译其实不太好,这个类 ...
- Android项目刮刮奖详解(四)
Android项目刮刮奖详解(三) 前言 上一期我们已经是完成了刮刮卡的基本功能,本期就是给我们的项目增加个功能以及美化一番 目标 增加功能 用户刮卡刮到一定程度的时候,清除遮盖层 在遮盖层放张图片, ...
- spring boot 2.0 整合 elasticsearch6.5.3,spring boot 2.0 整合 elasticsearch NoNodeAvailableException
原文地址:spring boot 2.0 整合 elasticsearch NoNodeAvailableException 原文说的有点问题,下面贴出我的配置: 原码云项目地址:https://gi ...