爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)

这里写目录标题

  • 漫画爬虫之动态加载(外部加载)——以知音漫客为例
    • 思路
    • 提取目录及其URL
    • 获取漫画目录真正的URL
    • 获取每话的漫画内容
    • 保存图片
    • 综合代码

漫画爬虫之动态加载(外部加载)——以知音漫客为例

本文皆以《第一话上》为例
目标网站:知音漫客(请点击这里)
目标漫画:元尊(请点击这里)
链接失效就自己上网搜吧~
最后有详细代码和解释

思路

  1. 找到漫画目录并且拿到文字标题及其URL
  2. 找到每章节漫画的内容
  3. 保存漫画

提取目录及其URL

  1. 首先打开知音漫客找到元尊,然后检查页面元素(F12),找到目录的body:
    爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第1张图片

  2. 写代码把目录及其URL取出来

import requests
from bs4 import BeautifulSoup
import os


class downloader(object):  # 定义全局变量
    def __init__(self):
        self.url = 'https://www.zymk.cn/1966/'
        self.list_names = []
        self.list_urls = []

# 提取目录
    def get_name_url(self):
        req = requests.get(url=self.url)
        req.encoding = req.apparent_encoding
        reqhtml = BeautifulSoup(req.text, features='lxml')  
        reqhtml = reqhtml.find_all('ul', class_='chapter-list clearfix')  # 相当于正则表达式的效果
        bf = BeautifulSoup(str(reqhtml), features='lxml')
        a = bf.find_all('a')
        for one in a[::-1]:  # 结果是倒序的,要顺序的
            self.list_names.append(one.string)
            self.list_urls.append(self.url + one.get('href'))
        return self.list_urls, self.list_names


if __name__ == '__main__':
    down = downloader()
    down.get_name_url()

代码结果:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第2张图片爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第3张图片

获取漫画目录真正的URL

可以点击上面我们找到的URL,验证我们是否正确。
以第一话漫画为例:

这时我很高兴,我以为我找到了我想要的URL,获取该网页的源码:

import requests
from bs4 import BeautifulSoup
import os
import json
req = requests.get(url='https://www.kanman.com/105855/1hs.html')
print(req.text)

代码部分截图:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第4张图片
我们用Element里的图片URL和代码获取网页源码的图片URL是对应不上的,也访问不了,直接显示403,加上headers和from data也不行,这说明了我们要的内容URL不在这里。没有在HTML里找到的图片URL,那么它应该是动态加载的。
Network里找:

接下来是体力活了,只能一个个找,也不知道哪个才是我们想要的,最终我们锁定这个文件,它让我们看到了熟悉的东西,也可以实现访问,返回图片,这就是我们想要的:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第5张图片
就找第一张图片的URL去验证一下:
在这里插入图片描述
状态码:200,说明返回联通。现在我们找到了真正的URL:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第6张图片
URL里"?"之后的都是参数,给服务器检索信息等用的,这些参数可以在General这列最后可以找到:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第7张图片
观察多章漫画URL发现规律:只有“chapter_newid”这个参数是变化的,其它均不变,这个参数也正好对应“第几话”。这里有个陷阱,这部漫画的每一话又分上下话,特别到了后面的付费章节(可以爬付费章节,这我也没想到,居然没做反爬……),id更是千奇百怪,这是踩坑的经验,所以要拿到“chapter_newid”这个参数,我们只能回到Element那里寻找,也可以requests请求返回的content里找:
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第8张图片爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第9张图片
然后把这些章节的id抠出来替换URL里的就得到了每一话的漫画URL了。

获取每话的漫画内容

import requests
from bs4 import BeautifulSoup
import os
import json
import pprint

req = requests.get(url='https://www.kanman.com/api/getchapterinfov2?product_id=1&productname=kmh&platformname=pc&comic_id=105855&chapter_newid=1hs&isWebp=1&quality=middle')
pprint.pprint(req.json())  # json文件格式化输出
json_data = req.json()
pic_url = json_data["data"]["current_chapter"]["chapter_img_list"]  # 提得每话漫画里的每张图片url
name = json_data["data"]["current_chapter"]["chapter_name"]  # 提得每话漫画的题目
print(pic_url)
print(name)

如果不知道json文件的定义和怎么提取它里面的数据,自己找一下吧。
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第10张图片
爬虫实战之爬虫漫画(有意外发现哦~嘿嘿)_第11张图片
这样子我们就可以直接从请求图片url保存图片。

保存图片

for循环就可以了,具体看后面详细代码。值得注意的是图片格式不是常用的.jpg和.png等等,是.webp。这有点坑……

综合代码

import requests  # 请求url用的
from bs4 import BeautifulSoup  # 提取信息用的
import os  # 文件操作用的
import json
import pprint  # json文件格式化输出用的库


class downloader(object):  # 定义全局变量
    def __init__(self):
        self.url = 'https://www.zymk.cn/1966/'  
        self.unique = 1  # 防止文件名重复,作为序号使用,每次+1
        self.i = 0  # 遍历章节题目用的
        self.list_names = []  # 所有章节题目
        self.list_urls = []  # 所有章节url
        self.true_urls = []  # 所有章节真正的url

# 提取目录
    def get_name_url(self):
        req = requests.get(url=self.url)
        req.encoding = req.apparent_encoding  # 解决返回网页乱码问题
        reqhtml = BeautifulSoup(req.text, features='lxml')
        reqhtml = reqhtml.find_all('ul', class_='chapter-list clearfix')  # 定位章节url位置
        bf = BeautifulSoup(str(reqhtml), features='lxml')
        a = bf.find_all('a')  # 精确提取章节url
        for one in a[::-1]:  # 章节目录是倒序的,要顺序的
            self.list_names.append(one.string)  # 添加到名字列表里去
            self.list_urls.append(self.url + one.get('href'))  # 添加url
        # print(self.list_urls)
        # print(self.list_names)
        print("已完成目录提取")
        return self.list_urls, self.list_names

# 获取内容
    def get_content(self):
        filename = '元尊'
        os.mkdir(filename)  # 创建父目录
        print("已完成父目录创建")

        for net in self.list_urls:  # 遍历章节url
            requrl = requests.get(url=net)
            requrl.encoding = requrl.apparent_encoding
            reqhtml = BeautifulSoup(requrl.text, features='lxml')
            reqhtml = reqhtml.find_all('link', rel='prefetch prerender')  # 提取章节id,chapter_newid
            # print(str(str(reqhtml).replace('[]', ''))
            self.true_urls.append('https://www.kanman.com/api/getchapterinfov2?product_id=1&productname=kmh&platformname=pc&comic_id=105855&'+'chapter_newid='+str(str(reqhtml).replace('[, '')).replace('.html" rel="prefetch prerender"/>]', '')+'&isWebp=1&quality=middle')  # 这才是真正的章节url
            print("已完成{}真正的图片URL爬取".format(self.list_names[self.i]))
            self.i += 1
        print("已完成真正的漫画图片目录提取")
        for url in self.true_urls:  # 遍历真正的url,开始保存图片
            n = 1
            if requests.get(url=url).status_code == 200:  # 状态码200避免不必要的错误导致程序停止
                req = requests.get(url=url)
                json_data = req.json()  # json文件加载
                pic_url = json_data["data"]["current_chapter"]["chapter_img_list"]  # 提取图片url
                name = json_data["data"]["current_chapter"]["chapter_name"]  # 提取图片名字
                if os.path.exists(filename + '/' + name):  # 防止文件名重复
                    dirname = filename + '/' + name + 'self.unique'
                    os.mkdir(dirname)
                    self.unique += 1
                else:
                    dirname = filename + '/' + name
                    os.mkdir(dirname)
                for pic in pic_url:  # 保存图片
                    n += 1
                    with open(dirname + '/' + str(n) + '.webp', 'wb') as file:  # 特别注意图片格式
                        file.write(requests.get(url=pic).content)
                print("已完成{}爬取".format(name))
            else:
                print("第{}话爬取失败".format(name))
                continue


if __name__ == '__main__':
    down = downloader()
    down.get_name_url()
    down.get_content()

你可能感兴趣的:(爬虫学习,python,爬虫)