Python3 03 网络爬虫 <下载漫画>


在这里插入图片描述

@ 我的老师:Jack Cui

PS:我是通过 看 Jack Cui 老师的文章 学习的爬虫,也为我之后的 爬虫打开了大门。


3.1 下载漫画

那么这一节,我们就要 去网络上下载漫画。即 图片 的爬取。

经过了 上次 爬取文字,其实图片的爬取我们也能手到擒来。

但是这一章,我们 需要学习的一个新知识点是:解决 header 头协议 反爬虫机制。 即最简单的反爬机制


3.1.1 目标 URL

我们都知道 大厂的 漫画,我们是 没法那么直接的爬取的。毕竟 人家 肯定有 安全保护。我们如果能把 这个保护 给破了。那也就 蹲号子了。

所以这次的 目标 URLhttps://www.dmzj.com/

《武林之王的退隐生活》 URL: https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html
在这里插入图片描述
通过 分析,我们发现 每个章节的 URL 都在 一个 <ul class = list_con_li autoHeight> 的标签下面,而且全是 a 标签的 href 属性。

在这里插入图片描述


import requests
from bs4 import BeautifulSoup

req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
href = []

for a in aList:
    href.append(a.get('href'))

print(href)

这样我们就获取到了 所有的 章节 url 地址。

在这里插入图片描述


3.1.2 分析 每个章节 URL

在这里插入图片描述
在这里插入图片描述
原来 显示哪一页 是根据 提供的 page 参数来控制的

但是,这些并不是图片的地址,而是这个展示页面的地址,要下载图片,首先要拿到图片的真实地址。

而且还会有一个问题!

审查元素找图片地址,你会发现,这个页面不能右键!

这也是最低级的反爬虫手段,这个时候我们可以通过键盘的 F12 调出审查元素窗口。

有的网站甚至把F12都禁掉,这种也是很低级的反爬虫手段,骗骗刚入门的手段而已。

面对这种禁止看页面源码的初级手段,一个优雅的通用解决办法是,在连接前加个view-source: 它也能够直接判断 该页面是否有动态加载。

view-source:https://www.dmzj.com/view/yaoshenji/41917.html

在这里插入图片描述
很明显 这个 img 里面的 src 才是图片的真实地址。
在这里插入图片描述
而我们 对比 我们之前 view-source 的源代码,发现 并没有这一行 img。也就说 这个 img 标签和 src 属性值 都是动态加载的。

在这里插入图片描述
动态加载 都是 用 js 的,我们看 这里就有一个 js 代码。我们可以猜测 一下,它就是 生成 src 的代码。

<script type="text/javascript">
        var arr_img = new Array();
        var page = '';
        eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('D E=\'{"F":"G","C":"0","B":"x\\/2\\/4\\/1\\/w.3\\r\\5\\/2\\/4\\/1\\/y.3\\r\\5\\/2\\/4\\/1\\/z.3\\r\\5\\/2\\/4\\/1\\/A.3\\r\\5\\/2\\/4\\/1\\/H.3\\r\\5\\/2\\/4\\/1\\/I.3\\r\\5\\/2\\/4\\/1\\/P.3\\r\\5\\/2\\/4\\/1\\/Q.3\\r\\5\\/2\\/4\\/1\\/R.3\\r\\5\\/2\\/4\\/1\\/S.3\\r\\5\\/2\\/4\\/1\\/O.3\\r\\5\\/2\\/4\\/1\\/N.3\\r\\5\\/2\\/4\\/1\\/J.3\\r\\5\\/2\\/4\\/1\\/v.3\\r\\5\\/2\\/4\\/1\\/L.3\\r\\5\\/2\\/4\\/1\\/M.3\\r\\5\\/2\\/4\\/1\\/T.3\\r\\5\\/2\\/4\\/1\\/q.3\\r\\5\\/2\\/4\\/1\\/c.3\\r\\5\\/2\\/4\\/1\\/b.3\\r\\5\\/2\\/4\\/1\\/d.3\\r\\5\\/2\\/4\\/1\\/e.3\\r\\5\\/2\\/4\\/1\\/g.3\\r\\5\\/2\\/4\\/1\\/f.3\\r\\5\\/2\\/4\\/1\\/a.3\\r\\5\\/2\\/4\\/1\\/6.3\\r\\5\\/2\\/4\\/1\\/9.3\\r\\5\\/2\\/4\\/1\\/8.3\\r\\5\\/2\\/4\\/1\\/7.3\\r\\5\\/2\\/4\\/1\\/h.3\\r\\5\\/2\\/4\\/1\\/u.3\\r\\5\\/2\\/4\\/1\\/p.3\\r\\5\\/2\\/4\\/1\\/i.3\\r\\5\\/2\\/4\\/1\\/s.3\\r\\5\\/2\\/4\\/1\\/t.3\\r\\5\\/2\\/4\\/1\\/o.3\\r\\5\\/2\\/4\\/1\\/n.3\\r\\5\\/2\\/4\\/1\\/j.3\\r\\5\\/2\\/4\\/1\\/k.3\\r\\5\\/2\\/4\\/1\\/l.3\\r\\5\\/2\\/4\\/1\\/m.3\\r\\5\\/2\\/4\\/1\\/K.3\\r\\5\\/2\\/4\\/1\\/1h.3\\r\\5\\/2\\/4\\/1\\/1p.3\\r\\5\\/2\\/4\\/1\\/U.3\\r\\5\\/2\\/4\\/1\\/1r.3\\r\\5\\/2\\/4\\/1\\/1s.3\\r\\5\\/2\\/4\\/1\\/1o.3\\r\\5\\/2\\/4\\/1\\/1n.3\\r\\5\\/2\\/4\\/1\\/1j.3\\r\\5\\/2\\/4\\/1\\/1k.3\\r\\5\\/2\\/4\\/1\\/1l.3\\r\\5\\/2\\/4\\/1\\/1m.3\\r\\5\\/2\\/4\\/1\\/1u.3\\r\\5\\/2\\/4\\/1\\/1A.3\\r\\5\\/2\\/4\\/1\\/1D.3\\r\\5\\/2\\/4\\/1\\/1F.3\\r\\5\\/2\\/4\\/1\\/1C.3\\r\\5\\/2\\/4\\/1\\/1E.3\\r\\5\\/2\\/4\\/1\\/1B.3\\r\\5\\/2\\/4\\/1\\/1w.3\\r\\5\\/2\\/4\\/1\\/1v.3\\r\\5\\/2\\/4\\/1\\/1x.3\\r\\5\\/2\\/4\\/1\\/1y.3\\r\\5\\/2\\/4\\/1\\/1z.3\\r\\5\\/2\\/4\\/1\\/1t.3\\r\\5\\/2\\/4\\/1\\/1i.3\\r\\5\\/2\\/4\\/1\\/11.3\\r\\5\\/2\\/4\\/1\\/12.3\\r\\5\\/2\\/4\\/1\\/13.3\\r\\5\\/2\\/4\\/1\\/14.3\\r\\5\\/2\\/4\\/1\\/10.3\\r\\5\\/2\\/4\\/1\\/Z.3\\r\\5\\/2\\/4\\/1\\/V.3\\r\\5\\/2\\/4\\/1\\/W.3\\r\\5\\/2\\/4\\/1\\/X.3\\r\\5\\/2\\/4\\/1\\/Y.3\\r\\5\\/2\\/4\\/1\\/15.3\\r\\5\\/2\\/4\\/1\\/16.3\\r\\5\\/2\\/4\\/1\\/1d.3\\r\\5\\/2\\/4\\/1\\/1e.3\\r\\5\\/2\\/4\\/1\\/1f.3\\r\\5\\/2\\/4\\/1\\/1g.3","1c":"1b","17":"18","19":"\\1a\\1q"}\';',62,104,'|103311|chapterpic|jpg|24629|nimg|15387132106463|15387132472758|1538713211461|15387132111986|15387132102993|15387132071765|15387132054942|15387132074021|15387132076097|1538713209176|15387132083894|15387132475134|15387132496057|15387132521831|1538713252453|15387132531873|15387132536869|15387132517065|15387132510715|15387132491843|15387132052465||15387132499641|15387132504361|15387132482533|1538713202897|15387131964674|img|15387131970081|15387131973556|15387131975423|page_url|hidden|var|pages|id|81686|1538713198261|15387131993831|15387132022799|15387132541087|15387132031322|15387132033702|15387132021274|15387132017609|15387131996876|15387132000432|15387132010729|15387132013872|15387132041973|15387132561882|15387133795104|15387133800553|15387133810704|15387133816276|15387133789255|15387133778269|15387132890782|15387132899411|15387133759005|15387133761202|15387133821677|1538713382639|chapter_order|26|chapter_name|u7b2c25|83|sum_pages|15387133833095|15387133842509|15387133848236|15387133853862|15387132551665|15387132884198|15387132796967|15387132806111|15387132816015|15387132819479|1538713279314|15387132576545|15387132556251|u8bdd|15387132565482|15387132569262|15387132876577|1538713282373|15387132861761|15387132858676|15387132864231|15387132867345|15387132873435|1538713282992|15387132856755|15387132851568|15387132836886|15387132853856|15387132839844'.split('|'),0,{}))
    </script>

在这里插入图片描述
我们会看到 一大堆的数字数据,这些数据 肯定 和 src 地址有关。

比如第一页图片:https://images.dmzj.com/img/chapterpic/24629/103311/15387131964674.jpg

第二页:https://images.dmzj.com/img/chapterpic/24629/103311/15387131970081.jpg

基本上前面有共同的前缀:https://images.dmzj.com/img/chapterpic/

只是后面的 不一样而已。

格式分别是:固定不变的5位数字/固定不变的6位数字/发生变化的13位数字or14位数字

而这些出现的数字,正好是 这段 js 代码数字数据里面的 数字!!!

换句话说:我们只要把固定不变的的5位和6位取到后,再分别取出 14位和15位数字 进行一个 字符串的连接。就可以得到 正确的 图片 url 了。

import requests
from bs4 import BeautifulSoup
import re

req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
urlList = []

for a in aList:
    urlList.append(a.get('href'))

for url in urlList:
    # 先把 js 源代码取出来
    # html.script 是取内置的 js 代码
    req = requests.request(method="GET",url=url)
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    script_info = bs.script
    固定的5位数字 = re.search('\|(\d{5})\|',str(script_info)).group(1)
    固定的6位数字 = re.search('\|(\d{6})\|', str(script_info)).group(1)
    发生变化的13or14数字 = re.findall('\d{13,14}', str(script_info))
    for x in 发生变化的13or14数字:
        url = 'https://images.dmzj.com/img/chapterpic/'+固定的5位数字+'/'+固定的6位数字+'/'+x+'.jpg'
        print(url)
    break

在这里插入图片描述

但是有个问题,这么合成的的图片链接不是按照漫画顺序的,这下载下来漫画图片都是乱的啊!不优雅!

最后发现,13or14位 的数字,小的是排前面的,大的是排后面的。即升序排序的!

那么我们就可以尝试 下载了。

import os

import requests
from bs4 import BeautifulSoup
import re
from urllib.request import urlretrieve

os.mkdir('武林之王的退隐生活')
req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
urlList = []
nameList = []

for a in aList:
    urlList.append(a.get('href'))
    nameList.append(a.text)

for i,url in enumerate(urlList):
    # 先把 js 源代码取出来
    # html.script 是取内置的 js 代码
    req = requests.request(method="GET",url=url)
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    script_info = bs.script
    固定的5位数字 = re.search('\|(\d{5})\|',str(script_info)).group(1)
    固定的6位数字 = re.search('\|(\d{6})\|', str(script_info)).group(1)
    发生变化的13or14数字 = re.findall('\d{13,14}', str(script_info))
    发生变化的13or14数字 = sorted(发生变化的13or14数字, key=lambda x:int(x))
    print(发生变化的13or14数字)
    os.mkdir('武林之王的退隐生活\\'+nameList[i])
    for j,x in enumerate(发生变化的13or14数字):
        url = 'https://images.dmzj.com/img/chapterpic/'+固定的5位数字+'/'+固定的6位数字+'/'+x+'.jpg'
        urlretrieve(url, '武林之王的退隐生活\\'+nameList[i]+'\\'+str(j)+'.jpg')
        print(url)
    break

在这里插入图片描述


3.2.1 解决 403 问题

这个403问题,就是你没权限访问。但是我们知道的是,我们正常访问的时候,确实是可以的。

所以我们猜测,应该 是 不认为我们是 人类

那我们就可以通过 header 来进行伪装!

我们通过使用,NetWork 工具 按 F5 刷新页面。会发现 它捕获了 很多 数据包!

其中我们最在意的 图片,也在里面,我们点击一下。

在这里插入图片描述
再点击 Headers 可以看到 对应的 Request Headers

Referer: https://www.dmzj.com/
sec-ch-ua: " Not A;Brand";v=“99”, “Chromium”;v=“96”, “Google Chrome”;v=“96”
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: “Windows”
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36

我们 可以 先取 第一个 参数 Referer:https://www.dmzj.com/ 来进行 伪装。

import os
from contextlib import closing

import requests
from bs4 import BeautifulSoup
import re

import time

os.mkdir('武林之王的退隐生活')
req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
urlList = []
nameList = []

for a in aList:
    urlList.append(a.get('href'))
    nameList.append(a.text)

header = {
    'Referer':'https://www.dmzj.com/'
}

for i,url in enumerate(urlList):
    # 先把 js 源代码取出来
    # html.script 是取内置的 js 代码
    req = requests.request(method="GET",url=url)
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    script_info = bs.script
    固定的5位数字 = re.search('\|(\d{5})\|',str(script_info)).group(1)
    固定的6位数字 = re.search('\|(\d{6})\|', str(script_info)).group(1)
    发生变化的13or14数字 = re.findall('\d{13,14}', str(script_info))
    发生变化的13or14数字 = sorted(发生变化的13or14数字, key=lambda x:int(x))
    print(发生变化的13or14数字)
    os.mkdir('武林之王的退隐生活\\'+nameList[i])
    for j,x in enumerate(发生变化的13or14数字):
        url = 'https://images.dmzj.com/img/chapterpic/'+固定的5位数字+'/'+固定的6位数字+'/'+x+'.jpg'
        with closing(requests.get(url, headers=header, stream=True)) as response:
            chunk_size = 1024
            content_size = int(response.headers['content-length'])
            if response.status_code == 200:
                with open('武林之王的退隐生活\\'+nameList[i] +'\\'+str(j)+'.jpg', "wb") as file:
                    for data in response.iter_content(chunk_size=chunk_size):
                        file.write(data)
            else:
                print('链接异常')

    break

在这里插入图片描述
最后 发现,还是顺序不对。原因居然在于,13位必须补0,变为 14位。然后 再进行排序。

排完序后,如果最后一位 是 0的话,就只取13位。

import os
from contextlib import closing

import requests
from bs4 import BeautifulSoup
import re

import time

os.mkdir('武林之王的退隐生活')
req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
urlList = []
nameList = []

for a in aList:
    urlList.append(a.get('href'))
    nameList.append(a.text)

header = {
    'Referer':'https://www.dmzj.com/'
}

for i,url in enumerate(urlList):
    # 先把 js 源代码取出来
    # html.script 是取内置的 js 代码
    req = requests.request(method="GET",url=url)
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    script_info = bs.script
    固定的5位数字 = re.search('\|(\d{5})\|',str(script_info)).group(1)
    固定的6位数字 = re.search('\|(\d{6})\|', str(script_info)).group(1)
    发生变化的13or14数字 = re.findall('\d{13,14}', str(script_info))

    for j,x in enumerate(发生变化的13or14数字):
        if len(x) == 13:
            发生变化的13or14数字[j] = x+'0'

    发生变化的13or14数字 = sorted(发生变化的13or14数字, key=lambda x:int(x))

    # print(发生变化的13or14数字)
    os.mkdir('武林之王的退隐生活\\'+nameList[i])
    for j,x in enumerate(发生变化的13or14数字):
        if x[-1] == '0':
            url = 'https://images.dmzj.com/img/chapterpic/' + 固定的5位数字 + '/' + 固定的6位数字 + '/' + x[:-1] + '.jpg'
        else:
            url = 'https://images.dmzj.com/img/chapterpic/' + 固定的5位数字 + '/' + 固定的6位数字 + '/' + x + '.jpg'

        with closing(requests.get(url, headers=header, stream=True)) as response:
            chunk_size = 1024
            content_size = int(response.headers['content-length'])
            if response.status_code == 200:
                with open('武林之王的退隐生活\\'+nameList[i] +'\\'+str(j)+'.jpg', "wb") as file:
                    for data in response.iter_content(chunk_size=chunk_size):
                        file.write(data)
            else:
                print('链接异常')
    break

在这里插入图片描述


3.3.1 完整代码

import os
from contextlib import closing

from tqdm import tqdm
import requests
from bs4 import BeautifulSoup
import re

import time

os.mkdir('武林之王的退隐生活')
req = requests.request(method='GET',url='https://www.dmzj.com/info/wulinzhiwangdetuiyinshenghuo.html')
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')

ul = bs.find(name="ul", attrs={"class" :"list_con_li autoHeight"})
aList = ul.find_all('a')
urlList = []
nameList = []

for a in aList:
    urlList.append(a.get('href'))
    nameList.append(a.text)

header = {
    'Referer':'https://www.dmzj.com/'
}

for i,url in tqdm(enumerate(urlList)):
    # 先把 js 源代码取出来
    # html.script 是取内置的 js 代码
    req = requests.request(method="GET",url=url)
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    script_info = bs.script
    固定的5位数字 = re.search('\|(\d{5})\|',str(script_info)).group(1)
    固定的6位数字 = re.search('\|(\d{6})\|', str(script_info)).group(1)
    发生变化的13or14数字 = re.findall('\d{13,14}', str(script_info))

    for j,x in enumerate(发生变化的13or14数字):
        if len(x) == 13:
            发生变化的13or14数字[j] = x+'0'

    发生变化的13or14数字 = sorted(发生变化的13or14数字, key=lambda x:int(x))

    # print(发生变化的13or14数字)
    os.mkdir('武林之王的退隐生活\\'+nameList[i])
    for j,x in enumerate(发生变化的13or14数字):
        if x[-1] == '0':
            url = 'https://images.dmzj.com/img/chapterpic/' + 固定的5位数字 + '/' + 固定的6位数字 + '/' + x[:-1] + '.jpg'
        else:
            url = 'https://images.dmzj.com/img/chapterpic/' + 固定的5位数字 + '/' + 固定的6位数字 + '/' + x + '.jpg'

        with closing(requests.get(url, headers=header, stream=True)) as response:
            chunk_size = 1024
            content_size = int(response.headers['content-length'])
            if response.status_code == 200:
                with open('武林之王的退隐生活\\'+nameList[i] +'\\'+str(j)+'.jpg', "wb") as file:
                    for data in response.iter_content(chunk_size=chunk_size):
                        file.write(data)
            else:
                print('链接异常')
    time.sleep(2)

一定要记住 下面的 代码,它可以是 一个模板哟!

 with closing(requests.get(url, headers=header, stream=True)) as response:
            chunk_size = 1024
            content_size = int(response.headers['content-length'])
            if response.status_code == 200:
                with open('武林之王的退隐生活\\'+nameList[i] +'\\'+str(j)+'.jpg', "wb") as file:
                    for data in response.iter_content(chunk_size=chunk_size):
                        file.write(data)
            else:
                print('链接异常')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值