更新项目代码

This commit is contained in:
JoeamAmier
2023-12-03 22:45:36 +08:00
parent ceb3757085
commit 981477fd95
5 changed files with 58 additions and 68 deletions

View File

@@ -1,6 +1,6 @@
<div align="center">
<img src="static/XHS-Downloader.png" alt="" height="256" width="256"><br>
<h1>小红书作品采集工具</h1>
<h1>XHS-Downloader</h1>
<img alt="GitHub" src="https://img.shields.io/github/license/JoeanAmier/XHS-Downloader?style=for-the-badge">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/JoeanAmier/XHS-Downloader?style=for-the-badge&color=c56cf0">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/JoeanAmier/XHS-Downloader?style=for-the-badge&color=fff200">
@@ -11,21 +11,21 @@
<h1>📑 功能清单</h1>
<ul>
<li>✅ 采集小红书图文/视频作品信息</li>
<li>✅ 获取小红书图文/视频作品下载地址</li>
<li>✅ 下载小红书图文/视频作品文件</li>
<li>✅ 自动跳过已存在的作品文件</li>
<li>✅ 获取小红书图文/视频作品文件下载地址</li>
<li>✅ 下载小红书无水印图文/视频作品文件</li>
<li>✅ 自动跳过已下载的作品文件</li>
<li>✅ 作品文件完整性处理机制</li>
<li>✅ 批量下载小红书作品文件</li>
</ul>
<h1>📸 程序截图</h1>
<br>
<img src="static/程序运行截图.png" alt="">
<h1>🔗 支持链接</h1>
<ul>
<li>https://www.xiaohongshu.com/explore/作品ID</li>
<li>https://www.xiaohongshu.com/discovery/item/作品ID</li>
<li>https://xhslink.com/分享码</li>
<p>可以单次输入多个作品链接,链接之间使用空格分隔。</p>
<li><code>https://www.xiaohongshu.com/explore/作品ID</code></li>
<li><code>https://www.xiaohongshu.com/discovery/item/作品ID</code></li>
<li><code>https://xhslink.com/分享码</code></li>
<br/>
<p><b>可以单次输入多个作品链接,链接之间使用空格分隔。</b></p>
</ul>
<h1>🪟 关于终端</h1>
<p>⭐ 推荐使用 <a href="https://learn.microsoft.com/zh-cn/windows/terminal/install">Windows 终端</a> Windows 11 自带默认终端)运行程序以便获得最佳显示效果!</p>

View File

@@ -1,4 +1,5 @@
from source import XHS
from source import XHSDownloader
def example():
@@ -30,5 +31,6 @@ def example():
if __name__ == '__main__':
example()
# XHSDownloader().run()
# example()
with XHSDownloader() as xhs:
xhs.run()

View File

@@ -2,14 +2,13 @@ from pathlib import Path
from shutil import move
from shutil import rmtree
__all__ = ['Manager']
__all__ = ['Manager', "rich_log"]
class Manager:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/119.0.0.0 Safari/537.36",
}
"Chrome/119.0.0.0 Safari/537.36", }
def __init__(self, root: Path):
self.temp = root.joinpath("./temp")
@@ -28,3 +27,8 @@ class Manager:
def clean(self):
rmtree(self.temp.resolve())
def rich_log(log, text):
if log:
log.write(text)

View File

@@ -12,13 +12,14 @@ from textual.widgets import Footer
from textual.widgets import Header
from textual.widgets import Input
from textual.widgets import Label
from textual.widgets import Log
from textual.widgets import RichLog
from .Downloader import Download
from .Explore import Explore
from .Html import Html
from .Image import Image
from .Manager import Manager
from .Manager import rich_log
from .Settings import Settings
from .Video import Video
@@ -54,45 +55,51 @@ class XHS:
chunk,
timeout)
def __get_image(self, container: dict, html: str, download):
def __get_image(self, container: dict, html: str, download, log):
urls = self.image.get_image_link(html)
# rich_log(log, urls) # 调试代码
if download:
self.download.run(urls, self.__naming_rules(container), 1)
container["下载地址"] = urls
def __get_video(self, container: dict, html: str, download):
def __get_video(self, container: dict, html: str, download, log):
url = self.video.get_video_link(html)
# rich_log(log, url) # 调试代码
if download:
self.download.run(url, self.__naming_rules(container), 0)
container["下载地址"] = url
def extract(self, url: str, download=False) -> list[dict]:
def extract(self, url: str, download=False, log=None) -> list[dict]:
urls = self.__deal_links(url)
# return urls
return [self.__deal_extract(i, download) for i in urls]
# rich_log(log, urls) # 调试代码
# return urls # 调试代码
return [self.__deal_extract(i, download, log) for i in urls]
def __deal_links(self, url: str) -> list:
urls = []
for i in url.split():
if u := self.short.search(i):
i = self.html.request_url(u.group(), headers=self.manager.headers, text=False)
i = self.html.request_url(
u.group(), headers=self.manager.headers, text=False)
if u := self.share.search(i):
urls.append(u.group())
elif u := self.link.search(i):
urls.append(u.group())
return urls
def __deal_extract(self, url: str, download: bool):
def __deal_extract(self, url: str, download: bool, log):
html = self.html.request_url(url)
# rich_log(log, html) # 调试代码
if not html:
return {}
data = self.explore.run(html)
# rich_log(log, data) # 调试代码
if not data:
return {}
if data["作品类型"] == "视频":
self.__get_video(data, html, download)
self.__get_video(data, html, download, log)
else:
self.__get_image(data, html, download)
self.__get_image(data, html, download, log)
return data
@staticmethod
@@ -109,35 +116,36 @@ class XHS:
class XHSDownloader(App):
VERSION = 1.6
Beta = True
BETA = True
ROOT = Path(__file__).resolve().parent.parent
APP = XHS(**Settings(ROOT).run())
CSS_PATH = ROOT.joinpath(
"static/XHS-Downloader.tcss")
BINDINGS = [
Binding(key="q", action="quit", description="退出程序"),
Binding(key="q", action="quit", description="结束运行"),
("d", "toggle_dark", "切换主题"),
]
# APP = XHS(**Settings().run())
def __enter__(self):
return self
# def __enter__(self):
# return self
# def __exit__(self, exc_type, exc_value, traceback):
# self.manager.clean()
def __exit__(self, exc_type, exc_value, traceback):
self.APP.manager.clean()
def compose(self) -> ComposeResult:
yield Header()
yield ScrollableContainer(Label("请输入小红书图文/视频作品链接(多个链接使用空格分隔)"),
Input(placeholder="URL"),
yield ScrollableContainer(Label("请输入小红书图文/视频作品链接:"),
Input(placeholder="多个链接之间使用空格分隔"),
HorizontalScroll(Button("下载无水印图片/视频", id="deal"),
Button("读取剪贴板", id="paste"),
Button("清空输入框", id="reset"), ))
yield Log(auto_scroll=True)
yield RichLog(markup=True)
yield Footer()
def on_mount(self) -> None:
self.title = f"小红书作品采集工具 V{self.VERSION}{" Beta" if self.Beta else ""}"
self.title = f"XHS-Downloader V{
self.VERSION}{
" Beta" if self.BETA else ""}"
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "deal":
@@ -148,14 +156,8 @@ class XHSDownloader(App):
self.query_one(Input).value = paste()
def deal(self):
url = self.query_one(Input).value
log = self.query_one(Log)
if not url:
log.write_line("未输入任何作品链接!")
else:
self.APP.extract(url, True, log)
self.query_one(Input).value = ""
class FakeGUI:
pass
url = self.query_one(Input)
log = self.query_one(RichLog)
if self.APP.extract(url.value, True, log=log):
pass
url.value = ""

View File

@@ -1,23 +1,13 @@
Screen {
layout: grid;
grid-size: 1 2;
grid-rows: 1fr;
grid-columns: 1fr;
grid-gutter: 1;
}
Button {
width: 1fr;
margin: 1 1;
text-style: bold;
}
Button#deal {
tint: green 35%;
}
Button#paste {
tint: green 35%;
Button#deal, Button#paste {
tint: green 40%;
}
Button#reset {
tint: red 35%;
tint: red 40%;
}
Label {
width: 100%;
@@ -26,11 +16,3 @@ Label {
content-align-vertical: middle;
text-style: bold;
}
ScrollableContainer {
row-span: 1;
column-span: 1;
}
Log {
row-span: 1;
column-span: 1;
}