http://www.7klian.com

某动态js加密cookie网站爬虫记录

return

}

"context"

剧本:

}

fmt.Println("visit first")

Domain string

dwFlags

安详相关的符号,配置为0即可。

d[i] = *p2

creation_utc INTEGER NOT NULL,

log.Fatal(err)

if !ok {

defer db.Close()

return fmt.Errorf("encrypted_value不是[]byte范例")

procDecryptData = dllcrypt32.NewProc("CryptUnprotectData")

r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(newBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outblob)))

1.问题由来:由于公司新项目需求,需要从差异平台爬取大量与项目相关的数据,大大都平台没有反爬机制,只有一个站点部署了反爬。固然可以爬取的平台许多,可以选择爬取其他平台的数据来取代,可是思量到该平台的可用数据量很大,值得花时间做这个爬虫,同时也是受到好奇心的差遣,于是研究了该平台的反爬机制。以下将该站点称为h网站。2.问题描写:h网站的的会见需要带上一个动态cookie才气会见乐成。

type data_blob struct {

// run task list

var cookiesFile string = usr.HomeDir + `\AppData\Local\Google\Chrome\User Data\Default\Cookies`

fmt.Println(err)

"os/user"

type Cookie struct {

return &data_blob{}

chromedp.WaitVisible(`body`),

return nil

cbData: uint32(len(d)),

cookie.Name = name

return d

func main() {

}

encrypted_value BLOB DEFAULT '',

go-sqlite/sqlite3

利用sqlite3读取cookies这个db文件,按照cookie的host,name过滤得到需要的FSSBBIl1UgzbN7N80T即可。个中cookies中的字段,假如cookie value是加密的blob内容,那么value的值是放在encrypted_value字段,假如value没有加密,那么值放在value字段。爬取h平台所需cookie的value值是加密的,所以读取出来的encrypted_value还需要解密。chrome加密cookie在差异平台上的加密要领差异, Windows下加密回收DPAPI。

if nameFilter != "" && name != nameFilter {

}

path TEXT NOT NULL,

if err != nil {

"github.com/chromedp/chromedp"

会见失败原因:每一次会见Request Header需要带上一个动态的cookie,假如请求里没有该cookie,则会见失败,cookie如图所示pvReserved

保存参数,设为NULL即可。

if !ok {

defer cancel()

cookie.Domain = domain

if err != nil {

}

}

会见失败和会见乐成的图示

会见失败,返回HTML源码

})

cookie.Value = decrypted

s, err := decrypt(encrypted)

if err != nil {

return cookies, nil

}

cookies, err := ReadChromeCookies(cookiesFile, "www.hbsredcross.org.cn", "FSSBBIl1UgzbN7N80T")

value, ok := rec.Values[3].(string)

func (b *data_blob) toByteArray() []byte {

if r == 0 {

pbData *byte

}

}

Value string

encrypted_value, ok := rec.Values[12].([]byte)

err = db.VisitTableRecords("cookies", func(rowId *int64, rec sqlite3.Record) error {

if len(cookies) == 0 {

dllcrypt32 = syscall.NewLazyDLL("Crypt32.dll")

return fmt.Errorf("decrypting cookie %v: %v", cookie, err)

}

func decryptValue(encrypted []byte) (string, error) {

}

cbData uint32

}

}

defer localFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))

pbData: &d[0],

if len(rec.Values) < 14 {

domain, ok := rec.Values[1].(string)

return outblob.toByteArray(), nil

"syscall"

}

}

pOptionalEntropy

一个指向含有密钥DATA_BLOB的指针,不外在举办Cookie加密时凡是不会用到。

cookie := &Cookie{}

}

has_expires INTEGER NOT NULL DEFAULT 1,

if !ok {

<script type="text/javascript" r="m">(function(){var _$1B=0,_$cb=[[2,4,0,6,3,1,5,7],[97,4,63,4,78,47,10,82,53,20,38,20,66,3,90,20,87,49,77,75,37,93,33,61,42,44,56,50,20,39,83,57,26,54,6,21,41,95,96,11,21,45,74,62,43,69,21,15,98,92,98,17,47,58,21,30,51,29,48,16,89,14,76,21,73,13,21,85,81,64,35,20,40,9,67,64,31,7,20,55,64,20,68,47,27,0,88,5,24,20,86,46,8,34,28,1,60,32,23,36,2,70,12,65,80,72,25,19,52,71,18,91,79,84,94,22,59,20],[32,1,0,31,0,21,33,7,18,27,22,15,5,23,20,22,26,12,30,17,11,28,8,28,2,4,19,10,19,9,19,29,19,16,25,19,6,19,3,24,13,14,22],[11,39,23,34,15,47,18,3,19,31,21,6,30,5,22,38,46,25,2,36,12,6,45,15,20,27,8,32,14,0,14,39,26,1,41,35,26,24,9,37,9,44,13,44,40,6,9,16,40,38,29,10,28,33,43,7,37,40,16,29,0,17,4,42,18],[24,25,13,6,30,27,31,8,34,29,10,26,25,7,23,21,25,0,14,21,28,20,22,2,32,5,11,35,28,1,17,33,36,15,32,12,35,9,1,25,4,16,19,18,8,3,25]];function _$MB(_$7U,_$5F){return _$e8.Math.abs(_$7U)%_$5F;}function _$x2(_$Qf){if(_$2B(_$Qf)){_$pc(_$Qf);}var _$6n=_$5M();var _$6n=_$Qf[_$MB(_$c2()+_$jX(),16)];_$ui(_$Qf);var _$6n=_$Qf[_$MB(_$Dh()+_$UF(),16)];_$Qf[_$MB(_$Qf[_$MB(_$c2()+_$jX(),16)],16)]=_$i1(_$Qf);return _$DW(_$Qf);}function _$2B(_$Qf){var _$6n=_$UF();var _$s2=_$5M();if(_$Lt()){_$Qf[_$MB(_$jX(),16)]=_$Xc();}_$Qf[11]=_$5M();_$Qf[7]=_$c2();var _$6n=_$Ri();var _$6n=_$zc();return _$fx(_$Qf);}function _$UF(){return 11}function _$5M(){return 1}function _$Lt(){return 4}function _$jX(){return 3}function _$Xc(){return 9}function _$Dh(){return 5}function _$c2(){return 13}function _$Ri(){return 14}function _$zc(){return 12}function _$fx(_$Qf){var _$6n=_$05();var _$U6=_$c2();_$Qf[_$MB(_$Y$(),16)]=_$Ri();_$Qf[_$MB(_$Dh(),16)]=_$UF();return _$5M();}function _$05(){return 7}function _$Y$(){return 0}function _$pc(_$Qf){_$x$(_$Qf);_$Qf[8]=_$Sd();var _$s2=_$jX();var _$s2=_$Xc();_$Qf[15]=_$Dh();var _$s2=_$Sd();var _$U6=_$Lt();return _$QL(_$Qf);}function _$x$(_$Qf){var _$6n=_$Ri();var _$U6=_$zc();_$Qf[_$MB(_$UF(),16)]=_$5M();_$Qf[7]=_$c2();var _$s2=_$Ri();var _$s2=_$zc();return _$5u();}function _$5u(){return 10}function _$Sd(){return 6}function _$QL(_$Qf){_$Qf[0]=_$Ri();var _$U6=_$UF();var _$U6=_$5M();_$Qf[7]=_$c2();return _$jX();}function _$ui(_$Qf) .....................})()</script>

}

)

return fmt.Errorf("name不是string范例")

if len(d) == 0 {

is_persistent INTEGER NOT NULL DEFAULT 1,

value TEXT NOT NULL,

}

source_scheme INTEGER NOT NULL DEFAULT 0,

host_key TEXT NOT NULL,

"github.com/go-sqlite/sqlite3"

个中最为要害的cookie是name为FSSBBIl1UgzbN7N80T的cookie,该cookie是动态变革的,而其他的cookie:譬喻:FSSBBIl1UgzbN7N80S, JSESSIONID, site_id_cookie等这些都是稳定的,而让FSSBBIl1UgzbN7N80T这个cookie发活跃态变革的代码有两段,别离是:<script type="text/javascript" charset="iso-8859-1" src="https://www.wanbizu.com/4QbVtADbnLVIc/d.FxJzG50F.3e2af61.js" r='m'></script>

usr, _ := user.Current()

cookie.Value = value

return string(s), nil

"fmt"

func decrypt(data []byte) ([]byte, error) {

}

last_access_utc INTEGER NOT NULL,

)

chromedp.Evaluate(`document.cookie`, &res),

fmt.Println(cookieBase + res)

固然可以爬取的平台许多,可以选择爬取其他平台的数据来取代,可是思量到该平台的可用数据量很大,值得花时间做这个爬虫,同时也是受到好奇心的差遣,于是研究了该平台的反爬机制。

var cookies []*Cookie

return nil, err

if err != nil {

return nil

)

for i := 0; i < int(b.cbData); i++ {

func main() {

zellyn/kooky

有封装好的直接得到所需cookie的要领。其他相关的库可以自行查找…

import (

"unsafe"

name TEXT NOT NULL,

var cookieBase string = "site_id_cookie=1; clientlanguage=zh_CN; "

chromedp.Navigate(``),

var outblob data_blob

会见乐成,返回HTML源码

p := uintptr(unsafe.Pointer(b.pbData))

}

}

is_httponly INTEGER NOT NULL,

go有一个goja的执行js的库,相当于python的pyv8模块。我刚开始想的是挪用goja,每次会见无论失败乐成返回中城市附发动态js代码,所以可以用goja执行代码,得到cookie,带上cookie再会见。可是随之而来的问题是,动态js代码中引用了window,document这样的欣赏器情况中才有的全局变量。goja已经无法满意动态js的执行,到这里有一个办理步伐就是利用chromedp库。最近遍及利用的headless browser办理方案PhantomJS已经公布不再继承维护,转而推荐利用headless chrome.那么headless chrome毕竟是什么呢,Headless Chrome 是 Chrome 欣赏器的无界面形态,可以在不打开欣赏器的前提下,利用所有 Chrome 支持的特性运行你的措施。简而言之,除了没有图形界面,headless chrome具有所有现代欣赏器的特性,可以像在其他现代欣赏器里一样渲染方针网页,并能举办网页截图,获取cookie,获取html等操纵。想要在golang措施里利用headless chrome,需要借助一些开源库,实现和headless chrome交互的库有许多,这里选择chromedp,接口和Selenium雷同,易上手。chromedp提供一种更快,更简朴的方法来驱动欣赏器 (Chrome, Edge, Safari, Android等)在 Go中利用Chrome Debugging Protocol 而且没有外部依赖 (如Selenium, PhantomJS等)。挪用chromedp的Evaluate来执行相关js代码,在运行中照旧报错。可是其实利用chromedp会见站点,跟在欣赏器里会见是一样的,只是没有可视化的图形页面罢了。操作chromedp会见后已经无需再执动作态js,会见的时候代码已经执行过了,此时cookie已经发生。所以只需要操作chromedp获取headless chrome里存储的cookie即可。package main

return

Name string

return fmt.Errorf("value不是string范例")

}

if len(encrypted_value) > 0 {

is_secure INTEGER NOT NULL,

"log"

return fmt.Errorf("table 至少有14个字段", len(rec.Values))

)

2.Simple script to extract (encrypted) cookies out of Chrome OS X cookie store. Usage: ./cookiemonster domain.com

samesite INTEGER NOT NULL DEFAULT -1,

return ``, err

} else {

func newBlob(d []byte) *data_blob {

第二段代码不妨称为bootstrap.js,bootstrap.js是动态变革,并且加密夹杂过的。

p += unsafe.Sizeof(byte(0))

"fmt"

dllkernel32 = syscall.NewLazyDLL("Kernel32.dll")

if domainFilter != "" && domain != domainFilter {

pDataIn

一个指向DATA_BLOB布局体的指针,该DATA_BLOB内需存放被解密的数据。DATA_BLOB布局体内含两个成员:cbData,数据的所占用的字节数;pbData,,指向数据地址内存的指针。

1.Chrome在对Cookie的值生存之前会举办加密处理惩罚,并生存在数据库的encrypt_value字段中。在Windows系统中,Cookie加密回收的是系统提供的函数CryptProtectData,在解密的时候也需要挪用系统提供的函数CryptUnprotectData。解密的Windows用户必需与加密的用户一致才气乐成解密。不外系统提供的是C函数,go通过syscall库来实现对C函数的挪用。CryptUnprotectData需要7个参数:

)

ctx, cancel := chromedp.NewContext(context.Background())

UNIQUE (host_key, name, path)

}

pPromptStruct

解密是一个有安详风险的操纵,大概需要弹出风险晋升,假如不需要弹出提示配置为NULL即可。

localFree = dllkernel32.NewProc("LocalFree")

ppszDataDescr

描写该加密数据的信息,假如在举办加密操纵的时候添加了描写,那么在解密的时候也能获得该描写信息。得到该描写后需要挪用系统提供的LocalFree释放ppszDataDescr指向的内存。假如不需要,设为NULL即可。

爬虫的难度

对比其他网站,该网站爬虫的难度在于每次会见需要带上所需的动态cookie,可是离开了欣赏器情况,发生cookie的js代码无法执行,并且js代码也是动态变革的,所以无法只在js情况内里执行一次代码,就一劳永逸。

}

return nil

if err != nil {

return fmt.Errorf("domain不是string范例")

var res string

return &data_blob{

}

if err != nil {

err := chromedp.Run(ctx,

var (

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读