某网站防爬虫/防盗资源的实现和破防

逛某漫画站,有想弄个爬虫把图片爬下来的想法。

但发现该站的原图是被做了切割的。如果找图片链接,直接下载,是这个样子的:

眼好花是不?而实质上网站显示的图片是这个样子:

挺有意思的,估计该网站这样设计,是防爬虫或者防盗其资源吧。

可以知道其切割逻辑:

如果直接下载图片,图片就是右图那个鸟样。

通过开发者工具看看元素,发现该img 的style="visibility: hidden;",下面多了一个画布 canvas,如下:

大概可以知道该网站的思路了:网站预先把图片切割好,生成倒叙切片图片(切多少片不固定),前端通过脚本加载图片后,再把图片切片,用正确的顺序把片段draw 到画布上。

模拟该网站的实现

为什么要模拟它?没有为什么,就是写着玩玩。

直接上一个html 代码,为了简便,直接把js也写里面了。

大概就是这样:

xml 复制代码
<!DOCTYPE html>
<head>
    <title>拆分图片</title>
</head>
<body>
    <div id="container">
        <img src="./00001.webp" id="album_photo_00001" style="visibility: hidden;">
    </div>
</body>

<script>
    // 实质使用上会单独到另一个文件(并且混淆),这里演示方便,扔这了。    
    function draw_image(canvas, image) {
        var count = 8; // 实际上 count 是根据某些规则,这里演示,直接写死

        var image_w = image.width;
        var image_h = image.height;
        var frame_h = image.height/count;

        // 倒叙摆放,把它转回来
        for (var i = 0; i < count; i++) {
            var start_h = frame_h * (count - i -1);
            context.drawImage(image, 0, start_h, image_w, frame_h, 0, frame_h * i, image_w, frame_h);
        }
    }

    window.onload = function() {
        // 加载图片
        var image = new Image();
        image.src = document.getElementById("album_photo_00001").src;

        // 创建画布
        var canvas = document.createElement("canvas");
        canvas.setAttribute('width', image.width);
        canvas.setAttribute('height', image.height);

        context = canvas.getContext("2d") ;

        draw_image(canvas, image);

        var container = document.getElementById("container");
        container.appendChild(canvas);
    }
</script>
</html>

运行效果:

图片的破防的思路

demo可以固定切片数,但爬虫应该如何知道切片数?

分析该网站js代码,会发现有个函数计算它(根据"漫画id 和图片id"来计算),虽然这段代码被混淆了,但有前端分析功底的伙伴这个不是难事。

本文说说求得切片数的另一个思路。

由于图片是被均匀的横向切割再拼接的,所以图片会有明显的横行线条,这不,就可以用openCV 对其进行横向线条获取和分析了?!

步骤就是用 Canny 检测边缘,之后通过HoughLinesP 检测线条,过滤非水平线即可。

ini 复制代码
img = cv.imread("00001.webp")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)

for line in cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=10, maxLineGap=1000):
    x1,y1,x2,y2 = line[0]
    angle = np.degrees(np.arctan2(y2 - y1, x2 - x1))
    if abs(angle) > 1:
        continue

    cv.line(img, (x1,y1), (x2,y2), (0,255,0), 2)

如下,openCV 识别横向线条(画出绿色线标注)效果:

有了这些线条,便可对它们进行聚合整理(再做些基本的校验),不难得出切割的图片数多少。

识别出线条数,便可知道切片多少了(如上图,线条整合就是七束,也就是八块)。后面几乎就等价于用python 把上面js 写一遍,再保存新图片即可。

还原图片代码:

ini 复制代码
import cv2 as cv
import numpy as np

img = cv.imread("00001.webp")

emptyImage = np.zeros(img.shape, np.uint8)

# 根据识别结果填充,测试所以写定了。
count = 8

image_h, image_w, frame_h = img.shape[0], img.shape[1], int(img.shape[0] / count)

for i in range(count):
    img_offset_y = i * frame_h
    result_offset_y = (count - 1 - i) * frame_h

    # 倒叙还原过来
    for y in range(frame_h):
        for x in range(image_w):
            emptyImage[img_offset_y + y, x] = img[result_offset_y + y, x]

cv.imwrite("result.png", emptyImage)

完整的爬站代码就不上了,本文主要是说说思路,有编程功底的看官,稍微整理下,整合一个防破的爬虫代码不是啥难事。

相关推荐
Mr Aokey29 分钟前
Spring MVC参数绑定终极手册:单&多参/对象/集合/JSON/文件上传精讲
java·后端·spring
水银嘻嘻32 分钟前
05 APP 自动化- Appium 单点触控& 多点触控
python·appium·自动化
狐凄37 分钟前
Python实例题:Python计算二元二次方程组
开发语言·python
地藏Kelvin1 小时前
Spring Ai 从Demo到搭建套壳项目(二)实现deepseek+MCP client让高德生成昆明游玩4天攻略
人工智能·spring boot·后端
烛阴2 小时前
Python枚举类Enum超详细入门与进阶全攻略
前端·python
菠萝012 小时前
共识算法Raft系列(1)——什么是Raft?
c++·后端·算法·区块链·共识算法
长勺2 小时前
Spring中@Primary注解的作用与使用
java·后端·spring
武子康2 小时前
AI炼丹日志-28 - Audiblez 将你的电子书epub转换为音频mp3 做有声书
人工智能·爬虫·gpt·算法·机器学习·ai·音视频
小奏技术3 小时前
基于 Spring AI 和 MCP:用自然语言查询 RocketMQ 消息
后端·aigc·mcp
编程轨迹3 小时前
面试官:如何在 Java 中读取和解析 JSON 文件
后端