python爬虫爬取某漫画网站并解决图片切割逆序问题

前言

每次看本都要进入某网站,这实在是太麻烦了。正好学过点爬虫,不勤加练习恐荒废知识。分析了网页,编写好程序。运行一看,一些漫画居然有防爬,即将图片切割成若干部分并逆序拼接,且每张图片切割数量不尽相同。正当要放弃之时,看到一篇文章,使我醍醐灌顶。

正文

网页分析

直接进入某漫画主页,F12打开开发者工具,找到图片位置html,如下图

由此可以发现图片链接都是放在img标签中,我们从这便可获取图片链接

代码编写

1.库介绍

首先介绍需要用到的python库,如下

import requests
import re
from io import BytesIO
from PIL import Image
import os
import shutil
import hashlib

requests库用于网页源码,re用于正则表达式获取网页源码中的图片链接,io和PIL用于处理图片,

os和shutil用于文件夹操作

2.开始编写

先从获取图片链接开始,代码如下

#获取所有图片链接,漫画名称和id
def get_photo_url(url: str):
    r = requests.get(url)
    results = re.findall(r'data-original="(https://.*)"', r.text)
    name = re.search(r'<div class="pull-left">(.*)</div>', r.text).group(1).replace("!", "").replace("?", "")
    id = re.search(r".*/(.*)", url).group(1)
    print(name)
    return results, name, id

使用get获取网页源码,然后用正则表达式获取图片链接(列表存放),漫画名称,漫画id

之后通过图片链接将图片保存至本地,代码如下

#保存
def save(results: list, path: str, is_slice: bool, id: str):
    for result in results:
        filename = re.search(r".*/(.*)\.", result).group(1)#获取图片页码作为文件名
        print(filename)
        resp = requests.get(result)
        byte_stream = BytesIO(resp.content)
        im = Image.open(byte_stream)
        # im.show()
        if im.mode == "RGBA":       #这段是cv的不知道干嘛用的
            im.load()  # required for png.split()
            background = Image.new("RGB", im.size, (255, 255, 255))
            background.paste(im, mask=im.split()[3])

        if is_slice:  #如果图片是切割过的,则处理一下
            im = handle_img(filename, id, im)

        im.save(f'{path}/{filename}.jpg', 'JPEG')

如果图片是切割过的,则调用handle_img方法,如下

#处理切割图片
def handle_img(filename, id, im):
    width, height = im.size
    n = get_num(id, filename)
    new_im = Image.new("RGB", im.size)
    im_parts = []
    for i in range(n):
        if i == n - 1:
            part = im.crop((0, i * int(height / n), width, height))
        else:
            part = im.crop((0, i * int(height / n), width, (i + 1) * int(height / n)))
        im_parts.append(part)
    last_height = 0
    for i in im_parts[::-1]:
        new_im.paste(i, (0, last_height))
        last_height += i.height

    return new_im


#计算图片切割次数,参数为id和页码(例如第一页,00001)
def get_num(id: str, page_num: str):
    a = 10
    if int(id) >= 268850:
        n = str(id) + page_num
        n = hashlib.md5(str(n).encode()).hexdigest()
        n = n[-1]
        n = ord(n) % 10
        if n < 10:
            a = (n + 1) * 2
    return a

其中get_num方法用于获取图片的切割次数,因为每张图片的切割次数不尽相同,其中id和页码均为字符串。思路参考文章

此程序有个不足,暂未找到区分漫画是否切割的方法,只能自行判断,is_slice为标志,true即为该漫画切割过

3.完整代码

仅供参考

import requests
import re
from io import BytesIO
from PIL import Image
import os
import shutil
import hashlib


#创建文件夹
def mkdir(name) -> str:
    path = f"./manga/{name}"
    folder = os.path.exists(path)

    if folder:  # 判断是否存在文件夹如果存在则删除文件夹
        shutil.rmtree(path)
    os.makedirs(path)  # makedirs 创建文件夹
    return path


#获取所有图片链接,漫画名称和id
def get_photo_url(url: str):
    r = requests.get(url)
    results = re.findall(r'data-original="(https://.*)"', r.text)
    name = re.search(r'<div class="pull-left">(.*)</div>', r.text).group(1).replace("!", "").replace("?", "!")
    id = re.search(r".*/(.*)", url).group(1)
    print(name)
    return results, name, id

#计算图片切割次数,参数为id和页码(例如第一页,00001)
def get_num(id: str, page_num: str):
    a = 10
    if int(id) >= 268850:
        n = str(id) + page_num
        n = hashlib.md5(str(n).encode()).hexdigest()
        n = n[-1]
        n = ord(n) % 10
        if n < 10:
            a = (n + 1) * 2
    return a

#保存
def save(results: list, path: str, is_slice: bool, id: str):
    for result in results:
        filename = re.search(r".*/(.*)\.", result).group(1)
        print(filename)
        resp = requests.get(result)
        byte_stream = BytesIO(resp.content)
        im = Image.open(byte_stream)
        # im.show()
        if im.mode == "RGBA":       #这段是cv的不知道干嘛用的
            im.load()  # required for png.split()
            background = Image.new("RGB", im.size, (255, 255, 255))
            background.paste(im, mask=im.split()[3])

        if is_slice:  #如果图片是切割过的,则处理一下
            im = handle_img(filename, id, im)

        im.save(f'{path}/{filename}.jpg', 'JPEG')

#处理切割图片
def handle_img(filename, id, im):
    width, height = im.size
    n = get_num(id, filename)
    new_im = Image.new("RGB", im.size)
    im_parts = []
    for i in range(n):
        if i == n - 1:
            part = im.crop((0, i * int(height / n), width, height))
        else:
            part = im.crop((0, i * int(height / n), width, (i + 1) * int(height / n)))
        im_parts.append(part)
    last_height = 0
    for i in im_parts[::-1]:
        new_im.paste(i, (0, last_height))
        last_height += i.height

    return new_im


url = ""      #漫画主页面链接
results, name, id = get_photo_url(url)
path = mkdir(name)
save(results, path, is_slice=True, id=id)

成果展示

参考

参考文章

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值