1. 程式人生 > 實用技巧 >聽說國漫最近崛起了,那我們就來爬幾部國漫看看,居然有反爬!

聽說國漫最近崛起了,那我們就來爬幾部國漫看看,居然有反爬!

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

轉載文,如有侵權聯絡小編刪除!