听说国漫最近崛起了,那我们就来爬几部国漫看看,居然有反爬!

1.前言

说实话这次的爬虫可能是目前我遇到的最难的一个爬虫,主要之前爬取的都是一些静态资源的网站,这次的网站虽然 反爬机制 虽然也只是低层次的,但是对于新手的我来说也算是比较难的了。

2.1基本思路

事实证明也的确是这样的。就是先爬取漫画 所有章节的链接 ,之后在 通过章节链接二次访问 再爬取该章节中所有的漫画链接,之后 通过漫画链接三次访问 并进行保存操作即可。但是具体操作之后才发现动漫之家在这其中的确还是下了很多的套的。

2.2爬取章节链接

这一步的问题不大按部就班的使用xpath定位元素的位置就行了。只需要简单分析一下网页结构即可。


这样我们便能通过xpath直接定位得到了

def getLinks(html):
    chapter_link=[]
    chapter_title=[]
    parse=parsel.Selector(html)
    links=parse.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/@href').getall()
    titles=parse.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/span[@class="list_con_zj"]/text()').getall()
    for link in links:
        chapter_link.insert(0,link)
    for title in titles:
        chapter_title.insert(0, title)
    return chapter_link,chapter_title

只要注意他这里章节是降序排列的,所以我们爬取的过程中需要将他翻转过来,所以不能只用 append 方法,应用 insert 方法。

2.3爬取漫画链接

从这里开始,就开始要命了。因为之前根本就没遇到过,就比较难搞。

2.3.1无法查看源码

这里我尝试去看他的网页源代码,但是发现鼠标右键根本是点不动的,这就说明这玩意儿看不了源代码???

之后自己通过F12发现,F12还是能用的,说明动漫之家还是给了条活路的。


但是百度完之后发现这还只是最低级的反爬操作,只需要通过在地址前面加上 view-source: 就能显示网页源代码了。

2.3.2动态加载

但是看了源代码之后自己搜了一下漫画的链接发现,这怎么啥也没有啊,玩个锤子啊!!


这时候百度了之后才知道这叫动态加载,动态加载主要是下面两种类别;

1. 外部加载
2. 内部加载

这里我们检查之后发现是属于外部加载的情况。
其实之前博主就看到script里面有些数据看着很眼熟,也就发现了,也没去深究。主要就是在下面的红色区域中:
漫画链接:https://images.dmzj.com/img/chapterpic/3059/14450/14397725505788.jpg


既然这样起码还是能够拼凑出图片的链接的,那么我们就把这些数据先提取出来。

def getImgs(link):
    pic_url=[]
    response=requests.get(link,headers=headers)
    html=BeautifulSoup(response.text,'lxml')
    script_info=html.script
    one = re.findall("\|(\d{4})\|", str(script_info))[0]
    two = re.findall("\|(\d{5})\|", str(script_info))[0]
    threes=re.findall('\d{13,14}',str(script_info))

2.3.3漫画乱序

这个我的时候就看到了,但是自己一直想不通他这个顺序是怎么排列的,也想了好长的时间一直没想出来。但是这老哥是真的牛逼,随便一试还就真TM试出来了,我是真的服。
他的最后一部分的数字 要么是13位,要么就是14位 ,那么怎么排序的呢,数字还能怎么排序?比大小呗 ,但是那样的话13位的要么 并排在最后面 ,要么 并排在最前面 但是事实上却不是这样,那么就只能是 13位的末尾添0再进行比较大小 的操作。我尼玛,现在想想,我是真特么的蠢,都没想到这个。

    for i, three in enumerate(threes):
        if len(three) == 13:
            threes[i] = three + '0'
    threes = sorted(threes, key=lambda x: int(x))
    for three in threes:
        if three[-1]=='0':
            pic_url.append("https://images.dmzj.com/img/chapterpic/"+one+"/"+two+"/"+three[:-1]+".jpg")
        else:
            pic_url.append("https://images.dmzj.com/img/chapterpic/" + one + "/" + two + "/" + three + ".jpg")

2.3.4下载漫画报403

说实话这个要是没有大哥的博客,我可能还得耗上好长的时间。
这里我们主要是发现如果你是通过他网站内部访问该图片链接的话,那么图片是可以正常显示的,但是如果我们重新刷新一下即从外部直接访问该链接图片就无法显示了,就如下图所示:


这就是一种典型的通过 Referer 的反扒爬虫手段!

Referer 可以理解为来路,先打开章节URL链接,再打开图片链接。打开图片的时候,Referer的信息里保存的是章节URL。
举个简单的例子:

假设你的家只有一扇门,那么很显然想要进你家,就必须要经过那扇门,但是现在有一个人是直接往你家墙上凿了个洞进来的,没有经过你家的门,那么很显然你这肯定违法了。

解决起来其实也简单,只要告诉浏览器,我的确是从你提供的入口进来的就行了。

# 下载漫画
    headers1={
        'Referer': "章节链接",
    }
    response=requests.get(link,headers=headers1) 

这样我们就能正常访问该图片了。

2.4下载图片

这里就很简单了之前我们已经说过下载文件的两种方式了,这里我们还是选择通过 with open 的方式来下载图片。

# 下载漫画
def download(url,links,dir_name):
    headers1={
        'Referer': url,
    }
    i=1;
    for link in links:
        pic_name = '%03d.jpg' % (i)
        new_dir_name = os.path.join(dir_name, pic_name)
        response=requests.get(link,headers=headers1)
        with open(new_dir_name, 'wb')as f:
            f.write(response.content)
            print(pic_name+"下载完成")
        i+=1

3.效果演示

4.源码

我的代码:

import requests
import parsel
import pypinyin
from bs4 import BeautifulSoup
import re
import os
import time

# 伪装浏览器。设置请求头
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",}
# 返回网页的请求信息
def askUrl(url):
    response=requests.get(url,headers=headers)
    html=response.content.decode('utf-8')
    return html

# 获取所有的章节链接以及章节名称
def getLinks(html):
    chapter_link=[]
    chapter_title=[]
    parse=parsel.Selector(html)
    links=parse.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/@href').getall()
    titles=parse.xpath('//div[@class="tab-content tab-content-selected zj_list_con autoHeight"]/ul[@class="list_con_li autoHeight"]/li/a/span[@class="list_con_zj"]/text()').getall()
    for link in links:
        chapter_link.insert(0,link)
    for title in titles:
        chapter_title.insert(0, title)
    return chapter_link,chapter_title

# 获取所有漫画的链接
def getImgs(link):
    pic_url=[]
    response=requests.get(link,headers=headers)
    html=BeautifulSoup(response.text,'lxml')
    script_info=html.script
    one = re.findall("\|(\d{4})\|", str(script_info))[0]
    two = re.findall("\|(\d{5})\|", str(script_info))[0]
    threes=re.findall('\d{13,14}',str(script_info))
    for i, three in enumerate(threes):
        if len(three) == 13:
            threes[i] = three + '0'
    threes = sorted(threes, key=lambda x: int(x))
    for three in threes:
        if three[-1]=='0':
            pic_url.append("https://images.dmzj.com/img/chapterpic/"+one+"/"+two+"/"+three[:-1]+".jpg")
        else:
            pic_url.append("https://images.dmzj.com/img/chapterpic/" + one + "/" + two + "/" + three + ".jpg")
    return pic_url

# 下载漫画
def download(url,links,dir_name):
    headers1={
        'Referer': url,
    }
    i=1;
    for link in links:
        pic_name = '%03d.jpg' % (i)
        new_dir_name = os.path.join(dir_name, pic_name)
        response=requests.get(link,headers=headers1)
        with open(new_dir_name, 'wb')as f:
            f.write(response.content)
            print(pic_name+"下载完成")
        i+=1

# main方法
def main():
    manhuas=input("请输入你要下载的漫画名:")
    dir_name = r'D:\漫画'
    if not os.path.exists(dir_name + './' + manhuas):
        os.makedirs(dir_name + './' + manhuas)
    dir_name=dir_name + './' + manhuas
    manhuas=pypinyin.pinyin(manhuas,style=pypinyin.NORMAL)
    name=''
    for manhua in manhuas:
        name=name+''.join(manhua)
    url="https://www.dmzj.com/info/"+name+".html"
    html=askUrl(url)
    links=getLinks(html)[0]
    names = getLinks(html)[1]
    for i,link in enumerate(links):
        if not os.path.exists(dir_name + './' + str(names[i])):
            os.makedirs(dir_name + './' + str(names[i]))
        print("开始下载:"+names[i])
        imglinks=getImgs(link)
        download(link,imglinks,dir_name + './' + str(names[i]))
        print(names[i]+"下载完毕")
        print("休息一会儿,稍微继续下载下一章")
        time.sleep(10)
        print("————————————————————————————————————————————————————————————————————————————————")
    print(manhuas+"已经完全下载完毕")

#主函数入口 
if __name__ == '__main__':
    main()

都看到这里了,如果需要源代码的话  加下交流技术群:1136192749

转载文,如有侵权联系小编删除!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值