模拟浏览器登录操作

GiXuan · 2015-06-13 03:49:12 · 303940 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2015-06-13 03:49:12 的主题,其中的信息可能已经有所发展或是发生改变。

近来想用Go做一点事,以减轻工作上的负担。 我的工作中有几项工作是每日重复的,大致内容:

1、将数据收集到Excel中。
2、收集齐后,将Excel中的部分数据提交到办公系统中(网页上操作)。
3、再将提交过后的审批号码提取出来,存入Excel中。

我现在有两个问题:

1、现在,上面的第一步Excel操作,Go中不知有何现成的库,若没有,我有个效率不高的办法。这个问题倒还不算急。
2、第二个问题比较着急。向办公系统提交数据,得先登录。我的操作步骤如下:
2.1、先访问办公系统首页,获取Session的Cookie。 2.2、进行登录数据提交,将刚才获取的这个Session的Cookie一并提交上去。 2.3、进行业务数据提交。

我现在的问题卡在上面的2.2步了。

测试期间,登录操作完后,我进入业务逻辑提交页面,可系统反馈登陆超时。后抓包中看到:

1、在我登录验证成功后,服务器返回了一个30X状态码。
2、http包直接帮我转入了登录成功后的页面,返回的Body是跳转后的页面代码。我的User-Agent在http帮我跳转时改动了,改为了"Go 1.1 package http"了。

我的登录代码逻辑大概是这样:

import (
    "net/http"
    "log"
)

c := &http.Client{}

// sUrl 是登录验证页面地址
// v中是登录帐号、密码等内容
req, err := http.NewRequest("POST", sUrl, v)

// 将之前文字描述 2.1 步骤中的Session Cookie一并发送到服务端
for _, v := range aCookies {
    req.AddCookie(v)
}

// 一系列Header设置省略
// 其中下面这条是将User-Agent设置为我正常操作办公系统时使用的浏览器的标识
req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)")

// 执行登录操作
res, err := c.Do(req)
if nil != err {
    log.Fatal(err)
}
// 将返回的Cookie保留下来,下次操作使用
aCookies = res.Cookies()

我认为User-Agent的改动是导致我下面一步进入业务逻辑提交页面提示登录超时的原因。不知我的想法是否正确,还有问题如何解决呢?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

303940 次点击  ∙  2 赞  
加入收藏 微博
32 回复  |  直到 2021-10-13 01:39:14
GiXuan
GiXuan · #1 · 10年之前

编辑了半天,代码高亮还是没出来,不知道怎么用。

polaris
polaris · #2 · 10年之前

额,好吧。需要在 ``` 后面加上 go

GiXuan
GiXuan · #3 · 10年之前
polarispolaris #2 回复

额,好吧。需要在 ``` 后面加上 go

原来如此,不会用,谢谢了。

GiXuan
GiXuan · #4 · 10年之前

有哪位朋友做过吗?

ttyige
ttyige · #5 · 9年之前

不错支持一下了..

GiXuan
GiXuan · #6 · 9年之前

主题的内容,下面代码实现了两个功能: 1、始终使用自定义的浏览器标识。 2、每次请求中,发送和接收Cookie。

import (
    "net/http" 
    "net/http/cookiejar"
    "net/url"
)

type MyTransport struct {
    Transport RoundTripper
}

func (t *MyTransport) transport() http.RoundTripper {
    if nil != t.Transport {
        return t.Transport
    }
    return http.DefaultTransport 
}

func (t *MyTransport) RoundTrip(req *http.Request) (http.Response, error) {
    req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)") 
    return t.transport().RoundTrip(req)
}

var c Client

type Client {
    http.Client
}

func NewClient() *Client {
    t := &MyTransport{}
    jar, err := cookiejar.New(nil)
    if nil != err {
        log.Fatal(err)
    }
    return &Client{ Transort: t, Jar: jar }
}

func main() {
    c = NewClient()
    // sUrl 是登录验证页面地址
    sUrl := "http://localhost/login"
    // v中是登录帐号、密码等内容
    v := url.Values{
        "username": "test",
        "password": "test",
    }
     req, err := http.NewRequest("POST", sUrl, v)
    // 执行登录操作
    res, err := c.Do(req) if nil != err {
        log.Fatal(err)
    }
}
GiXuan
GiXuan · #7 · 9年之前
GiXuanGiXuan #6 回复

主题的内容,下面代码实现了两个功能: 1、始终使用自定义的浏览器标识。 2、每次请求中,发送和接收Cookie。 ```go import ( "net/http" "net/http/cookiejar" "net/url" ) type MyTransport struct { Transport RoundTripper } func (t *MyTransport) transport() http.RoundTripper { if nil != t.Transport { return t.Transport } return http.DefaultTransport } func (t *MyTransport) RoundTrip(req *http.Request) (http.Response, error) { req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)") return t.transport().RoundTrip(req) } var c Client type Client { http.Client } func NewClient() *Client { t := &MyTransport{} jar, err := cookiejar.New(nil) if nil != err { log.Fatal(err) } return &Client{ Transort: t, Jar: jar } } func main() { c = NewClient() // sUrl 是登录验证页面地址 sUrl := "http://localhost/login" // v中是登录帐号、密码等内容 v := url.Values{ "username": "test", "password": "test", } req, err := http.NewRequest("POST", sUrl, v) // 执行登录操作 res, err := c.Do(req) if nil != err { log.Fatal(err) } } ```

漏了 import ("log"),记得不上。

GiXuan
GiXuan · #8 · 9年之前

手机打的,有问题。修改了一下,没自己测试,再发一次: 主题的内容,下面代码实现了两个功能: 1、始终使用自定义的浏览器标识。 2、每次请求中,发送和接收Cookie。

import (
    "net/http" 
    "net/http/cookiejar"
    "net/url"
    "log"
)

type MyTransport struct {
    Transport RoundTripper
}

func (t *MyTransport) transport() http.RoundTripper {
    if nil != t.Transport {
        return t.Transport
    }
    return http.DefaultTransport 
}

func (t *MyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)") 
    return t.transport().RoundTrip(req)
}

type Client {
    http.Client
}

var c Client

func NewClient() *Client {
    t := &MyTransport{}
    jar, err := cookiejar.New(nil)
    if nil != err {
        log.Fatal(err)
    }
    return &Client{ Transort: t, Jar: jar }
}

func main() {
    c = NewClient()
    // sUrl 是登录验证页面地址
    sUrl := "http://localhost/login"
    // v中是登录帐号、密码等内容
    v := url.Values{
        "username": "test",
        "password": "test",
    }
     req, err := http.NewRequest("POST", sUrl, v)
    // 执行登录操作
    res, err := c.Do(req)
    if nil != err {
        log.Fatal(err)
    }
}
TheWind
TheWind · #9 · 9年之前

重定向的问题解决了没,最近也在搞类似的一个东西。:smiley:

GiXuan
GiXuan · #10 · 9年之前
TheWindTheWind #9 回复

重定向的问题解决了没,最近也在搞类似的一个东西。:smiley:

func (t *MyTransport) RoundTrip(req *http.Request) (http.Response, error) 上面这个方法解决了浏览器跳转后User-Agent又变回了"Go 1.1 package http"的问题。 顺便推荐一个包,我这两天在开源中国社区看到的,但还没使用,看介绍觉得很方便。你可以看看:http://www.oschina.net/p/go-request

LuYuChengProject
LuYuChengProject · #11 · 8年之前

以前用Java做过模拟登陆,Go没有做过。可能你的登陆请求发出去之后 暂停一下试试。

channel
channel · #12 · 8年之前

这个帖子几乎每天阅读排行榜第一。。。

GiXuan
GiXuan · #13 · 8年之前

以前用Java做过模拟登陆,Go没有做过。可能你的登陆请求发出去之后 暂停一下试试。

http://www.oschina.net/p/go-request 现在用的是这个库,进行模拟登录,至今仍然在使用中。

当使用了上面库后发现,当时用自带的net/http库,登陆不上的另外一个原因,是: 需要登陆的系统用的不是uft-8的字符集,而是用的GB2312的,所以还用到了另一个库https://github.com/axgle/mahonia来进行转码。 最终成功登录。

victorl
victorl · #14 · 8年之前

ChromeDriver PhantomJS Selenium 这三个都不错

yudeguang
yudeguang · #15 · 8年之前

https://github.com/yudeguang/gather
模拟浏览器进行数据采集包,可较方便的定义http头,同时全自动化处理cookie

xiaohaoxiong
xiaohaoxiong · #16 · 7年之前

一直困扰的问题,http 包post 没法重定向

Alex-liutao
Alex-liutao · #17 · 7年之前

使用 Surf 这个库能够非常方便地解决你的问题,连抓包分析都不用

xioxu
xioxu · #18 · 7年之前
  1. 可以使用 http://www.github.com/xioxu/goreq 包试试
  2. user agent也别自己写了, 可以使用 https://github.com/xioxu/gorandomua
wuxian
wuxian · #19 · 7年之前

老铁,你试验一下这个包"github.com/astaxie/beego/httplib"。该包在我司项目中大面积使用,亲测可用,不明白的艾特我

rainydew
rainydew · #20 · 6年之前

如果困难的话,用python解决这个会很快……

huoyongliang
huoyongliang · #21 · 6年之前

excel操作的可以使用这个包 https://github.com/360EntSecGroup-Skylar/excelize https://github.com/zuijinbuzai/excelclaim

登陆上传的,应该是请求上传接口的时候带上cookies身份会话信息吧。

这里有许多go lang相关的PDF电子书 http://www.86clouds.com/tag/go?from=studygolang 无需密码,无需付费,免费下载,仅供个人学习、研究之用,请勿用于商业用途,下载后请于24小时内删除。

myxu
myxu · #22 · 6年之前

下载一个fiddler监听页面,如果一些url是302跳转的 可以用下面的代码抓取,如果是post请求需要添加参数,有些参数是在url上直接添加了,有的是通过body,通过body的有两种 一种 form data ,一种request payLoad,post 方法一定要记得加header(“Content-Type”,"/类型/") var url string client:=http.Client{ checkRedirect: func(req http.Request,via []http.Request)error{ url =req.URL.String() return fmt.Errorf("错误") } } param :=fmt.Sprintf("/要传的参数/") req2,err:=http.NewRequest("POST","/你要登录的url/",strings.NewReader(param)) if err!=nil{ return err } req2.Header.Set(Content-Type”,"/类型/")//Add和Set你可以查一下,一个是替换原有的,一个是添加,反正我写了4个爬虫都是用 //set req2.AddCookie(/要加的cookie/) req2.AddCookie(/要加的cookie/) req2.AddCookie(/要加的cookie/) req2.AddCookie(/要加的cookie/)//cookie 不一定是一个 resq2,:=client2.Do(req2) defer resq2.Body.Close() result,:=ioutil.ReadAll(resq2.Body) fmt.println(string(result))//打印结果就是你要是数据所有 剩下的自己赛选 //纯自己手动打的 没办法粘贴 因为不在一台电脑上,希望能帮助你,而且一定要记得,有些js是把密码加密的,你可以查到他加密算法模拟加密,或者整合一下js,用golang调用cmd命令的方式,调用nodejs命令,用nodejs命令对密码加密返回加密的密码 再传如加密的密码

jan-bar
jan-bar · #23 · 5年之前

1.关于写excel我觉得不是很必要,因为可以直接写csv文本文件用excel打开后复制到另一个excel文件,当然也是有现成库,只不过我没用过。
2.关于go库自动将重定向处理可以参考我之前的一个回答点击跳转

client := &http.Client{ // 忽略证书验证
            Transport: &http.Transport{
                TLSClientConfig: &tls.Config{
                    InsecureSkipVerify: true,
                },
            }, // 不重定向:http://www.sohu.com/a/122147787_505779
            CheckRedirect: func(req *http.Request, via []*http.Request) error {
                return http.ErrUseLastResponse
            },
            Timeout: 5 * time.Second,
        },
linkerlin
linkerlin · #24 · 5年之前

声明式网页抓取器 Ferret http://zhipu.us/t/150.html

emVybwo
emVybwo · #25 · 5年之前

使用chromedp吧,不用模拟了

DDDZZZFFF
DDDZZZFFF · #26 · 5年之前

写个python脚本他不香吗

GodSadness
GodSadness · #27 · 5年之前

用python脚本他不香吗!!!

qazxdr1
qazxdr1 · #28 · 5年之前

JSRUN 里有更多内容 搜索 jsrun

itchin
itchin · #29 · 5年之前

网站用了些反爬虫的机制,可以考虑用chromedp来爬,它是用代码操作浏览器,可直接在chromedp代码中用用户名、密码直接代码,然后用同一个上下文继续往后操作,不需要自己处理cookie。

bjtn123
bjtn123 · #30 · 4年之前

:thumbsup:

shuidaan
shuidaan · #31 · 4年之前

学习了

164067986
164067986 · #32 · 4年之前
bjtn123bjtn123 #30 回复

:thumbsup:

支持

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传