爬虫常规思路:
1.分析网页
2.对网页发送请求,获取响应
3.提取解析数据
4.保存数据
本案例所用到的模块:
import requests
import parsel
import os
一、分析网页
分析思路:这个图片网站和别的图片网站不一样,是因为它有一定的反爬机制,它的反爬就是如果按照正常的提取保存图片,是没用的,保存的图片是不显示,经过分析,其实是问题就是出现在请求头里面,如下图:
那么我们在保存图片的时候,就需要把这个参数加上,另外一点就是这个参数是一个动态的,需要不断的变化,经过分析每次当前图片的链接,这个referer参数就是上一个图片的链接,所以也就是每次想获取当前图片真实链接就需要把这个请求头里面的referer参数变成一个动态的参数,传递进去就可以了。
我爬取这个网站的思路,就是,对主页发送请求,获取响应数据,获取到的都是html数据,可以通过CSS选择器,提取每一个主页图片模特特辑的链接,然后对图片模特特辑内页进行请求,获取到的响应数据也是html数据,但是现在问题来了,我们看到,每一个模特特辑内页里都有很多该模特图片,多的有百十张,少的也有几十张,所以每个模特的特辑的图片数量都不一样,这样我们怎么才能把每个模特的所有图片都提取出来啊,经过分析,如下图可以看出:
模特特辑内页里面在翻页的html源代码位置,有多个该模特图片的链接地址,经过分析,可以看到,这些链接地址有一个共同的特性,就是链接前面都不变,变化的就是后面的数字,正好这个数字也对着每一张模特图片的数字,也就是第二张图片就是网页显示的该模特的第二张图片,那么分析最后一个链接也就是下一张图片的链接,倒数第二张就是该模特的最后一张图片的链接,这样我们就好办了,可以先把链接里面的最后图片的链接提取出来,得到最后一张图片的图片数,然后通过for循环遍历这个数字,就可以把每一个图片的真实链接提取出来了。
二、对网页发送请求,获取响应
代码部分:
def parse_url(self, url, headers):
"""
发送请求,获取响应数据的方法
:param url: self.HOME_URL
:param headers:
:return:
"""
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.content.decode()
三、提取解析数据
提取了每一个模特特辑的网页链接,下面就需要需要对这些链接发送请求,获取数据了,提取出每个模特图片的总数量,
def get_home_pic_url(self, home_html_str):
"""
提取主页图片的链接地址的方法
:param home_html_str:
:return:
"""
html = parsel.Selector(home_html_str)
# 提取每个的链接
pic_urls = html.css('#pins>li>a::attr(href)').extract()
return pic_urls
def get_html_num(self, html_str):
"""
提取每个模特链接的最大页数的方法
:param html_str:
:return:
"""
html = parsel.Selector(html_str)
html_page_num = html.css('.pagenavi > a:nth-child(7)::attr(href)').extract_first().split('/')[-1]
return html_page_num
剩下的就是构建请求头(headers),这个是关键,因为每个referer参数都是动态的,所以必须构建好这个逻辑,有了这个请求头就可以在对每一张真实的图片地址请求的时候,把这个请求头加入进去就可以获取到真实的图片了。
def get_headers(self, pic_url, img_url):
"""
构建请求头参数的方法
:param pic_url:
:param img_url:
:return:
"""
img_url_num = int(img_url.split('/')[-1]) - 1
img_true_url = pic_url + f'/{str(img_url_num)}'
headers = {
"referer": img_true_url,
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36 FS",
}
return headers
四、保存数据
def save_img(self, img_url, headers, img_name):
"""
保存图片的方法
:param img_url:
:param headers:
:param img_name:
:return:
"""
os.makedirs('./meizitu/', exist_ok=True)
path = './meizitu/'
response = requests.get(img_url, headers=headers)
with open(f'{path}{img_name}', 'wb') as imgfile:
imgfile.write(response.content)
print(f'{img_name}保存完成')
保存后的效果:
五、完整思路代码
def run(self):
"""
实现主要逻辑思路
:return:
"""
# 1.对主页发送请求,获取响应数据
home_html_str = self.parse_url(self.HOME_URL, self.headers)
# 2.提取主页图的链接地址列表
pic_urls = self.get_home_pic_url(home_html_str)
for pic_url in pic_urls:
# 3.对提取的地址列表遍历进行发送请求,获取响应数据
html_str = self.parse_url(pic_url, self.headers)
# 4.提取每个模特链接的最大页数
html_page_num = self.get_html_num(html_str)
for page in range(3, int(html_page_num)):
# 5.构建新的图片地址
img_url = pic_url + f'/{str(page)}'
# 6.构建请求头
headers = self.get_headers(pic_url, img_url)
# 7.对新图片地址发送请求,获取响应数据
pic_html_str = self.parse_url(img_url, self.headers)
# 8.提取真实的图片地址
img_url = self.get_img_url(pic_html_str)
img_name = img_url.split('/')[-1]
# 9.保存图片
self.save_img(img_url, headers, img_name)