前言由于最近爬虫项目遇到行为效验,导致项目下游相关业务版块进入暂停运营阶段,于是我就大致分析了下解决大致方案。
好在之前有过处理类似的业务项目,然后我又在网上找了一些相关的资料,嘿嘿嘿~
你们是遇到对手了~
涉及编程语言:PHP、JavaScript 大致处理思路:通过二值化图像,找出横向图像中,纵列区间段占颜色均值最高的缺口图片。
此文干货较长,若与笔者见解不一致,欢迎随时留言。
关于图片的处理首先分析出目标站点接口返回的数据,在给出的所有行为效验数据中。笔者通过分析,服务端回传给客户端的行为效验数据,只有:纵坐标位置,及效验的背景缺口底图和滑动图片。 而客户端只要对滑动图片和背景缺口底图进行拼合,再有客户端发起封包向服务端对做数据效验(滑动轨迹、滑动图片停止的横向位置、客户端会话、客户端ip)等。 如下是笔者对滑动图片的处理流程 1、载入 滑动背景底图
2、载入滑动拖动图片3、加载图片信息(宽高)通过PHP的GD图像处理库,对上述的两个图片信息的宽高进行获取,见下图 调用示列
相关代码图片信息
4、标记纵坐标位置至此“我们”在每次切入重心点先从“滑动图片”纵向位置为主要下手点。 缺口位置纵向高度
5、分割滑动背景底图图片以横向起点0,到背景缺口底图的最大宽度为终点。截取出“主要的分析图片”的,以纵向位置为起点向“滑动图片”的高度区域为终点做出图片截取,见下图所示。 提取主要图片内容
6、灰度分割后的图片[color=var(--themecolor)]灰度数字图像是每个像素只有一个采样颜色的图像。这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑白两种颜色,灰度图像在黑色与白色之间还有许多级的颜色深度。 灰度后台的图片
php图片转灰度算法
| /** |
| * 设置->图片灰度 |
| * |
| * @param mixed $ResourceImage 资源图片 |
| * |
| * @Return resource |
| */ |
| protected final function setGray($ResourceImage) { |
| $img_width = ImageSX($ResourceImage); |
| $img_height = ImageSY($ResourceImage); |
| for ($y = 0; $y < $img_height; $y++) { |
| for ($x = 0; $x < $img_width; $x++) { |
| $gray = ( imagecolorat($ResourceImage, $x, $y) >> 8 ) & 0xFF; |
| imagesetpixel($ResourceImage, $x, $y, imagecolorallocate($ResourceImage, $gray, $gray, $gray)); |
| } |
| } |
| return $ResourceImage; |
| } |
7、二值化图片图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。调整对应“阈值”数值。让图像上的块色域更能明显突出。
php图片转二值化算法
| /** |
| * 获取指定位置颜色值 |
| * |
| * @param mixed $ResourceImage 图片资源 |
| * @param int $X 横向坐标 |
| * @param int $Y 纵向坐标 |
| * |
| * @return array |
| */ |
| protected final function getPicturePositionRgbColor($ResourceImage, int $X, int $Y) { |
| $rgb = imagecolorat($ResourceImage, $X, $Y); |
| $r = ( $rgb >> 16 ) & 0xFF; |
| $g = ( $rgb >> 8 ) & 0xFF; |
| $b = $rgb & 0xFF; |
| return [$r, $g, $b]; |
| } |
| |
| /** |
| * 设置->图片二值化 |
| * |
| * @param mixed $ResourceImage 图片资源 |
| * @param int $Threshold 阈值 |
| */ |
| protected final function setImageBinarization($ResourceImage, int $Threshold) { |
| //图片->宽度 |
| $image_width = imagesx($ResourceImage); |
| //图片->高度 |
| $image_height = imagesx($ResourceImage); |
| //遍历横向区域 |
| for ($i = 1; $i <= $image_width; $i++) { |
| //遍历纵向区域 |
| for ($j = 1; $j <= $image_height; $j++) { |
| //取出图片颜色 |
| [$r, $g, $b] = $this->getPicturePositionRgbColor($ResourceImage, $i, $j); |
| //三色求平均值 |
| $avg = ( $r + $g + $b ) / 3; |
| //对像素点设置指定颜色 |
| imagesetpixel($ResourceImage, $i, $j, $avg >= $Threshold ? imagecolorallocate($ResourceImage, 255, 255, 255) : 0); |
| } |
| } |
| } |
关于图片的数据分析按上述流程执行完后,在对底图横向每一格的像素纵列求出列“颜色均值”,并把对应的数据以可观的分析图展示出来。 二值化后的分析图
从上述图中可以看到醒目的红色标记块,从这个过程,我们就可以找出适应的“阈值”,来让处理的二值化图片更醒目,也能让后续算法的工作量更少,从而达到识别出横向位置所在具体区域。 PHP求出图片横向每一格纵列“RGB颜色均值”算法
| |
| /** |
| * 获取->求出图片横向每一格纵列“RGB颜色均值”算法 |
| * |
| * @param mixed $ResourceImage 图片资源 |
| * |
| * @return array |
| */ |
| protected final function getImageHorizontalPxRgbArray($ResourceImage): array { |
| //图片->宽度 |
| $image_width = imagesx($ResourceImage); |
| //图片->高度 |
| $image_height = imagesx($ResourceImage); |
| |
| |
| $horizontalArray = []; |
| //遍历横向区域 |
| for ($i = 1; $i <= $image_width; $i++) { |
| //累计值 |
| $sum = 0; |
| //遍历纵向区域 |
| for ($j = 1; $j <= $image_height; $j++) { |
| //取出图片颜色 |
| [$r, $g, $b] = $this->getPicturePositionRgbColor($ResourceImage, $i, $j); |
| //三色求平均值 |
| $avg = ( $r + $g + $b ) / 3; |
| //累加均值 |
| $sum += $avg; |
| } |
| //该纵向列的总和在除以图片的高度,即得出纵列“RGB颜色均值” |
| $horizontalArray[] = $sum / $image_height; |
| } |
| return $horizontalArray; |
| } |
如何通过算法,获取横向坐标缺口位置?横向每一格纵列“RGB颜色均值”求出来后,经过笔者分析,切入重点可以放在每次横向每一格像素点往右移动“滑动图片宽度距离”,并在此移动过程中,计算并记录出区域的总值,并把最后的答案设为answerPosition,大致思路如下图。 PHP算法
| /** |
| * 获取->答案位置 |
| * |
| * @param array $VerticalArrayData 纵向数组数据 |
| * @param int $SlideImageWidth 滑动图片宽度 |
| * |
| * @return int |
| */ |
| protected final function getAnswerPosition(array $VerticalArrayData, int $SlideImageWidth): int { |
| // |
| $answerArr = []; |
| //纵向长度 |
| $vertical_len = count($VerticalArrayData); |
| //遍历横向 |
| for ($i = 1; $i <= $vertical_len; $i++) { |
| $sum = 0; |
| //计算区域宽度 |
| $calc_area_width = $i + $SlideImageWidth; |
| //判断当前计算区域宽度是否大于总长度 |
| if ($calc_area_width > $vertical_len) { |
| //取出可计算的宽度 |
| $tempWidth = $vertical_len - $i; |
| } else { |
| //赋值可计算的区域宽度 |
| $tempWidth = $SlideImageWidth; |
| } |
| if ($tempWidth <= 0) continue; |
| //遍历滑动图片区域颜色均总值 |
| for ($j = 1; $j <= $tempWidth; $j++) { |
| //累加该区域颜色均值 |
| $sum += $VerticalArrayData[$i + $j] ?? 0; |
| } |
| //记录位置 |
| $answerArr[] = [ |
| 'x' => $i, |
| 'v' => $sum, |
| ]; |
| } |
| //找出颜色最大范围横向位置(找大小) |
| $ansIndex = $ansXValue = 0; |
| foreach ($answerArr as $k => $v) { |
| if ($ansXValue <= $v['v']) { |
| $ansIndex = $k; |
| $ansXValue = $v['v']; |
| } |
| } |
| //返回答案所在横向坐标 |
| return $ansXValue[$ansIndex]['x']; |
| } |
关于真人滑动的数据分析在浏览器客户端进行行为效验滑动操作过程中,经过分析,用户每一次向左或者向右滑动数组数据结构体大致如下: 从前文概述中,我们已经知道“纵向坐标位置”是已知参数,而“横向坐标位置”是需要通过一定的技术算法获取出答案位置,所停留的时间,这块则是需要当前时间加上随机数字做累加处理。至此为大概求解思路分析完毕。 通过技术手段抓取的真实滑动轨迹数据分析折线图,笔者依次按快、中、慢做如下截图展示: 快中慢从上述三个折线分析图中,依次能看出部分滑动轨迹数据的变化,而每次滑动的范围长度是不定的,这里我们设为随机N。 X坐标则是处于一个缓慢上升的阶段,中间部分有一小段数据快速增高,后继部分续保持平匀速增加。那么这里生成的X坐标数据思路,笔者这里的构思算法是 startX=rand(200,230); endX=startX+answerPosition+rand(10,20); Y坐标非常明显,几乎处于平衡线,但是细看数据,有一小部分数据还是有变动的,那么我们既可以对该参数值设定一个初始值,然后每次生成数据做随机小范围的累加或者累减,笔者这里设定是-2到3。 timeStamp在快和中的滑动分析图中,可以明显看出增长弧度非常平缓,而慢滑动则是梯阶速度增加。笔者这里选择参考范围值,是慢滑动生成数据,即随机范围值在3到20的每次累加。
如何让算法伪造滑动数据通过前面的讲解思路,我们已知:N、startX、endX、Y和timeStamp的随机范围值;最后通过率较高灵魂滑动算法生成的图如下: 伪造滑动轨迹分析图PHP算法
| /** |
| * 创建滑动原始数据 |
| * |
| * @param int $EndPosition 结束位置 |
| * |
| * @return array |
| */ |
| public final function createSlideRawData(int $AnswerPosition): array { |
| //移动轨迹记录 |
| $track = []; |
| //当前横向位移初始位置 |
| $currentX = rand(200, 230); |
| //当前纵向位移初始位置 |
| $currentY = rand(190, 200); |
| //当前起始停留时间 |
| $timeStamp = rand(5, 15) * 100; |
| //结束位置 |
| $EndPosition = $currentX + $AnswerPosition+ rand(10, 20); |
| //减速阈值 |
| $mid = $EndPosition * ( 4 / 5 ); |
| //计算间隔 |
| $t = 0.5; |
| //初始速度 |
| $v = 0; |
| while ($currentX < $EndPosition) { |
| if ($currentX < $mid) { |
| #加速度为2 |
| $a = rand(1, 3); |
| } else { |
| //加速度为-3 |
| $a = rand(-2, 0); |
| } |
| $v0 = $v; |
| $v = $v0 + $a * $t; |
| //移动横坐标 |
| $move = $v0 * $t + 1 / 2 * $a * $t * $t; |
| //当前位移 |
| $currentX += $move; |
| |
| $track[] = round($currentX); |
| $track[] = $currentY += rand(-2, 3); |
| $track[] = $timeStamp += mt_rand(3, 20); |
| } |
| return $track; |
| } |
感谢您的观看,文中部分思路来之网络及朋友的部分技术指导。本文技术攻略若是对你有帮助,各位老爷们那就安排 “ 打赏+分享 ” 把~
转载请标明原处,谢谢。
|