阅读量: 304
由于最近爬虫项目遇到行为效验,导致项目下游相关业务版块进入暂停运营阶段,于是我就大致分析了下解决大致方案。
好在之前有过处理类似的业务项目,然后我又在网上找了一些相关的资料,嘿嘿嘿~
你们是遇到对手了~
涉及编程语言:PHP、JavaScript
大致处理思路:通过二值化图像,找出横向图像中,纵列区间段占颜色均值最高的缺口图片。
此文干货较长,若与笔者见解不一致,欢迎随时留言。
首先分析出目标站点接口返回的数据,在给出的所有行为效验数据中。笔者通过分析,服务端回传给客户端的行为效验数据,只有:纵坐标位置,及效验的背景缺口底图和滑动图片。
而客户端只要对滑动图片和背景缺口底图进行拼合,再有客户端发起封包向服务端对做数据效验(滑动轨迹、滑动图片停止的横向位置、客户端会话、客户端ip)等。
如下是笔者对滑动图片的处理流程
通过PHP的GD图像处理库,对上述的两个图片信息的宽高进行获取,见下图
调用示列
相关代码
图片信息
至此“我们”在每次切入重心点先从“滑动图片”纵向位置为主要下手点。
缺口位置纵向高度
以横向起点0,到背景缺口底图的最大宽度为终点。截取出“主要的分析图片”的,以纵向位置为起点向“滑动图片”的高度区域为终点做出图片截取,见下图所示。
提取主要图片内容
灰度数字图像是每个像素只有一个采样颜色的图像。这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑白两种颜色,灰度图像在黑色与白色之间还有许多级的颜色深度。
灰度后台的图片
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;
}
图像二值化( 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;
}
感谢您的观看,文中部分思路来之网络及朋友的部分技术指导。
转载请标明原处,谢谢。