极限验证 geetest 怎么用又有新破解版了,有人试过没有,到底是不是真的

以GeeTest为例的滑动验证码破解 - 参数初探 - 知乎专栏
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"title":"以GeeTest为例的滑动验证码破解 - 参数初探","author":"xJonathan","content":"上一篇文章的最后,我们列出来需要解决的一些问题。这些问题基本上都与参数有关,因此从这里开始我们便会开始研究他们。首先,要用到的工具是浏览器F12 Dev Tool里的Debugger,Chrome和Edge的都可以。开始之前先确保你对JavaScript有最基础的认知,达到语法上能看懂就好了。---------------------------------------------------------------------------------------首先要探究的是1号包里的ts参数,上一篇文章中我们作出了它是随机数的假设。切换到Debugger标签页,在搜索框中输入ts=进行搜索:可以看到,ts参数的确是随机数没错。这样我们就可以写代码模拟出1号包了。可以看到,ts参数的确是随机数没错。这样我们就可以写代码模拟出1号包了。接着是回调函数名geetest_xxx中的xxx,我们想知道这里的xxx是否也是随机数。在搜索框中寻找callback=\",结果有两个,一个是gt.js中的:s.src = protocol + apiServer + \"getfrontlib.php?gt=\" + config.gt + \"&callback=\" + cb;\n从这里往上追查cb,找到了这一行:var cb = \"geetest_\" + random();\nrandom并不是JS原生函数,在同一页面找到random的定义:var random = function () {\n
return parseInt(Math.random() * 10000) + (new Date()).valueOf();\n
};\n我们一开始猜测它是单纯的随机数,实际上它是一个0-10000的随机整数加上目前的UNIX时间。这个实际上也非常好模拟。至此,对于上次留下的5个问题中,第一个问题:1号包的参数ts和后面的callback的后缀是否真的是随机数?我们得出了答案:ts是单纯的随机数,只是为了防止浏览器直接返回缓存callback的后缀是随机数+目前时间是的,就是这样,这篇文章无耻地在这里结束了?(一天一更就是这样)。原本想把图像还原也开个头的,但是有点累了不想写了。我还得尽快在专栏微软信仰中心里更新之前挖下的必应词典API的坑啊(有兴趣的可以去看看)。下篇文章里我们将一起探究打乱了的图像是如何被还原的,而在再下一篇文章里,我们将会开始写C#来实现这个还原。还是那句啦,喜欢我的文章的话记得关注点赞!","updated":"T01:14:14.000Z","canComment":false,"commentPermission":"anyone","commentCount":1,"collapsedCount":0,"likeCount":9,"state":"published","isLiked":false,"slug":"","lastestTipjarors":[],"isTitleImageFullScreen":false,"rating":"none","titleImage":"/21a76c58f75c592aaef564aec22bff47_r.png","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[{"url":"/topic/","id":"","name":"验证码识别"},{"url":"/topic/","id":"","name":"Windows 开发"},{"url":"/topic/","id":"","name":"JavaScript"}],"adminClosedComment":false,"titleImageSize":{"width":1259,"height":757},"href":"/api/posts/","excerptTitle":"","column":{"slug":"windev","name":"Windows应用开发"},"tipjarState":"activated","tipjarTagLine":"真诚赞赏,手留余香","sourceUrl":"","pageCommentsCount":1,"tipjarorCount":0,"annotationAction":[],"snapshotUrl":"","publishedTime":"T09:14:14+08:00","url":"/p/","lastestLikers":[{"profileUrl":"/people/jiu-yue-30-73","bio":"","hash":"bd2f915bc702f555e331eb8","uid":936400,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"jiu-yue-30-73","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"name":"玖月"},{"profileUrl":"/people/liu-yi-xin-48-66","bio":"游戏评论师","hash":"61cc0abaa7abefc14a981b","uid":070200,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"liu-yi-xin-48-66","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"name":"刘亦鑫"},{"profileUrl":"/people/sun-hui-ming-51-62","bio":"","hash":"ef2b73b","uid":791300,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"sun-hui-ming-51-62","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"name":"孙会明"},{"profileUrl":"/people/li-zhang-86","bio":"","hash":"db365df9a1e64c92089eba646f771fc4","uid":68,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"li-zhang-86","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"name":"li zhang"},{"profileUrl":"/people/God-J","bio":"Solitude|Migraine","hash":"4f3aca5f9d5fb918a4c87d013f43170c","uid":173600,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"God-J","avatar":{"id":"defd47b21c12d51bfb518ef2eb47f65a","template":"/{id}_{size}.jpg"},"name":"WISE"}],"summary":"上一篇文章的最后,我们列出来需要解决的一些问题。这些问题基本上都与参数有关,因此从这里开始我们便会开始研究他们。首先,要用到的工具是浏览器F12 Dev Tool里的Debugger,Chrome和Edge的都可以。开始之前先确保你对JavaScript有最基础的认知,达到语法…","reviewingCommentsCount":0,"meta":{"previous":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"/af195bf14e6ddabd2bc83_r.png","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"验证码识别"},{"url":"/topic/","id":"","name":"Windows 开发"},{"url":"/topic/","id":"","name":"C#"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"profileUrl":"/people/xJonathan","bio":"学商科的伪程序猿 ","hash":"b62ffa72aafb3f7d10b5ec5e6e50bd16","uid":24,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"xJonathan","avatar":{"id":"74a89d383","template":"/{id}_{size}.jpg"},"name":"Jonathan LEI"},"column":{"slug":"windev","name":"Windows应用开发"},"content":"接下来便正式开始这个系列的教程了。虽然我本身已经完成破解的绝大部分,但是我仍然会在这个教程里以第一次接触的视角进行讲解,以避免出现太过跳跃的情况。要想完成破解,必须先了解整个系统的运作原理。这里,乃至这往后的几篇文章里,的整个过程无需写任何一句代码。你只需要一个浏览器就够了。至于浏览器的选择,我并不推荐Edge。因为未知的原因,在捕捉该页面的包的时候,其中一个包的Response Body在Edge的F12 Dev Tool中显示为空,实际上它包含重要的内容。而经过测试,在Chrome中该包内容正确显示。除了这一个包之外,Edge没有任何问题。如果你实在不想用Chrome,可以选择Edge+Fiddler的组合(我就是这样解决的?)。选择好你的浏览器之后,访问,待首次加载完成后,再开启F12,并从地址栏重新进入网页抓包(非刷新)。这样做可以避免一大堆CSS和图片之类的无用包干扰视线,最后拉动滑块完成验证。于是大概会得到如下的结果:全程是清一色的GET Request,而且可以注意到,除了被高亮了的四个package,其他的包都是没有带Query String的,所以分析的重点便落在了这四个包上。------------------------------------------------------------------------------------------首先看1号包,也就是我前面提到的Edge无法抓到的包。这个包只带有一个参数ts:如果重复多次抓包,可以看到这个ts值每次都不一样,初步猜测是随机数,防止浏览器从缓存中直接返回结果。至于Response Body,从Fiddler中看到如下:{\"success\":1,\"gt\":\"80a8ed78d1d22e16f5b6c478f03b9212\",\"challenge\":\"c7f5d6e24c34b500221aed87feca10f8\"}\n这是一段包含了三个值的JSON,其中的gt和challenge显然会用在后面的请求中。------------------------------------------------------------------------------------------接着是2号包,这个包发送的参数如图:其中gt便是我们刚才从1号包的回复里找到的值,至于callback,从名字推测是本地生成了名为geetest_xxxx的函数,待请求完成后会回调这个函数,至于后面的xxxx是怎么来的暂时不清楚。猜测是随机数。至于Response Body,则意外地是一段没有被混淆的明文JavaScript。浏览后发现这段JavaScript是在执行一些初始化工作,并发出后面的请求。代码比较长这里不贴出来了,这也是这次破解里能见到的最后一段没有被混淆的JavaScript代码了?。------------------------------------------------------------------------------------------然后是3号包。刚才看的2号包实际上没有太多作用,返回的JavaScript中除了每次会更改要调用的回调函数名之外没有改变,并没有包含有效信息。3号包则不一样,其参数为:更新:现在3号包已经新增参数\"type\",其值设置为\"slide\"即可。callback应该也是回调函数的名称。challenge和gt是之前1号包得到的值。offline并不知道是什么?,不过看上去并不重要,应该设置为false就好了吧。至于product,从官网上可以了解到它的验证码有多种嵌入模式,而中山大学教务系统采用了float的模式。所以product设置为float就错不了了。至于返回值,则包含了重要的信息:geetest_2({\"fullbg\": \"pictures/gt//.jpg\", \"fullpage\": false, \"hide_delay\": 800, \"staticservers\": [\"uems./jwxt/geetest/\"], \"clean\": false, \"theme_version\": \"3.0.21\", \"https\": false, \"slice\": \"pictures/gt//slice/88d04351e.png\", \"feedback\": \"/contact#report\", \"product\": \"float\", \"link\": \"\", \"ypos\": 31, \"challenge\": \"c7f5d6e24c34b500221aed87feca10f8g6\", \"type\": \"slide\", \"id\": \"ac7f5d6e24c34b500221aed87feca10f8\", \"apiserver\": \"/\", \"gt\": \"80a8ed78d1d22e16f5b6c478f03b9212\", \"height\": 116, \"xpos\": 0, \"version\": \"5.5.9\", \"show_delay\": 250, \"benchmark\": false, \"theme\": \"golden\", \"mobile\": false, \"logo\": true, \"bg\": \"pictures/gt//bg/88d04351e.jpg\"})\n这是在以这段JSON为参数,调用本地的回调函数。这段JSON里包含了三个图片地址:fullbg、bg和slice。分表访问其URL,得到的图片如下:看得出来,slice并不在我们的兴趣范围内。fullbg和bg则分别是完整的背景和缺块的背景。这两张图片被打乱的方法是相同的,可见可以通过同一个算法还原。另外,返回值里的staticservers和https可以帮我们还原出完整的图片地址。而剩余的对我们来说并没有太大意义。------------------------------------------------------------------------------------------最后是4号包,4号包明显是我们最后拖动滑块后触发的一个包,先看返回值:geetest_5({\"success\": 1,\"message\":\"success\",\"validate\":\"8ee3c4a1ee1\",\"score\":1})\n总共4个返回值,其中score是用以显示“您击败了xx%的用户”的分数(这风格好像360?)。而validate相信是在网页的实际登录过程中的一个参数。接下来看参数:这里总共有多达7个参数。其中callback、challenge和gt的含义我们都已经了解。a是一段看上去毫无意义的乱码,但是想必是用以防破解的Hash之类。imgload,这个参数的含义暂时不清楚。passtime,从名字便可以看出是指用户拉动滑块后用了多少时间完成,这也是返回值里score的来源。userresponse,这个参数里包含了用户拉动滑块的数据。估计是用滑动距离加密得出。------------------------------------------------------------------------------------------至此,我们的第一步就大致完成了。我们知道了这些:总共需要模拟4个(甚至3个)包来完成验证码自动化gt和challenge是服务器用以识别用户的参数fullbg和bg两张图片被打乱了,但是能用同一个算法还原然而更多的是未知:1号包的参数ts和后面的callback的后缀是否真的是随机数?fullbg和bg通过什么算法还原完整图象?imgload是什么参数,它是否服务器防破解的一环?userresponse是如何算出的,其算法的参数中的移动距离使用px作单位吗?a包含了什么信息,为什么这么长?在接下来的文章里,我们将一一探索这些问题。通过一个个解决这些问题,我们便可以了解GeeTest系统运作的原理。在探索的过程中,我们会逐步开始写代码模拟。这篇文章就到这里,从下一篇文章开始,我们便要开始阅读那些乱七八糟的经过混淆的JavaScript代码。我强烈建议读者将本教程里的内容自己动手试一遍,只有真的自己动手(get your hands dirty),才可能学到新的知识。如果你喜欢我的文章,不妨关注我的专栏并点赞。本人编程水平不高,欢迎大家投稿让更多人学到新技术。谢谢!","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T09:03:43+08:00","url":"/p/","title":"以GeeTest为例的滑动验证码破解 - 总体分析","summary":"接下来便正式开始这个系列的教程了。虽然我本身已经完成破解的绝大部分,但是我仍然会在这个教程里以第一次接触的视角进行讲解,以避免出现太过跳跃的情况。要想完成破解,必须先了解整个系统的运作原理。这里,乃至这往后的几篇文章里,的整个过程无需写任…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":0,"likesCount":0},"next":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"/dafd067b794_r.png","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"验证码识别"},{"url":"/topic/","id":"","name":"Windows 开发"},{"url":"/topic/","id":"","name":"JavaScript"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"profileUrl":"/people/xJonathan","bio":"学商科的伪程序猿 ","hash":"b62ffa72aafb3f7d10b5ec5e6e50bd16","uid":24,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"xJonathan","avatar":{"id":"74a89d383","template":"/{id}_{size}.jpg"},"name":"Jonathan LEI"},"column":{"slug":"windev","name":"Windows应用开发"},"content":"(请原谅我的配图,毕竟是用MSPaint画的)总算要开始讲解图片还原了。我们首先看看GeeTest自己是如何实现网页上的图片还原的:打开DOM Explorer,点击Ctrl+B开始选择元素,把指针放到滑块上,待图像出现后点击:然后在DOM里,我们可以看到如下的结构:是的,GeeTest并没有在网页上还原这个图片,而是通过放置2行26列的52个10px*58px的div元素,将这些元素的背景统统设为被打乱的图片,并设置相应的背景偏移,以达到看上去图像被还原的效果。于是,问题的关键落在了这些偏移值是如何计算的上面。只要能找到偏移值的计算方法,我们就可以模拟出这个算法,真正地还原这张图片。留意到每个div的class都是gt_cut_fullbg_slice,在Debugger中搜索,出来的结果却全是CSS。我们要找的可是JavaScript啊,看来gt_cut_fullbg_slice并没有完整地在JS中出现,说明它是由几个部分相连而成的。而这里面最需要被替换的估计是fullbg,于是搜索_slice,在几个结果中,我们能发现下面这个才是我们真正需要的:从这里我们可以整理出这样的代码:for (o.className = \"gt_cut_\" + b + \"_slice\", i = 0, j = n.length; j & i; i++)\n
k = \"-\" + (n[i] % 26 * 12 + 1) + \"px \" + (n[i] & 25 ? -f.config.height / 2 : 0) + \"px\",\n
m = o.cloneNode(), m.style.backgroundImage = \"url(\" + c + \")\",\n
l.push(m),\n
e.appendChild(m),\n
m.style.backgroundPosition = k\nJavaScript的语法真是相当随意啊?,这也是我不喜欢它的原因之一。这里面其它的代码都自己理解一下吧,我们关注的重点在k上,因为k显然是一个代表了位移的字符串:k = \"-\" + (n[i] % 26 * 12 + 1) + \"px \" + (n[i] & 25 ? -f.config.height / 2 : 0) + \"px\"\n这里总共有两个值,第一个值是x方向偏移,第二个是y方向偏移。其余的部分和C#一样都很好理解,问题只有两个:n是什么?f.config.height是什么?为了解决这两个问题,我们在这里下个breakpoint。记住要通过右键添加breakpoint,而不是直接在左侧点击。原因是这里的代码经过了混淆,整个文件只有一行,直接在左边点击出来的断点不一定出现在你想要的位置。重新进入页面,我们首先看看什么是f.config吧:这东西...似曾相识啊...这不就是我们上次3号包的返回结果吗!好了第二个问题解决了,我们来看第一个,看看n是什么:这样一来,这个数组就成了问题的关键,我们需要继续追查这个数组的来源,实际上它就在for的前一句里:var m,n=a(),o=document.createElement(\"div\");\n看来n是由一个名为a的函数产生的,我们来看看a是什么。转到Console标签页,输入a然后回车:function (){for(var a,b=\"6_11_7_10_4_12_3_1_0_5_2_9_8\".split(\"_\"),c=[],d=0,e=52;e&d;d++)a=2*parseInt(b[parseInt(d%26/2)])+d%2,parseInt(d/2)%2||(a+=d%2?-1:1),a+=26&d?26:0,c.push(a);return c}\n这便是a的定义。可以看到,a里面再也没有引用外部变量,也就是说我们的追查到底了。将这个函数翻译为C#并不难,但是懒惰的我选择直接在C#中运行JS解决问题?。然而还有一个问题,就是这个还原函数是固定的吗,还是每次都不一样?如果搜索那串带下划线的字符串,可以发现这个函数实际上被定义在这里:而这段代码位于geetest.5.5.9.js文件中,是一个静态JavaScript文件。这下便可以放心了。如此看来,所有下载的图片都是经过同一个次序打乱的,我们只需要写一次这个还原函数,就能还原所有图片。至此,对于第二个问题:fullbg和bg通过什么算法还原完整图象?我们也有了答案,接下来我们就要开始写C#代码实现还原算法,将这些被打乱的图像还原。但是要还原图像我们首先要模拟1、2、3号包并下载图片。对于有网络编程基础的人来说这是小儿科,但为了照顾没有基础的读者,同时也为了有基础读者的使用方便,我会在该系列下一篇文章之前插入我的一个小项目:NetworkHandler。NetworkHandler一个非常简单的类,但是它能让使用者一句代码完成一个HttpRequest,而不需要设置这个设置那个。而且还有重要的一点,便是原生的CookieContainer中有一个严重的问题。某些网站的Set-Cookie没有按照Standard来设置,它便无法识别。这其实不是CookieContainer的bug,只是网站没有按规矩办事。我的NetworkHandler中通过使用一个List&Cookie&对象解决这个问题。这个项目将在我的GitHub上开源并不断更新,欢迎大家使用和Contribute。谢谢阅读本文,喜欢的还请关注点赞,谢谢!","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T09:16:34+08:00","url":"/p/","title":"以GeeTest为例的滑动验证码破解 - 图片还原1","summary":"(请原谅我的配图,毕竟是用MSPaint画的)总算要开始讲解图片还原了。我们首先看看GeeTest自己是如何实现网页上的图片还原的:打开DOM Explorer,点击Ctrl+B开始选择元素,把指针放到滑块上,待图像出现后点击:然后在DOM里,我们可以看到如下的结构:是的…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":0,"likesCount":0}},"annotationDetail":null,"commentsCount":1,"likesCount":9,"FULLINFO":true}},"User":{"xJonathan":{"isFollowed":false,"name":"Jonathan LEI","headline":"","avatarUrl":"/74a89d383_s.jpg","isFollowing":false,"type":"people","slug":"xJonathan","bio":"学商科的伪程序猿 ","hash":"b62ffa72aafb3f7d10b5ec5e6e50bd16","uid":24,"isOrg":false,"description":"","profileUrl":"/people/xJonathan","avatar":{"id":"74a89d383","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{},"columns":{"windev":{"following":false,"canManage":false,"href":"/api/columns/windev","name":"Windows应用开发","creator":{"slug":"xJonathan"},"url":"/windev","slug":"windev","avatar":{"id":"624faddb3510faede58f71d7667d3bcb","template":"/{id}_{size}.jpeg"}}},"columnPosts":{},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"switches":{"couldAddVideo":false},"draft":{"titleImage":"","titleImageSize":{},"isTitleImageFullScreen":false,"canTitleImageFullScreen":false,"title":"","titleImageUploading":false,"error":"","content":"","draftLoading":false,"globalLoading":false,"pendingVideo":{"resource":null,"error":null}},"config":{"userNotBindPhoneTipString":{}},"recommendPosts":{"articleRecommendations":[],"columnRecommendations":[]},"env":{"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{}}您还可以使用以下方式登录
当前位置:&>&&>&&>& > 破解极验(geetest)验证码
geetest 验证码 破解极验(geetest)验证码
最近在搞爬虫的时候在好几个网站都碰到了一种叫做geetest的滑动条验证码,一直没有太好的办法只能在触发这个验证码后发个报警去手动处理一下。/exp_embed是他们官网的样例。后来研究了下觉得要破解这个验证码有这么几个问题:无法直接通过发送url请求来实现鼠标拖动的动作; 实际的背景图片是乱的,并不是我们实际肉眼看到的图像,如下图; &开创行为判别算法,利用数据挖掘和机器学习,提取超过200多个行为判别特征,建立坚若磐石的多维验证防御体系。&这是官网的描述,听上去就已经很高大上,查了些资料也都说拖动轨迹的识别是geetest的核心内容而无过多的表述,那么这也应该是主要的难点了。后面我也就基于了以上的问题去一步一步研究如何实现模拟这一操作:一.安装配置geetest的样例首先自己安装配置一份geetest的样例。虽然geetest官网上有样例,但有时候反应比较慢,而且后面研究拖动轨迹的时候还需要对样例做一定的改动。编程语言我使用的是python2.7,所以这里选择的也是python版本的。参考内容:/install/sections/idx-server-sdk.html安装git:[root@mysql-test1 ~]# yum install git在github中clone出最新Demo项目:[root@mysql-test1 ~]# git clone /GeeTeam/gt-python-sdk.git安装GeetestSDK:[root@mysql-test1 ~]# cd gt-python-sdk/[root@mysql-test1 gt-python-sdk]# python setup.py install安装Django,要注意的是最新的Django-1.10.1和当前的GeetestSDK是有兼容性问题的,要用Django-1.8.14:[root@mysql-test1 ~]# wget --no-check-certificate
/download/1.8.14/tarball/[root@mysql-test1 ~]# tar zxvf Django-1.8.14.tar.gz[root@mysql-test1 ~]# cd Django-1.8.14[root@mysql-test1 Django-1.8.14]# python setup.py install后面就可以直接运行了:[root@mysql-test1 ~]# cd gt-python-sdk/demo/django_demo/[root@mysql-test1 django_demo]# python manage.py runserver 0.0.0.0:8000另外如果安装启动的时候报sqlite相关的错误,那就要安装Linux的sqlite-devel包,然后再编译安装python就可以了。现在在浏览器里打开http://192.168.161.51:8000/就可以看到安装的geetest样例了。另外还可以把gt-python-sdk/demo/django_demo/static/index.html里面41-61行注释掉,只保留嵌入式的Demo。二.在浏览器上模拟鼠标拖动的操作参考内容:/wangly/p/5630069.html这里要实现鼠标拖动的动作靠直接发送url请求是无法实现的,需要有个真的浏览器再去模拟鼠标拖动的动作。根据参考的内容使用了Selenium(也有python版本的)可以实现这一操作。通过python的pip可以直接安装,我这里显示的版本是selenium-2.53。除此之外还需要根据浏览器下载webdriver。我使用的是chrome,驱动在http://download.csdn.net/detail/paololiu/9620177有下载,下载完后解压放到chrome的安装目录即可。另外还要注意chrome的版本,我这里使用的是52.0.。#!/usr/local/bin/python# -*- coding: utf8 -*-'''Created on 日@author: PaoloLiu'''from selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitfrom mon.action_chains import ActionChainsimport timedef main():#
这里的文件路径是webdriver的文件路径
driver = webdriver.Chrome(executable_path=r&C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe&)#
driver.get(&http://192.168.161.51:8000/&)#
等待页面的上元素刷新出来
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_slider_knob gt_show']&).is_displayed())
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_cut_bg gt_show']&).is_displayed())
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_cut_fullbg gt_show']&).is_displayed())#
找到滑动的圆球
element=driver.find_element_by_xpath(&//div[@class='gt_slider_knob gt_show']&)#
鼠标点击元素并按住不放
print &第一步,点击元素&
ActionChains(driver).click_and_hold(on_element=element).perform()
time.sleep(1)
print &第二步,拖动元素&#
拖动鼠标到指定的位置,注意这里位置是相对于元素左上角的相对值
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=200, yoffset=50).perform()
time.sleep(1)
print &第三步,释放鼠标&#
ActionChains(driver).release(on_element=element).perform()
time.sleep(3)if __name__ == '__main__':
main()三.计算图片中缺口的偏移量参考内容:/yuananyun/p/5655019.html上面的移动位置我写了一个固定的值,实际情况这个值是不固定的,需要根据背景图片的缺口来算出这个偏移量。然而要计算缺口的偏移量还要先还原图片。1.还原图片如上图,原始的图片是乱的,但是我们可以在html里面可以看到把同一个图片的位置进行重新组合就可以看到还原后的图片了:代码如下:import PIL.Image as imageimport PIL.ImageChops as imagechopsimport time,re,cStringIO,urllib2,randomdef get_merge_image(filename,location_list):
'''
根据位置对图片进行合并还原
:filename:图片
:location_list:图片位置
'''
im = image.open(filename)
new_im = image.new('RGB', (260,116))
im_list_upper=[]
im_list_down=[]
for location in location_list:
if location['y']==-58:
im_list_upper.append(im.crop((abs(location['x']),58,abs(location['x'])+10,166)))
if location['y']==0:
im_list_down.append(im.crop((abs(location['x']),0,abs(location['x'])+10,58)))
new_im = image.new('RGB', (260,116))
x_offset = 0
for im in im_list_upper:
new_im.paste(im, (x_offset,0))
x_offset += im.size[0]
x_offset = 0
for im in im_list_down:
new_im.paste(im, (x_offset,58))
x_offset += im.size[0]
return new_imdef get_image(driver,div):
'''
下载并还原图片
:driver:webdriver
:div:图片的div
'''
#找到图片所在的div
background_images=driver.find_elements_by_xpath(div)
location_list=[]
imageurl=''
for background_image in background_images:
location={}
#在html里面解析出小图片的url地址,还有长高的数值
location['x']=int(re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][1])
location['y']=int(re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][2])
imageurl=re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][0]
location_list.append(location)
imageurl=imageurl.replace(&webp&,&jpg&)
jpgfile=cStringIO.StringIO(urllib2.urlopen(imageurl).read())
#重新合并图片
image=get_merge_image(jpgfile,location_list )
return image2.计算缺口位置通过python的PIL.ImageChops可以计算出两个图片不同地方的位置,方法如下:import PIL.ImageChops as imagechopsdiff=imagechops.difference(image1, image2)diff.show()print diff.getbbox()但是这在我们这里并不适用。因为我们得到的两个图片是通过拼接而成的,并且两张原图在背景上也还是稍有区别的,而difference方法计算得过于精确,所以这里得到的位置并不会是我们要的缺口的位置。这里我借用的参考内容的方法:两张原始图的大小都是相同的260*116,那就通过两个for循环依次对比每个像素点的RGB值,如果相差超过50则就认为找到了缺口的位置:def is_similar(image1,image2,x,y):
'''
'''
pixel1=image1.getpixel((x,y))
pixel2=image2.getpixel((x,y))
for i in range(0,3):
if abs(pixel1[i]-pixel2[i])&=50:
return False
return Truedef get_diff_location(image1,image2):
'''
计算缺口的位置
'''
for i in range(0,260):
for j in range(0,116):
if is_similar(image1,image2,i,j)==False:
i四.鼠标拖动的轨迹1.输出鼠标滑动轨迹参考内容:http://blog.csdn.net/ieternite/article/details/如果我们直接把上面算出来的缺口位置放到前面脚本里,你会发现即使移动的位置正确了,提示却是&怪物吃了饼图&,验证不通过。很显然,geetest识别出了这个动作并不是人的行为。这我们就需要去查看自然人滑动鼠标和我们代码实现的滑动在轨迹上有什么不同。geetest目前版本客户端最核心的是geetest.5.5.36.js,我们可以把它复制出来加以改造。首先找个工具把原代码格式化一下,然后再加入以下的内容:index.html页面的上直接调用的是gt.js,再由gt.js去调用geetest.5.5.36.js。我用的土办法是自己搭建一个简易的web server,并在host里面把域名指向到我自己的web server,然后再把页面上要调用的里的内容都放到我自己搭建的web server上,当然geetest.5.5.36.js是要用我刚才改造过的那个。里面只要static目录里的内容即可,pictures里面的图片找不到会自动指向到他们备用的网站的。我用的简易web server是HTTP File Server,可以在下载。如此一来,我们每次滑动鼠标包括代码实现的滑动操作在浏览器里都能显示出滑动的轨迹:2.模拟人的行为有了轨迹的数据,我们就可以进行对比分析了。上图的是我手动滑动的轨迹,而下图的是我通过代码拖动的轨迹,其实根本就不需要涉及到什么复杂的数据挖掘机器学习的算法,两眼一看就能识别出不同来:这里我总结了一下差别(一个{x,y,z}是一个轨迹记录点,x代表x轴,y代表y轴,z代表累计时间毫秒):1.时间不宜太长又或者太短,最好能控制在1-5秒之内,另外两个相邻的记录点的时间也最好能控制在50ms以内,并且间隔的时间也不宜相同;2.乡邻的x值差值也不宜太大,最好控制在以5内,并且差值也不要是一层不变的;3.geetest虽然是横向拖动的,不会涉及到纵向移动,所以这部分很容易是被忽略的:y轴的值要控制在[-5,5]范围内,不能过大。而且上下抖动的频率不能高,要平缓一点。我试下来最好的办法就是平稳固定的0上,也不要上下抖动了。完整代码如下:#!/usr/local/bin/python# -*- coding: utf8 -*-'''Created on 日@author: PaoloLiu'''from selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitfrom mon.action_chains import ActionChainsimport PIL.Image as imageimport time,re,cStringIO,urllib2,randomdef get_merge_image(filename,location_list):
'''
根据位置对图片进行合并还原
:filename:图片
:location_list:图片位置
'''
im = image.open(filename)
new_im = image.new('RGB', (260,116))
im_list_upper=[]
im_list_down=[]
for location in location_list:
if location['y']==-58:
im_list_upper.append(im.crop((abs(location['x']),58,abs(location['x'])+10,166)))
if location['y']==0:
im_list_down.append(im.crop((abs(location['x']),0,abs(location['x'])+10,58)))
new_im = image.new('RGB', (260,116))
x_offset = 0
for im in im_list_upper:
new_im.paste(im, (x_offset,0))
x_offset += im.size[0]
x_offset = 0
for im in im_list_down:
new_im.paste(im, (x_offset,58))
x_offset += im.size[0]
return new_imdef get_image(driver,div):
'''
下载并还原图片
:driver:webdriver
:div:图片的div
'''
#找到图片所在的div
background_images=driver.find_elements_by_xpath(div)
location_list=[]
imageurl=''
for background_image in background_images:
location={}
#在html里面解析出小图片的url地址,还有长高的数值
location['x']=int(re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][1])
location['y']=int(re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][2])
imageurl=re.findall(&background-image: url\(\&(.*)\&\); background-position: (.*)px (.*)&,background_image.get_attribute('style'))[0][0]
location_list.append(location)
imageurl=imageurl.replace(&webp&,&jpg&)
jpgfile=cStringIO.StringIO(urllib2.urlopen(imageurl).read())
#重新合并图片
image=get_merge_image(jpgfile,location_list )
return imagedef is_similar(image1,image2,x,y):
'''
'''
pixel1=image1.getpixel((x,y))
pixel2=image2.getpixel((x,y))
for i in range(0,3):
if abs(pixel1[i]-pixel2[i])&=50:
return False
return Truedef get_diff_location(image1,image2):
'''
计算缺口的位置
'''
for i in range(0,260):
for j in range(0,116):
if is_similar(image1,image2,i,j)==False:
idef get_track(length):
'''
根据缺口的位置模拟x轴移动的轨迹
'''
间隔通过随机范围函数来获得
x=random.randint(1,3)
while length-x&=5:
list.append(x)
length=length-x
x=random.randint(1,3)
for i in xrange(length):
list.append(1)
return listdef main():#
这里的文件路径是webdriver的文件路径
driver = webdriver.Chrome(executable_path=r&C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe&)#
driver = webdriver.Firefox()#
driver.get(&http://172.16.2.7:8000/&)#
等待页面的上元素刷新出来
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_slider_knob gt_show']&).is_displayed())
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_cut_bg gt_show']&).is_displayed())
WebDriverWait(driver, 30).until(lambda the_driver: the_driver.find_element_by_xpath(&//div[@class='gt_cut_fullbg gt_show']&).is_displayed())#
image1=get_image(driver, &//div[@class='gt_cut_bg gt_show']/div&)
image2=get_image(driver, &//div[@class='gt_cut_fullbg gt_show']/div&)#
计算缺口位置
loc=get_diff_location(image1, image2)#
生成x的移动轨迹点
track_list=get_track(loc)#
找到滑动的圆球
element=driver.find_element_by_xpath(&//div[@class='gt_slider_knob gt_show']&)
location=element.location#
获得滑动圆球的高度
y=location['y']#
鼠标点击元素并按住不放
print &第一步,点击元素&
ActionChains(driver).click_and_hold(on_element=element).perform()
time.sleep(0.15)
print &第二步,拖动元素&
track_string = &&
for track in track_list:
track_string = track_string + &{%d,%d},& % (track, y - 445)#
xoffset=track+22:这里的移动位置的值是相对于滑动圆球左上角的相对值,而轨迹变量里的是圆球的中心点,所以要加上圆球长度的一半。#
yoffset=y-445:这里也是一样的。不过要注意的是不同的浏览器渲染出来的结果是不一样的,要保证最终的计算后的值是22,也就是圆球高度的一半
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=track+22, yoffset=y-445).perform()#
间隔时间也通过随机函数来获得
time.sleep(random.randint(10,50)/100)
print track_string#
xoffset=21,本质就是向后退一格。这里退了5格是因为圆球的位置和滑动条的左边缘有5格的距离
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-445).perform()
time.sleep(0.1)
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-445).perform()
time.sleep(0.1)
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-445).perform()
time.sleep(0.1)
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-445).perform()
time.sleep(0.1)
ActionChains(driver).move_to_element_with_offset(to_element=element, xoffset=21, yoffset=y-445).perform()
print &第三步,释放鼠标&#
ActionChains(driver).release(on_element=element).perform()
time.sleep(3)#
submit=driver.find_element_by_xpath(&//input[@id='embed-submit']&)
ActionChains(driver).click(on_element=submit).perform()
time.sleep(5)driver.quit()if __name__ == '__main__':
main()运行结果:五.浏览器的兼容问题1.最为重要的就是代码注释里说的y轴的高度问题,我试了PhantomJS,Chrome和Firefox三个浏览器,每一种渲染出来的高度都是不一样的,一定要保证最终的结果是拖动球高度的一半(一般都是22);2.版权兼容性(以下是我验证过可行的):selenium (2.53.6)===&PhantomJS 2.1selenium (2.53.6)===&Chrome 52selenium (2.53.6)===&Firefox 45(注意不要用48,有兼容问题)3.webdriver的cookie问题:有的时候我们需要带入cookie进行验证,那就有了cookie的问题了。Chrome和Firefox都可以通过webdriver.add_cookie来实现,但是经我试下来这个方法和PhantomJS有兼容性问题,我是这样解决的:
def save_cookies(self, driver, file_path, inputcookie):#
LINE = &document.cookie = '{name}={value}; path={path}; domain={domain}; expires={expires}';\n&
dict_cookie = {}
for item in inputcookie.split(&;&):
dict_cookie[item.split(&=&)[0].strip()] = item.split(&=&)[1].strip()#
(dict_cookie)
with open(file_path, 'w') as file :
for cookie in driver.get_cookies() :#
if u'expires' in cookie:
if cookie['name'] in dict_cookie:
line = &document.cookie = '%s=%s; path=%s; domain=%s; expires=%s';\n& % (cookie['name'], dict_cookie[cookie['name']], cookie['path'], cookie['domain'], cookie['expires'])
line = &document.cookie = '%s=%s; path=%s; domain=%s; expires=%s';\n& % (cookie['name'], cookie['value'], cookie['path'], cookie['domain'], cookie['expires'])
if cookie['name'] in dict_cookie:
line = &document.cookie = '%s=%s; path=%s; domain=%s';\n& % (cookie['name'], dict_cookie[cookie['name']], cookie['path'], cookie['domain'])
line = &document.cookie = '%s=%s; path=%s; domain=%s';\n& % (cookie['name'], cookie['value'], cookie['path'], cookie['domain'])#
file.write(line.encode(&utf8&))
def load_cookies(self, driver, file_path):
with open(file_path, 'r') as file:
driver.execute_script(file.read())再如此调用就可以解决cookie的兼容性问题了:driver.get(url)# save the cookies to a fileself.save_cookies(driver, r&cookies.js&, cookies)# delete all the cookiesdriver.delete_all_cookies()# load the cookies from the fileself.load_cookies(driver, r&cookies.js&)# reopen urldriver.get(url)4.PhantomJS浏览器解析出来的图片url是不带引号的,而Firefox和Chrome解析出来的是带引号的,这里正则过滤的时候要注意一下的。我最终使用的是selenium+Firefox。我实际运行的环境是centos,PhantomJS确实是个不错的选择,直接在shell里运行就可以了,不需要配置图形界面。但是使用下来破解的成功率不高,因为没有界面,也看不出运行的情况。Chrome在centos6.5里面没有现成的安装包,安装使用比较复杂。最终也就只有Firefox了。centos配置firefox方法如下:[root@db2-test1 ~]# yum groupinstall &X Window System& -y[root@db2-test1 ~]# yum groupinstall &Desktop& -y[root@db2-test1 ~]# yum install firefox -y注意不要纯shell环境下运行,要在图形界面的运行。运行init 5可以从字符界面切换到图形界面。就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
欢迎转载:
推荐:    

我要回帖

更多关于 initgeetest 的文章

 

随机推荐