氵:[教程向]如何扒陈叔叔的底裤



  • 下载霹雳霹雳漫画的技巧

    近段时间以来, 很多重要的百合漫画被霹雳霹雳收后宫了,于是得想办法把它下下来.
    很巧的是,这个漫画(以及很多其他的漫画),都是需要给钱的. 同时,陈叔叔对自己底裤的戒备是很高的,在陈叔叔眼皮地下抢漫画,难度很大.
    经过研究,我现在正式总结两种下载原图(不是饶某截图秘技)的方法.二楼开更



  • 首先,我来介绍一下在bilibili吧看到的方法,其方向是前端操作.
    打开开发界面,发现漫画内容是canvas节点,也就是说,他不是直接的img图片,是经过js处理的canvas.
    Screenshot_20201031_154133.png
    要获取canvas内容,经典的方法是通过ctx的getImageData函数.
    代码如下(不可用)

    var pic = document.querySelector("body > div.reader-layout.w-100.h-100.p-absolute.p-zero > div > div.reader-body.w-100.h-100.p-absolute.p-zero > div > div > div.images-container.p-zero.m-auto.double-page > div.view-container.p-relative.primary-image > div > canvas");
    var ctx = pic.getContext("2d");
    var img = ctx.getImageData();
    

    如果你老实地敲了这些代码,恭喜你,能看到以下结果:
    Screenshot_20201031_154814.png
    没错,陈叔叔改了__proto___的很多内容,让你不能正常地获取漫画内容.

    bilibili的大佬们发现,直接获取pic对象的 toDataURL也是不行的,前面说了,陈叔叔改了一些东西.

    var b64data = pic.toDataURL()
    

    Screenshot_20201031_155450.png

    到这种情况,需要想的是如何解决prototype被陈叔叔改的问题.



  • 不错的教程,围观ing



  • bilibili吧的朋友们发现了一个方法,重新赋值prototype:
    比如:

    pic.__proto__ = open().window.HTMLCanvasElement.prototype
    

    这样一来,canvas对象就重新有了toDataURL函数了:
    Screenshot_20201031_161645.png
    这类方法套路都是一样的重新赋值__proto__. 在前端与陈叔叔周旋.不过呢,要实现下载逻辑相对会比较复杂.



  • 那么,接下来介绍的是第二种方法,比较适合不依赖浏览器(包括无头浏览器)的情况下批量下载漫画.
    这种路线主要是靠分析打开网页过程中的所有请求和返回,理清获得最终图片的逻辑. 然后再在程序/脚本中复现这个逻辑.
    这样就比较适合使用golang, java, python等等语言中实现漫画下载. 同时不需要webkit.



  • 这是刷新页面的请求列表,可以看出开头的页面几乎不含任何内容,所有内容全部是靠ajax获取显示的.一般这种网站,获取内容就要模仿ajax的行为.
    Screenshot_20201031_162623.png
    不愧是你霹雳霹雳员工



  • 霹雳霹雳漫画网页版的很多重要数据是靠post请求而不是get请求,一些重要的数据放在post data里面,比如漫画id等等.
    这是第一个重要的post:获取漫画详细信息

    curl 'https://manga.bilibili.com/twirp/comic.v1.Comic/ComicDetail?device=pc&platform=web' \
      -H 'content-type: application/json;charset=UTF-8' \
      --data-binary '{"comic_id":28419}' \
      --compressed
    

    获取的是漫画的信息
    Screenshot_20201031_163652.png

    注意,这个请求是不需要cookie的,说明这属于公开信息. 只需要最基本的请求头,地址和post数据就可以获得.
    漫画的详细信息包括了每一话的全局id,这个id很重要.



  • 第二个:获取某话的信息

    $ curl 'https://manga.bilibili.com/twirp/comic.v1.Comic/GetEpisode?device=pc&platform=web' \
      -H 'content-type: application/json;charset=UTF-8' \
      --data-binary '{"id":494148}' \
      --compressed | jq .
    
    {
      "code": 0,
      "msg": "",
      "data": {
        "title": "如月站救出美军作战Ⅵ",
        "comic_id": 28419,
        "short_title": "第29话",
        "comic_title": "里世界郊游"
      }
    }
    


  • 第三,获取某话的所有图片链接:

    $ curl -s 'https://manga.bilibili.com/twirp/comic.v1.Comic/GetImageIndex?device=pc&platform=web' \
      -H 'content-type: application/json;charset=UTF-8' \
      -H $'cookie: SESSDATA=***********; ' \
      --data-binary '{"ep_id":494148}' \
      --compressed | jq .
    {
      "code": 0,
      "msg": "",
      "data": {
        "path": "/bfs/manga/28419/494148/data.index.8cc1d4d1?token=9ccee98c40e819ad4790406e90beb8f2&ts=5f9d5c7e",
        "images": [
          {
            "path": "/bfs/manga/80d03bb04002b8c9dd64098b1e1e65f6b87bef8a.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/5910cea20c094148d4bd23629116d7a6c8aeb017.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/8b7a534a3dbdfea21d626b73cb1a1131cf7581cf.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/884d580276337ede65f361b07566de2b0e5c2c28.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/f8d4129ebdc3c223531c71262901c90421c2e2a0.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/5ce4708140a3b070165c49e2712fca7d75dc8623.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/d9ad823ce08faaece723a35271c4c01c065c84a9.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/bacec90de946b77a4f962a68b64c28a9b6746997.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/22aa582287bf1576740db2570b2c77427f3cbf12.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/68090af7508a1c5c2b83d9cf35937dde65418187.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/37537b39ab3ec13976afec89b6b82e2f11b4299b.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/6e52941f5b474b06254c965b733f470401846640.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/6cc137380ac0d8db42c2f4c75cbb9024f9cb6120.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/08d03b31177c32e97c1073bcf49788c290da8a44.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/4984f7a5b6d0d802e1c5c63f02cd64d72af33452.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/963075384d4044242b5a618469a2ca01f3c8c52c.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/95ba9add1663d20a68d511fdc4da7ec5980cd829.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/d035ae1f96c89e1417d0cffd5dc9ce3ce2093fb3.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/67aa447322f3c0b5575b82cdf787744c9921afe7.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/299027fdea5013a6d845f669bce526d5b02e996d.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/415b986d3ba44142fb63ced58b1ca83c56a3cd8c.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/34277edd8dca6435db94b0cb01c61de697d486c4.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/79e35b2d6b53b39c13e6fa91dfe84e5f71e5d8cd.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/2b5391b0999f11dcd1bfe0e5bb3e7e364930b3b7.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/abb9e880b26a67d2cee7a0dd7c66b610407f6978.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/99d0c8c12a48d094f81c3feabc99da2eb368a100.jpg",
            "x": 1800,
            "y": 2628
          },
          {
            "path": "/bfs/manga/00aaf518d7f8dd85ff734dc24ae885a11428fdd1.jpg",
            "x": 1800,
            "y": 2559
          }
        ],
        "last_modified": "2020-10-09 18:53:52",
        "host": "https://manga.hdslb.com"
      }
    }
    

    这里获取的是某一话(具有全局唯一的id?)的所有图片的链接,注意, 对于付费章节,需要cookie证明你买了相关章节,好比示例的这个,是付费章节.
    经验证,需要的cookie只需要SESSDATA.
    注意,有了图片地址还不行,需要针对每个图片申请token(需要cookie), 有了token才可以获取最终的漫画图片.



  • 第四,申请图片的token

    $ curl -s 'https://manga.bilibili.com/twirp/comic.v1.Comic/ImageToken?device=pc&platform=web' \
      -H 'content-type: application/json;charset=UTF-8' \
      -H $'cookie: SESSDATA=************' \
      --data-binary '{"urls":"[\"/bfs/manga/[email protected]\"]"}' \
      --compressed | jq .
    
    {
      "code": 0,
      "msg": "",
      "data": [
        {
          "url": "https://manga.hdslb.com/bfs/manga/[email protected]",
          "token": "cd7e076666a81844efb61d5d447e2149&ts=5f9d606d"
        }
      ]
    }
    
    

    注意:在付费章节一定要带cookie,不然最终是访问不到图片的



  • 最后一步是获取图片本身,好消息是,不管是付费内容还是免费内容,都不需要cookie了,毕竟能获得链接和token本身需要cookie

    $ curl -L -o pic.jpg 'https://manga.hdslb.com/bfs/manga/[email protected]?token=cd7e076666a81844efb61d5d447e2149&ts=5f9d606d'
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  494k  100  494k    0     0   142k      0  0:00:03  0:00:03 --:--:--  142k
    

    注意:token是有时限的



  • 然后我们得到了最终的图片:
    pic.jpg



  • 教程就到这个地方了, 基本的下载漫画的原理就讲完了. 各位朋友们都了解了吗?
    现在需要做的事情就是实现这些流程了!
    谢谢朋友们!


  • 百合爱好者

    可以按照思路写个爬虫,很不错的教程



  • 工具正在龟速实现中2B0189B2941098BB3DC6FBE3C6CB16F6.jpg

    qcomicd