* 2025-08-06如何批量下载pinterset官网高清原图作品集图片*
亲测有效:程序更新时间:2025-08-03
pinterest图片下载器链接: pan.baidu.com/s/1O2kO3xDO… 提取码: uuib
使用过程有任何问题可以联系沟通。
第1步:
必须安装chorme谷歌浏览器,同时要自行解决科学上网,如果不能正常访问behance网站那么该程序也是无法正常下载图片
*第2步:双击 *Pinterest图片下载器 ****** .exe文件 ****** , ****** 弹出一个黑色面板和图片下载面板。注意不要关闭黑色面板。
*第3步:打开 *www.pinterest.com/ ****** 网站
*第4步 *: ****** 选择 ****** 下载方式
第1种下载方式是按输入关键词搜索下载
第2种下载方式是按相似图片url下载
*第 *5 ****** 步:程序会自动打开chorme谷歌浏览器访问输入的作品地址 ****** ,请不要关闭新打开的 ****** chorme谷歌浏览器;
*第 *6 ****** 步:自动下载作品所有图片,根据作品标题自动创建图片文件夹;
*第 *7 ****** 步:检查下载的图片;都是高清的原图;
开发代码
``
import os
import time
import threading
import random
import json
import requests
import re
from datetime import datetime
from PyQt5.QtCore import Qt, pyqtSignal, QObject
from concurrent.futures import ThreadPoolExecutor, as_completed
from jsonpath import jsonpath
# 开发者信息
DEVELOPER_INFO = """
"""
class LicenseManager:
"""许可证管理器,负责处理试用次数限制 """
def __init__(self):
self.ensure_license_file()
def ensure_license_file(self):
""" 确保许可证文件存在 """
if not os.path.exists(self.license_file):
try:
with open(self.license_file, 'w') as f:
f.write("30") # 默认写入30次试用次数
except:
# 如果无法创建文件,退出程序
QMessageBox.critical(None, "错误", "无法创建试用次数文件,程序将退出")
os._exit(1)
def read_use_count(self):
""" 读取剩余使用次数 """
if not os.path.exists(self.license_file):
return 0
try:
with open(self.license_file, 'r') as f:
content = f.read().strip()
return int(content) if content.isdigit() else 0
except:
return 0 # 如果读取失败,默认返回0次
def write_use_count(self, count):
""" 写入剩余使用次数 """
try:
with open(self.license_file, 'w') as f:
f.write(str(count))
return True
except:
return False
def check_license(self):
""" 检查license """
remaining = self.read_use_count()
if remaining <= 0:
return False, "试用次数已用完"
return True, f"剩余试用次数: {remaining}"#
def update_license(self):
""" 更新license计数 """
remaining = self.read_use_count()
if remaining > 0:
self.write_use_count(remaining - 1)
class Communicate(QObject):
""" 用于线程间通信的信号类 """
update_log = pyqtSignal(str)
progress_signal = pyqtSignal(int)
status_signal = pyqtSignal(str)
class ImageDownloader(QMainWindow):
""" 图片下载器主窗口 """
def __init__(self):
super().__init__()
self.license = LicenseManager()
self.comm = Communicate()
# 连接信号与槽函数
self.comm.update_log.connect(self.update_log)
self.comm.progress_signal.connect(self.update_progress)
self.comm.status_signal.connect(self.update_status)
self.init_ui()
self.check_license_status()
def init_ui(self):
""" 初始化用户界面 """
self.setWindowTitle("Pinterest图片下载器(")
self.setGeometry(100, 100, 900, 600)
# 主部件和布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# 下载方式选择布局
method_layout = QHBoxLayout()
self.method_combo = QComboBox()
self.method_combo.addItems(["按关键词下载", "按相似图片URL下载"])
self.method_combo.currentIndexChanged.connect(self.on_method_changed)
method_layout.addWidget(QLabel("下载方式:"))
method_layout.addWidget(self.method_combo)
main_layout.addLayout(method_layout)
# 搜索布局
search_layout = QHBoxLayout()
# 输入框(关键词或URL)
self.input_field = QLineEdit()
self.input_field.setPlaceholderText("请输入搜索关键词,例如:卧室设计")
search_layout.addWidget(self.input_field)
# 页码范围选择
search_layout.addWidget(QLabel("起始页:"))
self.start_page_spin = QSpinBox()
self.start_page_spin.setMinimum(1)
self.start_page_spin.setMaximum(20)
self.start_page_spin.setValue(1)
search_layout.addWidget(self.start_page_spin)
search_layout.addWidget(QLabel("结束页:"))
self.end_page_spin = QSpinBox()
self.end_page_spin.setMinimum(1)
self.end_page_spin.setMaximum(20)
self.end_page_spin.setValue(2)
search_layout.addWidget(self.end_page_spin)
# 下载按钮
self.download_btn = QPushButton("开始下载")
self.download_btn.clicked.connect(self.start_download)
search_layout.addWidget(self.download_btn)
main_layout.addLayout(search_layout)
# 状态标签
self.status_label = QLabel("状态:就绪")
main_layout.addWidget(self.status_label)
# 进度条
self.progress_bar = QProgressBar()
self.progress_bar.setValue(0)
main_layout.addWidget(self.progress_bar)
# 日志区域
log_label = QLabel("下载日志:")
main_layout.addWidget(log_label)
self.log_text = QTextEdit()
self.log_text.setReadOnly(True)
self.log_text.setWordWrapMode(QTextOption.WrapAnywhere)
main_layout.addWidget(self.log_text)
def on_method_changed(self, index):
"""根据选择的下载方式更改输入框提示"""
if index == 0: # 按关键词下载
self.input_field.setPlaceholderText("请输入搜索关键词,例如:卧室设计")
else: # 按相似图片URL下载
self.input_field.setPlaceholderText("请输入Pinterest URL,")
def check_license_status(self):
""" 检查license状态并更新UI """
valid, msg = self.license.check_license()
self.status_label.setText(msg)
def update_log(self, text):
""" 更新日志显示 """
timestamp = datetime.now().strftime("%H:%M:%S")
self.log_text.append(f"[{timestamp}] {text}")
# 自动滚动到底部
self.log_text.verticalScrollBar().setValue(
self.log_text.verticalScrollBar().maximum()
)
def update_progress(self, value):
""" 更新进度条 """
self.progress_bar.setValue(value)
def update_status(self, text):
""" 更新状态标签 """
self.status_label.setText(text)
def sanitize_filename(self, filename):
""" 清理文件名中的非法字符 """
# Windows中不允许的字符
invalid_chars = '<>:"/\|?*'
for char in invalid_chars:
filename = filename.replace(char, '')
# 去除首尾空格并限制长度
filename = filename.strip()
if len(filename) > 50: # 限制长度避免过长,为页码和索引留出空间
filename = filename[:50]
return filename if filename else "untitled"
def extract_pin_id(self, url):
"""从URL中提取pin ID(数字部分)"""
# 正则表达式匹配Pinterest URL中的数字ID
match = re.search(r'/pin/(\d+)/', url)
if match:
return match.group(1)
return None
def download_image(self, url, save_path):
""" 下载单张图片 - 添加了随机延迟 """
try:
# 下载前添加随机延迟,模拟人类行为
delay = random.uniform(0.5, 2.0) # 随机等待0.5-2秒
time.sleep(delay)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 200:
with open(save_path, 'wb') as f:
f.write(response.content)
return True, save_path
else:
return False, f"状态码错误: {response.status_code}"
except Exception as e:
return False, f"下载失败: {str(e)}"
def download_thread(self, method, input_data, start_page, end_page):
""" 下载线程函数 """
try:
# 根据下载方式初始化变量和URL
if method == 0: # 关键词下载
keyword = input_data
base_url = f'url'
listen_url = 'resource/BaseSearchResource/get'
# 创建保存图片的文件夹
safe_keyword = self.sanitize_filename(keyword)
save_dir = os.path.join("images", safe_keyword)
folder_name = safe_keyword
else: # URL下载
url = input_data
pin_id = self.extract_pin_id(url)
base_url = url
listen_url = 'resource/RelatedModulesResource/get/?source_url'
# 创建保存图片的文件夹(使用pin_id作为文件夹名)
save_dir = os.path.join("images", pin_id)
folder_name = pin_id
os.makedirs(save_dir, exist_ok=True)
self.comm.update_log.emit(f"图片将保存到: {os.path.abspath(save_dir)}")
# 启动浏览器并打开目标网页
self.comm.update_log.emit("正在启动浏览器...")
cp = Chromium().latest_tab
cp.listen.start(listen_url)
time.sleep(2)
cp.get(base_url)
# 开始监听指定接口
self.comm.update_log.emit("开始监听数据接口...")
# 存储图片URL及其对应的页码
pic_info = [] # 格式: [(url, page_num), ...]
# 如果不是从第1页开始,需要先滚动到起始页
if start_page > 1:
self.comm.update_log.emit(f"正在跳转到第 {start_page} 页...")
for page in range(1, start_page):
cp.scroll.to_bottom()
time.sleep(random.uniform(2, 3))
# 消耗掉这些页面的响应,避免影响后续数据获取
try:
cp.listen.wait(timeout=5)
except:
pass
# 下载图片
self.comm.update_log.emit("开始下载图片...")
success_count = 0
with ThreadPoolExecutor(max_workers=3) as executor: # 减少线程数降低请求频率
# 创建下载任务
futures = []
for idx, (pic_url, page_num) in enumerate(pic_info, start=1):
# 根据不同下载方式使用不同的命名逻辑
if method == 0: # 关键词下载命名
filename = f"{folder_name}-page{page_num}-{idx}.jpg"
else: # URL下载命名
filename = f"{folder_name}-page{page_num}-{idx}.jpg"
save_path = os.path.join(save_dir, filename)
futures.append(executor.submit(self.download_image, pic_url, save_path))
# 处理下载结果
for i, future in enumerate(as_completed(futures), 1):
success, result = future.result()
if success:
success_count += 1
self.comm.update_log.emit(f"下载成功: {os.path.basename(result)}")
else:
self.comm.update_log.emit(f"下载失败: {result}")
# 更新进度
progress = int((i / len(futures)) * 100)
self.comm.progress_signal.emit(progress)
self.comm.update_log.emit(f"下载完成,成功 {success_count}/{len(pic_info)} 张图片")
self.comm.status_signal.emit(f"下载完成:成功 {success_count}/{len(pic_info)} 张图片")
except Exception as e:
self.comm.update_log.emit(f"发生错误: {str(e)}")
self.comm.status_signal.emit("下载失败")
finally:
self.comm.progress_signal.emit(100)
self.download_btn.setEnabled(True)
def start_download(self):
""" 开始下载过程 """
# 检查license
valid, msg = self.license.check_license()
if not valid:
QMessageBox.critical(self, "授权限制", DEVELOPER_INFO + "\n" + msg)
return
else:
self.status_label.setText(msg)
# 验证输入
if not input_data:
if method == 0:
QMessageBox.warning(self, "输入错误", "请输入搜索关键词")
else:
QMessageBox.warning(self, "输入错误", "请输入Pinterest URL")
return
# 对于URL下载方式,验证URL格式
if method == 1:
pin_id = self.extract_pin_id(input_data)
if not pin_id:
QMessageBox.warning(self, "输入错误", "无法从URL中提取有效ID,请检查URL格式")
return
if start_page > end_page:
QMessageBox.warning(self, "输入错误", "起始页不能大于结束页")
return
# 更新license计数
self.license.update_license()
self.check_license_status()
# 准备下载
self.log_text.clear()
self.progress_bar.setValue(0)
self.download_btn.setEnabled(False)
self.comm.status_signal.emit("正在准备下载...")
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = ImageDownloader()
window.show()
sys.exit(app.exec_())