python抓取漫画(破解js)

闲着无聊看漫画,《镇魂街》,本来想等着动漫出来再看,等了好久也没出第二季,还是看漫画吧。

有的时候是不是会出现502,而且刷新的好慢,看的好烦躁,还是把动画下载下来吧,以前还在上学的时候,有使用python写过抓数据的demo,之前的比较简单,这次的稍微有点复杂,花了点时间写出来了,没有系统的学过python,所以写的肯定有点搓,哈哈,在这里做个备份,有什么优化的地方,可以评论提出来

百度搜索“镇魂街”,第一个链接,有妖气到50集就要VIP了,我也懒得管是不是要充钱才能看,就换了下面的仆飞漫画

点进去,首先肯定是根据这个连接 http://www.pufei.net/manhua/20/ 获取整个页面的html代码

    def get_content(self, url):
        ua = fake_useragent.UserAgent()
        headers = {
            'User_Agent': ua.random}
        response = requests.get(url, headers=headers)
        r = response.text
        a = r.encode('ISO-8859-1').decode(requests.utils.get_encodings_from_content(r)[0])
        return a

为了避免会被网站拦截请求,所以在请求头改变一下参数User_Agent,也不知道管不管用,哈哈

这里使用了request和fake_useragent库,需要import一下

import fake_useragent
import requests

还需要注意的时候,获取下来的html中文会乱码,所以需要重新编码再解码,代码很容易看懂,不多解释

接着要获取章节的名称,分析一下html的格式,我使用的是bs4来解析这个页面,然后通过css选择器获取这个div,然后遍历所有的li标签,再获取a标签,就可以拿到href连接了,注意这里的连接是相对路径,需要拼上网站的域名

代码像这样

    def get_page_chapter(self, url, dir_path):
        content = self.get_content(url)
        sel = bs4.BeautifulSoup(content, 'lxml')
        div = bs4.BeautifulSoup(str(sel.select_one('.max-h200')), 'lxml')
        for li in div.find_all("li"):
            a_url = li.find("a")
            if a_url:
                url = a_url.get("href")
                self.download_chapter('http://www.pufei.net' + url, a_url.get_text(), dir_path)

最最关键的来了,正常情况下,获取到章节的地址就可以获取到图片信息了,但是这个网站不是这么做的,这个网站是通过js动态的请求图片获取的,所以说单独的获取当前页面的内容是获取不到图片信息的

 

既然是动态的加载图片,肯定需要通过css选择器获取到图片的这个div,图片的这个div的class是viewimages,打开浏览器的调试功能,在网络那里搜索一下这个关键字看看,可以看到在view.js的这个文件加载图片的,继续找img标签的src属性

 

可以看到需要用到photosr这个数组的,不过初始化的代码不在这个文件中,继续全局搜索

可以看到这个变量是在下图的这个位置这里定义的,也就是进入当前章节页面就初始化了,继续搜索发现没有哪个地方是给这个变量赋值的,坑爹!!!

不过注意到下面有个packed常量,猜测可能是初始化photosr这个变量的

这么长一串的东西也不知道是啥,一开始尝试将js代码改成python来写,发现不好弄,放弃了,改用python的execjs库来调用js,将这段js全部复制下面,注意有个base64decode方法有用到,一起复制下面,因为这段代码是初始化photosr这个变量的,所以最终结果需要返回这个变量

var photosr = new Array();

function base64decode(str) {
    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
    var c1, c2, c3, c4;
    var i, len, out;
    len = str.length;
    i = 0;
    out = "";
    while (i < len) {
        do {
            c1 = base64DecodeChars[str.charCodeAt(i++) & 255]
        } while (i < len && c1 == -1);
        if (c1 == -1) {
            break
        }
        do {
            c2 = base64DecodeChars[str.charCodeAt(i++) & 255]
        } while (i < len && c2 == -1);
        if (c2 == -1) {
            break
        }
        out += String.fromCharCode((c1 << 2) | ((c2 & 48) >> 4));
        do {
            c3 = str.charCodeAt(i++) & 255;
            if (c3 == 61) {
                return out
            }
            c3 = base64DecodeChars[c3]
        } while (i < len && c3 == -1);
        if (c3 == -1) {
            break
        }
        out += String.fromCharCode(((c2 & 15) << 4) | ((c3 & 60) >> 2));
        do {
            c4 = str.charCodeAt(i++) & 255;
            if (c4 == 61) {
                return out
            }
            c4 = base64DecodeChars[c4]
        } while (i < len && c4 == -1);
        if (c4 == -1) {
            break
        }
        out += String.fromCharCode(((c3 & 3) << 6) | c4)
    }
    return out
}

function f(data) {
    eval(eval(base64decode(data).slice(4)));
    return photosr
}

引入execjs库,执行代码如下,获取到这个章节的所有漫画的连接,这里获取到的一样是相对地址,下面使用的时候需要拼上域名

import execjs
    def get_js(self):
        f = open("base64decode.js", 'r', encoding='utf-8')
        line = f.readline()
        html_str = ''
        while line:
            html_str = html_str + line
            line = f.readline()
        return html_str

    def base_64_decode(self, data):
        js_str = self.get_js()
        ctx = execjs.compile(js_str)
        return ctx.call('f', data)

 

由于每个章节的packed肯定是不一样的,所有需要使用正则表达式截取这个变量,注意需要导入re库,代码像这样

search_obj = re.findall(r'packed="(.+)";eval', content, re.S)

已经获取图片的地址了,接下来就比较简单了,只需要下载到本地就好了,代码如下

    def get_image(self, img_urls):
        response = requests.get(img_urls)
        if response.status_code == 200:
            return response.content

    def download_chapter(self, url, chapter_name, dir_path):
        content = self.get_content(url)
        search_obj = re.findall(r'packed="(.+)";eval', content, re.S)
        count = 1
        for url2 in self.base_64_decode(search_obj[0]):
            if isinstance(url2, str):
                if url2:
                    image_path = dir_path + '/' + chapter_name + '/P-%s.jpg' % count
                    if not os.path.exists(dir_path + '/' + chapter_name):
                        os.makedirs(dir_path + '/' + chapter_name)
                    if not os.path.exists(image_path):
                        image = self.get_image("http://res.img.pufei.net/" + url2)
                        if image:
                            with open(image_path, 'wb') as f:
                                f.write(image)
                                count += 1

为了避免图片乱序,所有将图片的名称改为P-xx,这样漫画的顺序就不会乱了

调用的主函数如下:

from DownloadPage import *

url = "http://www.pufei.net/manhua/20/"
save_path = "F:/dongman"

downloadPage = DownloadPage()
content = downloadPage.get_page_chapter(url, save_path)

效果如下:

python版本用的是3.7

代码github地址:https://github.com/justdrinkWater/downloadCartoon

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值