上篇的代码已经可以实现爬取主图的任务了,但是画师经常会上传不止一张图片,之前的代码就不能实现这一功能
我们找一个多张图片的作品抓取接口
发现子图的地址只是替换了 p0 为 p1 ,后面的依次替换 px
def down_z_picture(data):
p = 1
while True:
url = data['url'].replace("p0", f"p{p}")
p_name = url.split("/")[-1].replace("_master1200", "") # 获得图片的名称
# 开始下载
img = s.get(url, headers={"referer": f"https://www.pixiv.net/artworks/{data['p_id']}"})
if img.status_code == 404:
break
with open(p_name, 'wb') as f:
# 保存图片
f.write(img.content)
p += 1
注意:
1. data是主图下载后传递过来的
2. 在调用这个方法前需要判断,下载地址里面是否有p0存在,有些图片的地址没有p0,会导致程序无限循环在子图下载中
3. 通过判断状态码是404说明不存在此图片,来控制退出循环
经过前面的代码,下载图片的功能已经完成,但是存在新的问题
第一是如果已经下载过再次运行又会下载一次,非常浪费时间
第二是图片没有进行分类,后面处理起来也比较麻烦,还有就是后面添加黑名单不方便
用pathlib下的Path(file_path).exists()来判断是否已经下载过
from pathlib import Path
# 判断文件或文件夹是否存在
def judge_file(file_path):
return Path(file_path).exists()
注意:
1. file_path的路径中使用 \\ 来代表 \ 更加稳妥
画师的目录名称格式是 画师昵称_ID=ID值
但是画师的昵称会存在一些字符是不能创建目录的我们需要删除这些字符
del_li = [' ', '/', '|', '\t', '"', ':', '*', '\\', '<', '>', '?']
# 删除文本内容
def del_text(text):
for i in self.del_li:
text = text.replace(i, '')
return text
接下来是创建目录
from os import system
# 只返回有无错误
def my_system(cmd):
r = system(cmd)
if r == 0:
return True
else:
return False
def create_dir(data):
u_name = del_text(data["u_name"])
dir_name = f"{u_name}_ID={data['id']}"
# 创建前判断是否存在
if not judge_file(dir_name):
my_system(f'mkdir "{dir_name}"')
return dir_name
这样目录创建就完成了,最后调整一下之前的代码
因为方法非常多所以代码调整的比较大,前面的代码主要是提供思路
最后总结的代码
import requests
from os import system
from pathlib import Path
# 用类来进行封装
class pixiv_down:
# 初始化一些参数
def __init__(self):
self.s = requests.session() # p站爬取只能用会话才能获得返回数据
self.s.keep_alive = False # 设置保持连接为否
self.native_data = [] # 存放原始数据
self.del_li = [' ', '/', '|', '\t', '"', ':', '*', '\\', '<', '>', '?'] # windows目录删除的字符
# 主方法
def main_fanc(self):
self.__get_native_data()
self.__down_m_picture()
# 获得原始数据,方法名前加__为私有化方法
def __get_native_data(self):
url = "https://www.pixiv.net/ranking.php?mode=daily&p=%d&format=json" # 排行URL
header = {"referer": "https://www.pixiv.net/ranking.php?mode=daily"} # 头部跳转信息 注:应对P站防盗链,headers只需要加referer即可获得返回数据
# 循环一共有500排行, 每页50, 一共10页
for p in range(1, 11):
print(f"开始处理排行第{p}页的数据") # 输出调试信息
# 发送请求
r = self.s.get(url % p, headers=header, timeout=30) # timeout设置超时30秒
r = r.json()['contents'] # 获得排行原始数据
# 遍历原始数据
for i in r:
self.native_data.append({"p_id": i["illust_id"], # 图片ID
"url": i["url"].replace('/c/240x480', ''), # 图片地址还原大图地址
"u_id": i["user_id"], # 画师ID
"u_name": self.__del_text(i["user_name"]), # 画师昵称删除不符合的字符
"header": {"referer": f"https://www.pixiv.net/artworks/{i['illust_id']}"},}) # 跳转信息
print("排行原始数据处理完成")
# 下载主图
def __down_m_picture(self):
# 遍历数据
for data in self.native_data:
dir_name = f'{data["u_name"]}_ID={data["u_id"]}' # 目录名称
self.__create_dir(dir_name) # 创建画师目录
p_name = self.__get_p_name(data['url']) # 获得图片的名称
# 开始下载
img = self.s.get(data['url'], headers=data['header'])
with open(f'{dir_name}/{p_name}', 'wb') as f:
# 保存图片
f.write(img.content)
print(f'{p_name}保存成功')
if "p0" in data['url']: # 判断有p0,下载子图
self.__down_z_picture(data, dir_name)
# 下载子图
def __down_z_picture(self, data, dir_name):
p = 1
while True:
url = data['url'].replace("p0", f"p{p}") # 替换p0
p_name = url.split("/")[-1].replace("_master1200", "") # 获得图片的名称
# 开始下载
img = self.s.get(url, headers=data['header'])
if img.status_code == 404: # 404代码无图片了
break # 中断循环
with open(f'{dir_name}/{p_name}', 'wb') as f:
# 保存图片
f.write(img.content)
print(f'{p_name}保存成功')
p += 1
# 删除文本内容
def __del_text(self, text):
for i in self.del_li:
text = text.replace(i, '')
return text
# 判断文件或文件夹是否存在
def __judge_file(self, file_path):
return Path(file_path).exists()
# 创建画师目录
def __create_dir(self, file_path):
if not self.__judge_file(file_path): # 创建前判断不存在
if self.__system(f'mkdir "{file_path}"'):
print(f"{file_path} 创建成功")
# 只返回有无错误
def __system(self, cmd):
r = system(cmd)
if r == 0:
return True
else:
return False
# 根据url获取图片名称
def __get_p_name(self, url):
return url.split("/")[-1].replace("_master1200", "")
if __name__ == '__main__':
pixiv_down().main_fanc()