import requests
from lxml import etree
import json
import os
# 缺陷 1:下载的是图片合集,会下载其他角色的图片
# 缺陷 2:不能存 gif,因为P站的 gif 图片用的是我还不懂的方式
#================================================
#设置一个 Session 保持会话
se = requests.session()
# E:\\0-Picture\\3-明日方舟\\鞭刃\\
# E:\\0-Picture\\4-原神\\诺艾尔
# ウィスラッシュ 鞭刃
# ノエル Genshin 诺艾尔,原神
# 1000
class Pixiv():
def __init__(self):
# 登录界面的 URL
self.base_url = 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index'
# 登录时 post 的对象
self.login_url = 'https://accounts.pixiv.net/api/login?lang=zh'
# P站首页
self.main_url = 'http://www.pixiv.net'
# 请求头
self.headers = {
'Referer': 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0",
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "",
"Connection": "keep-alive",
}
self.pixiv_id = "xxxxxxxxxxxxxxxxxxxxxxx"
self.password = "xxxxxxxxxxxxxxxxxxxxxx"
def input_basic(self):
raw = []
# 输入 tag
tag = input("请输入您想搜索的tag,若输入多个tag,请使用空格分割开:\n")
tag = tag.replace(" ", "%20")
raw.append(tag)
# 输入 收藏数
collect = input("请输入一个数,代码会筛选出收藏超过这个数值的图片:\n")
collect = str(collect)
raw.append(collect)
if int(collect) < 0 or int(collect) > 10000:
os.system('cls')
print("Out of Range,ERROR")
self.input_basic()
# 创建目录
path = input("请输入地址,若地址不存在,代码会在地址处创建一个文件夹\n")
if (os.path.exists(path)) == False:
os.mkdir(path)
raw.append(path)
return raw
# if (os.path.exists("D:\\099_Picture\\明日方舟\\"+tag)) == False:
# os.mkdir("D:\\099_Picture\\明日方舟\\"+tag)
#================================================
# 这部分是用来登陆的
def login(self):
# 请求登录页面
post_key_html = se.get(self.base_url, headers=self.headers).content.decode("utf-8")
# 根据登录页面取得 post_key 里的 id
post_key_parse = etree.HTML(post_key_html)
post_key_value = post_key_parse.xpath("//input[@name='post_key']/@value")[0]
print(post_key_value)
# 登录用的 需要 post 的链接(先在浏览器登录一次,中间调转的时候能看到)
login_url = 'https://accounts.pixiv.net/api/login?lang=zh'
# post 所用的 data
data = {
'pixiv_id': self.pixiv_id,
'password': self.password,
'return_to': 'http://www.pixiv.net/',
'post_key': post_key_value
}
# 使用 Session post后保持登录
se.post(login_url, data=data, headers=self.headers)
#=============================================================
# 从网页数据的json字典文件里,提取图片网址列表和相关数据
def get_pic_url_list(self, noelle_html_dic):
noelle_ids = []
# 读取字典里的 data
noelle_data_list = noelle_html_dic['body']['illustManga']['data']
for noelle_data in noelle_data_list:
# 判断是否为gif图片
# 如果是gif,则跳过
if noelle_data['illustType'] ==2:
continue
else:
noelle_id = []
# 获取作品链接ID,放在 【noelle_id[0]】
pic_id = noelle_data['id']
noelle_id.append("https://www.pixiv.net/artworks/" + pic_id)
# 获取作品图片链接,放在 【noelle_id[1]】
pic_url = noelle_data['url']
pic_url1 = pic_url.split("img/")[-1]
pic_url2 = pic_url1.split("_p0")[0]
pic_url = "https://i.pximg.net/img-original/img/"+pic_url2
noelle_id.append(pic_url)
# 获取作品图片数量,放在 【noelle_id[2]】
pic_pageCount = noelle_data['pageCount']
noelle_id.append(pic_pageCount)
# 作品id,放在 【noelle_id[3]】
noelle_id.append(pic_id)
# 加入整体
noelle_ids.append(noelle_id)
print("已获得列表")
return noelle_ids
#=============================================================
# 添加cookie后获取 t_p2 链接里的网页,结合cookie,获取网页里的字典
def get_page(self, t_p2, cookie):
p_headers = self.headers
p_headers["cookie"] = cookie
noelle_html = se.get(t_p2, headers=p_headers).content.decode("utf-8")
print(noelle_html)
noelle_html_dic = json.loads(noelle_html)
noelle_ids = self.get_pic_url_list(noelle_html_dic)
return noelle_ids
#=============================================================
# 网页url,循环1~50页
def get_page_url(self, tag, collect):
# 在获取的网页,输出方便检测
t_p = "https://www.pixiv.net/ajax/search/artworks/" + tag + "?word=" + tag + "&order=date&mode=all&blt=" + collect + "&p=" + "1" + "&s_mode=s_tag&type=all&lang=zh"
print(t_p)
# cookie,没有cookie,网页获取就会出错
cookie = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 这个列表是储存了全部所需数据
page_url_list = []
# 循环,读取50页
for i in range(1, 50):
x = str(i)
# t_p1 = "https://www.pixiv.net/tags/xxxxxxxxxxxxx/artworks?order=date&blt=100&p="+x+"&s_mode=s_tag"
t_p2 = "https://www.pixiv.net/ajax/search/artworks/"+tag+"?word="+tag+"&order=date&mode=all&blt="+collect+"&p="+x+"&s_mode=s_tag&type=all&lang=zh"
page_url = self.get_page(t_p2, cookie)
# 如果为空,说明没有更多网页了结束了
if page_url == []:
print("第"+x+"页完成")
break
# 否则继续获取下一页
else:
print("第"+x+"页完成")
page_url_list= page_url_list + page_url
return page_url_list
#=============================================================
# 图片下载函数
def download(self, path, page_url_list):
# 下载出错的图片列表
Wrong = []
# headers 需要做一定修改,下方有解释
d_headers = self.headers
# 从列表里循环读取
for page_url in page_url_list:
# 没有图片所在网页的网址做 Referer 的话,图片会403
d_headers['Referer'] = page_url[0]
# page_url[2] :这网页上有多少张图片,和P站图片命名方式油关 xxxxx_p0.jpg
for i in range(page_url[2]):
# 组合出没有图片格式的图片网址
url = page_url[1]+"_p" + str(i)
# print(url)
try:
# 组合出jpg格式的图片网址,图片有两种格式:jpg、png,这里穷举了两种格式,跳过了读取图片网页的过程
original = url+".jpg"
# 组合出图片名
pic_name = page_url[3]+"_p"+str(i)
# 获取 jpg 格式的图片
r = se.get(original, headers=self.headers, stream=True, timeout=5)
# 如果状态码为 200,说明 jpg 格式下载成功
if r.status_code == 200:
open(path + "\\" + pic_name + ".jpg", 'wb').write(r.content) # 将内容写入图片
print(pic_name+" done")
# 如果状态码不是200,说明网页链接出错了,换成 png 格式试试
else:
original = url + ".png"
r = se.get(original, headers=self.headers, stream=True, timeout=5)
# 如果状态码是 200,那说明图片是 png 格式,存他
if r.status_code == 200:
open(path + "\\" + pic_name + ".jpg", 'wb').write(r.content) # 将内容写入图片
print(pic_name+" done")
# 如果既不是 jpg,又不是 png
else:
Wrong.append(url)
print("图片:" + url + " 下载出错")
del r
except:
print("图片:" + url + " 下载出错")
Wrong.append(url[0])
return Wrong
# =============================================================
# 汇总
def work(self):
# 1、登录
X = self.input_basic()
tag = X[0]
collect = X[1]
path = X[2]
self.login()
# 2、获取文件列表
p = self.get_page_url(tag, collect)
print(p)
print("一共"+str(len(p))+"个网页")
a = input("是否开始下载?(Y/N)\n")
if a == "Y" or a == "y" :
# 下载
self.download(path,p)
print("over")
else:
print("over")
# 运行
pixiv=Pixiv()
a = pixiv.work()
print(a)
input("输入任意按键结束")