经过上两篇文章的学习,Python爬虫走三步:发起请求、解析数据、保存数据。 我已经掌握了。 是入门级的爬虫吗?
不,还不够远! 如果你只掌握这种,那你只能算是门外汉。
今天,我就带大家继续学习如何更高尚地攀登!
按照惯例,我们还是从实战出发。 今天我们就爬一张图,盘点一下遇到的这些问题,以及甜蜜的解决方案。
本文男女老少,各种美女肌肉男都适合,学会了本文的方法,你就可以收入囊中了!
私信小编001即可获得海量Python学习资料!
2. 实际背景
咱们别下载抢眼的图片了,来点清淡的家常菜吧。
动漫之家 动漫下载!
在这次实战中,你会遇到动态加载和初级防爬。 知道了本文的方法后,你还怕爬不到你想要的“美图”吗?
3.下载漫画
我们不要下载整个站点资源,只选择一个下载,不要给服务器带来太大的压力。
经过挑挑拣拣,我找到了《魔神物语》,这是本动漫之家排名靠前的一本书。 说实话css获取焦点,看完动漫第一章的内容,有一股浓浓的火影气息。
网址:
要下载这部漫画,我们需要将所有章节的图片保存到本地。 让我们先回顾一下这些想法:
看似简单,但实际操作中,你可能会遇到各种各样的问题。 让我们一起高尚地解决这些问题吧!
1.获取章节名称和章节链接
一个网页是由很多div元素组成的
不同的div存储不同的内容,如上图所示,有存储标题Jack Cui的div,有存储菜单的div,有存储文本内容的div,还有存储版权信息的div。
看一下,不难发现,只要拿到class属性为zj_list的div标签,就可以拿到章节名和章节链接,它们都存储在这个div标签下的a标签中。
仔细一看,你会发现div标签下面有一个ul标签,而ul标签是距离a标签最近的标签。
使用上一篇文章讲解的BeautifulSoup,其实可以直接匹配最近的class属性为list_con_li的ul标签。 编写以下代码:
Python
import requests
from bs4 import BeautifulSoup
target_url = "https://www.dmzj.com/info/yaoshenji.html"
r = requests.get(url=target_url)
bs = BeautifulSoup(r.text, 'lxml')
list_con_li = bs.find('ul', class_="list_con_li")
comic_list = list_con_li.find_all('a')
chapter_names = []
chapter_urls = []
for comic in comic_list:
href = comic.get('href')
name = comic.text
chapter_names.insert(0, name)
chapter_urls.insert(0, href)
print(chapter_names)
print(chapter_urls)
瞧,章节名称和章节链接已完成!
没有困难吗? 别担心,困难还在后面。
2.获取动画图片的地址
我们只要分析一下如何获取章节中的图片,就可以在每个章节中批量获取动画图片了。
我们先看第一章。
网址:
打开第一章的链接,你会发现链接前面手动添加了#@page=1。
当你翻页时,你会发现第二页的链接前面是#@page=2,第三页的链接前面是#@page=3,以此类推。
不过,这些并不是图片的地址,而是显示页面的地址。 要下载图片,首先要获取图片的真实地址。
检查元素找到图片地址,你会发现这个页面无法右键!
这是最底层的反爬虫方法。 这时,我们可以使用鼠标的F12来调出审阅元素窗口。
有些网站甚至禁止F12,这也是一种非常低级的反爬虫方法,只是一种欺骗初学者的方法。
面对这些严格禁止查看页面源代码的中间方法,一个崇高的通用解决方案是在连接前添加一个view-source:。
壳
view-source:https://www.dmzj.com/view/yaoshenji/41917.html
使用此链接可以直接查看页面的源代码。
更简单的方法是将键盘焦点放在浏览器地址栏上,然后按 F12 仍然调出调试窗口。
该动画网站仍然可以通过 F12 检查元素并调出调试窗口。
我们可以在浏览器调试窗口中的Network中找到该页面加载的内容,比如一些css文件、js文件、图片等。
如果你想找图片的地址,直接在这里找就可以了,不用在html页面里找了,html信息那么多,猴年马月都可以一一找到。
在网络中,我们可以很容易地找到我们想要的图片的真实地址。 调试工具非常强大。 headers可以查看一些请求头信息,Preview可以浏览返回的信息。
搜索功能、过滤功能等等,你需要的都有,怎么用,自己点一下就知道了!
好了,现在我们已经得到了图片的真实地址,我们来看一下链接:
这是图片的真实地址。 拿着这个链接在html页面中搜索,可以看到img标签中存放着。 经过搜索,你会发现浏览器中的html页面有这个图片链接。
但如果你用view-source:打开这个页面,你会发现无法搜索到这个图片链接。
壳
查看源代码:
请记住,这意味着这张图片是动态加载的!
使用view-source:方法是查看页面的源代码,而不考虑动态加载的内容。 上面没有图片链接,这意味着图片是动态加载的。
容易判断吗?
遇到动态加载不要惊慌css获取焦点,使用JavaScript来动态加载,无非两种形式:
外部加载就是在html页面中通过引用加载一个js,例如:
XHTML
这段代码的意思是引用cuijiahua.com域名下的call.js文件。
内部加载是指Javascript脚本内容是用html编写的,比如这个动画网站。
这时候,你可以利用搜索功能来教一点搜索技巧。
图片链接是这样的,然后用图片的名字去掉后缀,就是14395217739069,在浏览器的调试页面上搜索,因为通常这些动态加载和链接都是由程序合成的,所以搜索是正确的!
XHTML
var arr_img = new Array();
var page = '';
eval(function(p,a,c,k,e,d){e=function(c){return(c35?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}('g f='{"e":"h","i":"0","l":"k\/3\/5\/2\/j.4\r\6\/3\/5\/2\/d.4\r\6\/3\/5\/2\/7.4\r\6\/3\/5\/2\/8.4\r\6\/3\/5\/2\/c.4\r\6\/3\/5\/2\/b.4\r\6\/3\/5\/2\/a.4\r\6\/3\/5\/2\/9.4\r\6\/3\/5\/2\/m.4\r\6\/3\/5\/2\/v.4\r\6\/3\/5\/2\/A.4\r\6\/3\/5\/2\/n.4\r\6\/3\/5\/2\/B.4\r\6\/3\/5\/2\/x.4\r\6\/3\/5\/2\/y.4","w":"p","o":"1","q":"\s\u \t\z"}';',38,38,'||14237|chapterpic|jpg|3059|nimg|14395217891719|14395217893745|14395217913416|14395217908431|14395217904781|1439521790086|1439521788936|id|pages|var|41917|hidden|14395217739069|img|page_url|14395217918734|14395217931135|chapter_order|15|chapter_name||u7b2c01|u91cd|u8bdd|14395217923415|sum_pages|14395217940216|14395217943921|u751f|14395217926321|1439521793602'.split('|'),0,{}))
不出意外,你仍然可以看到这段代码,14395217739069 就混在里面了!
我看不懂 JavaScript,我该怎么办?
没关系,说实话,我也很费劲地看。
那我们就去找找规律,分析分析,看看能不能优雅地解决这个动态加载问题。 我们看一下这个图片链接:
链接中的数字看起来很熟悉吗?
这不就是这些数字的综合吗?
嗯,我有一个大胆的想法! 直接获取这个长数字,尝试合成链接。
Python
import requests
from bs4 import BeautifulSoup
import re
url = 'https://www.dmzj.com/view/yaoshenji/41917.html'
r = requests.get(url=url)
html = BeautifulSoup(r.text, 'lxml')
script_info = html.script
pics = re.findall('d{13,14}', str(script_info))
chapterpic_hou = re.findall('|(d{5})|', str(script_info))[0]
chapterpic_qian = re.findall('|(d{4})|', str(script_info))[0]
for pic in pics:
url = 'https://images.dmzj.com/img/chapterpic/' + chapterpic_qian + '/' + chapterpic_hou + '/' + pic + '.jpg'
print(url)
运行代码,可以得到如下结果:
踏破铁鞋无处可寻,不费力气就能得到!
对比之后你会发现,这些确实是动漫图片的链接!
但有一个问题,这样合成的图片链接并不是按照动漫的顺序排列的,下载下来的动漫图片都是乱七八糟的! 不高贵!
这个网站也是人写的! 这是人性化的,很容易处理! 惯性思维,如果是你,你会把小数放在上面,大数放在前面吗? 这些长数字中,有13位和14位,而且都是以14开头。那我赌,补齐最后一位数字后的结果就是图片的顺序!
Python
import requests
from bs4 import BeautifulSoup
import re
url = 'https://www.dmzj.com/view/yaoshenji/41917.html'
r = requests.get(url=url)
html = BeautifulSoup(r.text, 'lxml')
script_info = html.script
pics = re.findall('d{13,14}', str(script_info))
for idx, pic in enumerate(pics):
if len(pic) == 13:
pics[idx] = pic + '0'
pics = sorted(pics, key=lambda x:int(x))
chapterpic_hou = re.findall('|(d{5})|', str(script_info))[0]
chapterpic_qian = re.findall('|(d{4})|', str(script_info))[0]
for pic in pics:
if pic[-1] == '0':
url = 'https://images.dmzj.com/img/chapterpic/' + chapterpic_qian + '/' + chapterpic_hou + '/' + pic[:-1] + '.jpg'
else:
url = 'https://images.dmzj.com/img/chapterpic/' + chapterpic_qian + '/' + chapterpic_hou + '/' + pic + '.jpg'
print(url)
程序将13位数字的末尾补0,然后对它们进行排序。
按顺序与网页上的链接对比一下,你会发现是正确的! 就是这样的命令!
不了解Javascript就直接分析测试合成的链接代码是否够高尚?
3.下载图片
万事俱备,只欠机会!
使用图像链接之一并通过下载代码进行尝试。
Python
import requests
from urllib.request import urlretrieve
dn_url = 'https://images.dmzj.com/img/chapterpic/3059/14237/14395217739069.jpg'
urlretrieve(dn_url,'1.jpg')
可以通过urlretrieve进行下载,这是最简单的下载方式。 第一个参数是下载链接,第二个参数是下载后保存的文件名。
不出意外,这张图你可以顺利下载!
然而,意外发生了!