This repository has been archived on 2026-08-18. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

477 lines
25 KiB
Python

while True:
version = "V.2025.2.21(c)"
import easygui as g
import os
import json
import ping3
import requests
import re
import time
import urllib3
from datetime import datetime as t
from tqdm import tqdm
from PIL import Image
import webbrowser
#字符画↘
YbbLolicon = """—————————————————————————————————————————————————————————————————————————————————————————————————————————
||| ||| |
||| || || || |||| ||| || ||
||| | || || || || ||
|| | |||||| |||||| || ||| || | |||| ||| |||||| ||
|| | || || || || || || || || || || || || || || || ||
|| || || || || || || || || || || || || || || ||
|| ||| || ||| || ||| ||| || || || || || | || || || ||
|||| ||||| ||||| ||||||| ||||| |||| |||| ||||| ||||| |||| |||| ||
—————————————————————————————————————————————————————————————————————————————————————————————————————————
"""
print(f"{YbbLolicon}\n\n")
#禁用警告↘
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
#时间定义↘
def NowTime():
now = t.now()
current_time = now.strftime("%H:%M:%S")
return current_time
#图片获取定义:
def PictureGet(NumberDisplay,GetTimesDisplay,file_path,pid,API):
if API == "1":
url = f"https://pixiv.re/{pid}.png"
elif API == "2":
url0 = f"https://open.pximg.org/pid.php?pid={pid}"
response = requests.get(url0)
json_data = (response.json())
url = json_data["origin"]
elif API == "3":
num = GetTimes
if num % 2 == 0:
url = f"https://pixiv.re/{pid}.png"
else:
url0 = f"https://open.pximg.org/pid.php?pid={pid}"
response = requests.get(url0)
json_data = (response.json())
url = json_data["origin"]
CurrentTime = NowTime()
print(f"[{CurrentTime}]开始获取图片,{GetTimesDisplay}/{NumberDisplay}(url:{url})")
tip = '下载 {}'
CurrentTime = NowTime()
desc = f"[{CurrentTime}]{tip}".format(os.path.basename(file_path))
progress_bar = tqdm(initial=0, unit='B', unit_divisor=1024, unit_scale=True, desc=desc)
try:
response = requests.get(url,stream=True,verify=False)
if response.status_code == 200:
if 'Transfer-Encoding' in response.headers:
with open(file_path,'wb') as f:
for chunk in response.iter_content(1024):
f.write(chunk)
progress_bar.update(len(chunk))
f.close()
progress_bar.close()
CurrentTime = NowTime()
print(f"[{CurrentTime}]完成获取,{GetTimesDisplay}/{NumberDisplay}")
elif 'Content-Length' in response.headers:
if len(response.content) == int(response.headers['Content-Length']):
with open(file_path,'wb') as f:
for chunk in response.iter_content(1024):
f.write(chunk)
progress_bar.update(len(chunk))
f.close()
progress_bar.close()
CurrentTime = NowTime()
print(f"[{CurrentTime}]完成获取,{GetTimesDisplay}/{NumberDisplay}")
except requests.exceptions.SSLError:
progress_bar.close()
CurrentTime = NowTime()
print(f"[{CurrentTime}]图片获取失败,pid:{pid},{GetTimesDisplay}/{NumberDisplay} (如果连续看到此报错,本次获取可能已被api限速,请一段时间后重试,或使用代理.)")
except requests.exceptions.ChunkedEncodingError:
progress_bar.close()
CurrentTime = NowTime()
print(f"[{CurrentTime}]图片获取失败,pid:{pid},{GetTimesDisplay}/{NumberDisplay} (可能是网络中断引起的连接超时,也可能是API限制..)")
#等待10秒定义↘
def sleep10s():
with tqdm(range(10), desc='等待时间') as tbar:
for i in tbar:
tbar.set_postfix(loss=i/10, x=i)
time.sleep(1)
tbar.close()
#词典存储定义↘
def dict_save(FilePathDict,FilterTagList,AIban,API):
dictdata = {'FilePathDict': FilePathDict,'FilterTagList':FilterTagList,"AIban":AIban,"API":API}
with open(f'{data_path}\dictdata.json','w') as f:
json.dump(dictdata, f)
#图片有效性检测定义↘
def PictureTest(file_path,InvalidGetList,pid):
try:
img = Image.open(file_path)
img.verify()
except (IOError, SyntaxError):
InvalidGetList.append(pid)
CurrentTime = NowTime()
print(f"[{CurrentTime}]检测到下载图片可能为无效图片,将在主获取结束后尝试重新获取.pid:{pid}")
#屏蔽词条修改定义↘
def Filter(FilterTagList,AIban,FilePathDict):
FilterInput = g.multenterbox(msg=f"请输入屏蔽词条\n支持多词条,请用单个空格分隔", title='YbbLolicon!', fields=("屏蔽词条列表","AI作品排除(true启用/false禁用)"),values=(FilterTagList,AIban))
try:
FilterTagList = FilterInput[0]
AIbanTest = FilterInput[1]
if AIbanTest == "false" or AIbanTest == "true":
AIban = AIbanTest
dict_save(FilePathDict,FilterTagList,AIban,API)
g.msgbox(msg=F"屏蔽词条修改成功,词典已保存.",title="YbbLolicon!",ok_button="确定")
else:
g.msgbox(msg=F"AI排除项格式输入有误,请重新填写.",title="YbbLolicon!",ok_button="确定")
except TypeError:
pass
#本地词典存在检测↘
data_path = os.path.expanduser("~\Documents\YbbLolicon")
try:
with open(f'{data_path}\dictdata.json', "r") as file:
jsonresult = "本地记录词典获取成功."
except FileNotFoundError:
try:
SavePathCreat = os.path.expanduser("~\Documents")
os.chdir(SavePathCreat)
NewFolder = "YbbLolicon"
os.makedirs(NewFolder)
FilterTagList = ""
FilePathPre = g.diropenbox(title='请选择图片保存路径')
FilePathDict = f"{FilePathPre}"
AIban = "false"
API = "1"
dictdata = {'FilePathDict':FilePathDict,'FilterTagList':FilterTagList,"AIban":AIban,"API":API}
with open(f'{data_path}\dictdata.json', 'w') as f:
json.dump(dictdata, f)
jsonresult = '检测到首次使用或json已丢失,已重新创建json,请按照提示修改默认存储路径与过滤词条.'
except FileExistsError:
FilterTagList = "无屏蔽词条."
FilePathPre = g.diropenbox(title='请选择图片保存路径')
FilePathDict = f"{FilePathPre}"
AIban = "false"
API = "1"
Filter(FilterTagList,AIban,FilePathDict,API)
dictdata = {'FilePathDict':FilePathDict,'FilterTagList':FilterTagList,"AIban":AIban,"API":API}
with open(f'{data_path}\dictdata.json', 'w') as f:
json.dump(dictdata, f)
jsonresult = '检测到首次使用或json已丢失,已重新创建json,请按照提示修改默认存储路径与过滤词条.'
#词典保存文件获取↘
with open(f'{data_path}\dictdata.json', 'r') as f:
loaded_dict = json.load(f)
FilePathDict = loaded_dict["FilePathDict"]
FilterTagList = str(loaded_dict["FilterTagList"])
if FilterTagList == None:
FilterTagList = [None]
AIban = str(loaded_dict["AIban"])
if AIban == None:
AIban = "false"
API = loaded_dict["API"]
if API == None:
API = "1"
#主界面↘
if FilterTagList == "":
FilterTagListDisplay = "无"
else:
FilterTagListDisplay = FilterTagList
if API == "1":
APIDisplay = "pixiv.re"
elif API == "2":
APIDisplay = "pximg.org"
elif API == "3":
APIDisplay = "pixiv.re与pximg.org混合."
time.sleep(1)
print(F"{version} by RRRosmontis.\n\n{jsonresult}\n当前图片存储路径:{FilePathDict}\n所有屏蔽词条:{FilterTagListDisplay}\nAI作品排除:{AIban}\nAPI选择:{APIDisplay}")
input("\n按Enter进入主界面.")
choices = ['获取图片(指定tag)','获取图片(指定pid)','设置']
selection = g.choicebox(f'—————— YbbLolicon! 涩图获取 ——————\n \n选择要进行的项目','YbbLolicon!',choices = choices)
#变量设定↘
GetTimes = 0
RunAgain = "Y"
InvalidGetList = []
#图片获取变量请求↘
if selection == "获取图片(指定tag)":
print("\n")
if FilePathDict == "None":
g.msgbox(msg=f"无图片存储路径.请修改默认值.",title="YbbLolicon!",ok_button="确定")
print("\033c", end="")
os._exit(0)
try:
if FilePathDict == "None":
g.msgbox(msg=F"警告:存储路径未填写,请退出程序并修改,否则无法正常保存.",title="YbbLolicon!",ok_button="确定")
#ping↘
print("正在测试api延迟,预计时间:小于5秒.")
target_host_1 = 'lolicon.app'
target_host_2 = 'pixiv.re'
target_host_3 = 'pximg.org'
delay_1 = ping3.ping(target_host_1,timeout=2)
delay_2 = ping3.ping(target_host_2,timeout=3,size=1024)
delay_3 = ping3.ping(target_host_3,timeout=2,size=1024)
if delay_1 is None:
print(f"ping {target_host_1} 延迟较高,请检查网络连接或查询相关服务器状态.")
else:
print(f"ping {target_host_1} 延迟为{delay_1}秒.")
if delay_2 is None:
print(f"ping {target_host_2} 延迟较高,请尝试挂加速器后重启程序或查询相关服务器状态.")
else:
print(f"ping {target_host_2} 延迟为{delay_2}秒.")
if delay_3 is None:
print(f"ping {target_host_3} 延迟较高,请尝试挂加速器后重启程序或查询相关服务器状态.")
else:
print(f"ping {target_host_3} 延迟为{delay_3}秒.")
print("注意:多次获取可能会导致api访问速度变慢或暂时禁止访问,请控制获取数量.\n为防止api速率限制,每次获取完成后将会有10秒冷却时间.\n")
#获取请求↘
userinput = g.multenterbox(msg=f"· 以下为tag说明:\n 获取想要图片的主要tag(如人物名)\n 支持多tag,不同tag间应用单个空格隔开\n \n· 以下为获取数量说明:\n 获取区间:1—20\n 多次获取可能返回相同结果,请尝试更换其他tag(如角色外文名)", title=f'YbbLolicon!', fields=("tag","数量"))
try:
GETINFOORGINAL = userinput[0]
NUMBER = int(userinput[1])
except ValueError :
g.msgbox(msg=f"数字格式输入有误.请使用阿拉伯数字.",title="YbbLolicon!",ok_button="确定")
RunAgain = "Y"
except TypeError:
RunAgain = "Y"
try:
if NUMBER > 20:
print(f"获取数量过大,无法请求\n将按最大数量(20)请求.({NUMBER}>20)")
NUMBER = int("20")
GETINFO = GETINFOORGINAL.replace(" ","&tag=")
GETINFO = f"tag={GETINFO}"
tag = GETINFO.replace(" ","")
R18choice = ['全年龄','R18','混合']
R18selection = g.choicebox('请选择年龄分级\n选择完毕后图片将开始获取,请耐心等待','YbbLolicon!',choices = R18choice)
if R18selection == "全年龄":
R18 = "0"
elif R18selection == "R18":
R18 = "1"
elif R18selection == "混合":
R18 = "2"
#请求api ↘
url = f"https://api.lolicon.app/setu/v2?size=original&r18={R18}&{tag}&num={NUMBER}&excludeAI={AIban}"
#处理返回的json↘
response = requests.get(url)
json_data = response.json()
result = json_data
#检测返回中是否有链接以确定是否有结果↘
pattern = str(r'https')
json_data_str = str(json_data)
match = re.search(pattern,json_data_str)
if match:
print("从API获取到结果,已开始获取.")
else:
g.msgbox(msg=f"未从api获取到相应结果.\ntag:{GETINFOORGINAL}\n注意:如果在此处看到了连续无间隔或间隔过长的期望词条,可能是由于没有正确使用空格进行分隔.",title="YbbLolicon!",ok_button="确定")
#从返回的data中获取值↘
print("正在处理结果并进行词条检测.")
GetList = [] #待获取pid列表
ResultList = json_data["data"]
ResultCount = len(ResultList)
if ResultCount < NUMBER:
print("\n注意:结果较少,获取数目可能无法达到预期值.\n")
for index, back in enumerate(json_data["data"]):
pid = back["pid"]
tags = str(back["tags"])
#词条检测↘
FilterTagListSplit = FilterTagList.split() #空白分割为列表
def FiltertagTest(FilterTag):
match = re.search(FilterTag,tags)
if not match:
TestResult = "y"
else:
CurrentTime = NowTime()
print(f"[{CurrentTime}]检测到过滤词条,pid:{pid}")
TestResult = "n"
return TestResult
for index, FilterTag in enumerate(FilterTagListSplit):
TestResult = FiltertagTest((FilterTag))
if TestResult == "n":
break
if TestResult == "n":
continue
elif TestResult == "y":
GetList.append(pid)
CurrentTime = NowTime()
print(f"[{CurrentTime}]词条检测完成.本次符合条件的pid为:{GetList}")
#获取图片↘
for pid in GetList:
GetTimes = GetTimes + 1
NumberDisplay = NUMBER
GetTimesDisplay = GetTimes
file_path = f"{FilePathDict}\{pid}.png"
PictureGet(NumberDisplay,GetTimesDisplay,file_path,pid,API)
#图片有效性检测↘
time.sleep(1)
PictureTest(file_path,InvalidGetList,pid)
if GetTimes < NUMBER:
sleep10s()
#大结果检测与词典存储↘
if GetTimes == NUMBER:
dict_save(FilePathDict,FilterTagList,AIban,API)
InvalidGetListStr = str(InvalidGetList)
if InvalidGetListStr == "[]":
g.msgbox(msg=f"获取完成.\n有效获取次数:{GetTimes}.",title="YbbLolicon!",ok_button="确定")
if GetTimes < NUMBER:
if GetTimes != 0:
dict_save(FilePathDict,FilterTagList,AIban,API)
InvalidGetListStr = str(InvalidGetList)
if InvalidGetListStr == "[]":
g.msgbox(msg=f"没有足够的结果继续获取.\n有效获取次数:{GetTimes}\ntag:{GETINFOORGINAL}.",title="YbbLolicon!",ok_button="确定")
else:
print(f"\n注意:没有足够的结果继续获取.\n")
InvalidGetListStr = str(InvalidGetList)
if InvalidGetListStr != "[]":
CurrentTime = NowTime()
print(f"[{CurrentTime}]主获取完成.检测到有无效获取.若不关闭程序,将在30秒后重新尝试获取无效图片.")
with tqdm(range(30), desc='等待时间') as tbar:
for i in tbar:
tbar.set_postfix(loss=i/30, x=i)
time.sleep(1)
print("正在尝试重新获取.")
InvalidGetTimes = 0
InvalidNumber = len(InvalidGetList)
for index, pid in enumerate(InvalidGetList):
url = f"https://pixiv.re/{pid}.jpg"
InvalidGetTimes = InvalidGetTimes +1
NumberDisplay = InvalidNumber
GetTimesDisplay = InvalidGetTimes
file_path = f"{FilePathDict}\{pid}.png"
PictureGet(NumberDisplay,GetTimesDisplay,file_path,pid,API)
if InvalidGetTimes < InvalidNumber:
sleep10s()
if InvalidGetTimes == InvalidNumber:
if GetTimes < NUMBER:
g.msgbox(msg=f"获取完成.(没有足够的结果继续获取)\n有效获取次数:{GetTimes}\n无效图片数:{InvalidNumber},重获取次数:{InvalidGetTimes}.",title="YbbLolicon!",ok_button="确定")
else:
g.msgbox(msg=f"获取完成.\n有效获取次数:{GetTimes}\n无效图片数:{InvalidNumber},重获取次数:{InvalidGetTimes}.",title="YbbLolicon!",ok_button="确定")
except NameError:
print("\033c", end="")
RunAgain = "Y"
#网络报错处理↘
except requests.exceptions.SSLError:
if GetTimes > 0:
GetTimesErrorsInform = GetTimes - 1
elif GetTimes == 0:
GetTimesErrorsInform = 0
g.msgbox(msg=f"服务器访问次数过多,请一段时间后尝试重新获取.\n已获取次数:{GetTimesErrorsInform}\n本次tag:{GETINFOORGINAL}\nurl:{url}",title="YbbLolicon!",ok_button="确定")
except requests.exceptions.ConnectionError:
g.msgbox(msg=f"获取失败:远程主机强迫关闭了一个现有的连接.",title="YbbLolicon!",ok_button="确定")
#其他功能性choices处理↘
elif selection == "获取图片(指定pid)":
print("\n")
try:
print("正在测试api延迟,预计时间:小于5秒.")
target_host = 'pixiv.re'
delay = ping3.ping(target_host,timeout=3,size=1024)
if delay is None:
print(f"ping {target_host} 延迟较高,请尝试挂加速器后重启程序或查询相关服务器状态.")
else:
print(f"ping {target_host} 延迟为{delay}秒.")
pid = g.enterbox(msg='输入指定pid.', title='YbbLolicon!', default='', strip=True, image=None, root=None)
pidtest = str(pid)
if pidtest == "None":
pass
else:
try:
pid = int(pid)
NumberDisplay = "1"
GetTimesDisplay = "1"
file_path = f"{FilePathDict}\{pid}.png"
PictureGet(NumberDisplay,GetTimesDisplay,file_path,pid,API)
PictureTest(file_path,InvalidGetList,pid)
InvalidGetListStr = str(InvalidGetList)
if InvalidGetListStr == "[]":
g.msgbox(msg=f"获取完成.",title="YbbLolicon!",ok_button="确定")
elif InvalidGetListStr != "[]":
CurrentTime = NowTime()
print(f"[{CurrentTime}]主获取完成.检测到有无效获取.若不关闭程序,将在30秒后重新尝试获取无效图片.")
with tqdm(range(30), desc='等待时间') as tbar:
for i in tbar:
tbar.set_postfix(loss=i/30, x=i)
time.sleep(1)
print("正在尝试重新获取.")
PictureGet(NumberDisplay,GetTimesDisplay,file_path,pid,API)
try:
img = Image.open(file_path)
img.verify()
g.msgbox(msg=f"获取完成.",title="YbbLolicon!",ok_button="确定")
except (IOError, SyntaxError) as e:
InvalidGetList.append(pid)
CurrentTime = NowTime()
g.msgbox(msg=f"检测到下载项仍无效,请确保pid准确,或一段时间后重试.pid:{pid}",title="YbbLolicon!",ok_button="确定")
except ValueError:
g.msgbox(msg=f"数字格式输入有误.请使用阿拉伯数字.",title="YbbLolicon!",ok_button="确定")
except requests.exceptions.SSLError:
g.msgbox(msg=f"服务器访问次数过多,请一段时间后尝试重新获取.\nurl:{url}",title="YbbLolicon!",ok_button="确定")
except requests.exceptions.ConnectionError:
g.msgbox(msg=f"获取失败:远程主机强迫关闭了一个现有的连接.",title="YbbLolicon!",ok_button="确定")
elif selection == "设置":
choices = ['保存路径修改','屏蔽词条修改','API设定',"API详情"]
selection = g.choicebox(f'—————— YbbLolicon! 涩图获取 ——————\n(设置页) \n \n选择要进行的项目','YbbLolicon!',choices = choices)
if selection == "保存路径修改":
print("\n")
FilePathDict = g.diropenbox(title='请选择图片保存路径')
FilePathDictTest = str(FilePathDict)
if FilePathDictTest == "None":
pass
else:
dict_save(FilePathDict,FilterTagList,AIban,API)
g.msgbox(msg=f"保存路径修改成功,词典已保存.",title="YbbLolicon!",ok_button="确定")
elif selection == "屏蔽词条修改":
print("\n")
Filter(FilterTagList,AIban,FilePathDict)
elif selection == "API设定":
APIChoice = g.buttonbox(msg=f'请选择需要使用的API:\n1:pixiv.re\n2:pximg.org\n3:以上两个API交替使用.\n \n当前api:{API}\n如果不进行选择而关闭窗口,API将自动设定为1.', title='YbbLolicon!', choices=('1', '2', '3'), image=None, images=None, default_choice=None, cancel_choice=None, callback=None, run=True)
if APIChoice == "None":
API == "1"
elif APIChoice == None:
API == "1"
else:
API = APIChoice
dict_save(FilePathDict,FilterTagList,AIban,API)
g.msgbox(msg=f"API设定成功,词典已保存.",title="YbbLolicon!",ok_button="确定")
elif selection == "API详情":
choices = ['lolicon.app','pixiv.re','pximg.org']
selection = g.choicebox(f'请选择需要了解的API\nlolicon.app:获取需求tag的pid用.\npixiv.re:取图用.\npximg.org:取图用.\n可手动访问以确定API是否仍在提供服务.','YbbLolicon!',choices = choices)
if selection == "lolicon.app":
webbrowser.open("lolicon.app")
elif selection == "pixiv.re":
webbrowser.open("pixiv.re")
elif selection == "pximg.org":
webbrowser.open("pximg.org")
else:
RunAgain = "N"
if RunAgain == "Y":
pass
print("\033c", end="")
elif RunAgain == "N":
break