diff --git a/README.md b/README.md
index d90c8bb..68def23 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,20 @@ print(xhs.extract(video_demo, download=download))
♥️ 支持项目
如果 XHS-Downloader 对您有帮助,请考虑为它点个 Star ⭐,感谢您的支持!
+
+
+
+| 微信(WeChat) |
+支付宝(Alipay) |
+
+
+
+ |
+ |
+
+
+
+如果您愿意,可以考虑提供资助为 XHS-Downloader 提供额外的支持!
✉️ 联系作者
- QQ: 2437596031
diff --git a/main.py b/main.py
index 622c109..dd34acb 100644
--- a/main.py
+++ b/main.py
@@ -1,5 +1,4 @@
from source import XHS
-from source import XHSDownloader
def example():
@@ -8,6 +7,9 @@ def example():
error_demo = "https://github.com/JoeanAmier/XHS_Downloader"
image_demo = "https://www.xiaohongshu.com/explore/63b275a30000000019020185"
video_demo = "https://www.xiaohongshu.com/explore/64edb460000000001f03cadc"
+ multiple_demo = (
+ "https://www.xiaohongshu.com/explore/63b275a30000000019020185 "
+ "https://www.xiaohongshu.com/explore/64edb460000000001f03cadc")
# 实例对象
path = "" # 作品下载储存根路径,默认值:当前路径
folder = "Download" # 作品下载文件夹名称(自动创建),默认值:Download
@@ -23,13 +25,14 @@ def example():
timeout=timeout,
chunk=chunk, ) # 使用自定义参数
# xhs = XHS() # 使用默认参数
- download = True # 是否下载作品文件
+ download = False # 是否下载作品文件
# 返回作品详细信息,包括下载地址
print(xhs.extract(error_demo)) # 获取数据失败时返回空字典
print(xhs.extract(image_demo, download=download))
print(xhs.extract(video_demo, download=download))
+ print(xhs.extract(multiple_demo, download=download))
if __name__ == '__main__':
- # example()
- XHSDownloader().run()
+ example()
+ # XHSDownloader().run()
diff --git a/source/Download.py b/source/Download.py
index 71d993a..e503c7e 100644
--- a/source/Download.py
+++ b/source/Download.py
@@ -18,7 +18,7 @@ class Download:
folder: str,
headers: dict,
proxies=None,
- chunk=256 * 1024, ):
+ chunk=1024 * 1024, ):
self.temp = root.joinpath("./temp")
self.root = self.__init_root(root, path, folder)
self.headers = self.__delete_cookie(headers)
@@ -30,14 +30,12 @@ class Download:
self.chunk = chunk
def __init_root(self, root: Path, path: str, folder: str) -> Path:
- if path and (r := Path(path)).exists():
+ if path and (r := Path(path)).is_dir():
root = r.joinpath(folder or "Download")
else:
root = root.joinpath(folder or "Download")
- if not root.is_dir():
- root.mkdir()
- if not self.temp.is_dir():
- self.temp.mkdir()
+ root.mkdir(exist_ok=True)
+ self.temp.mkdir(exist_ok=True)
return root
def run(self, urls: list, name: str, type_: int, log):
diff --git a/source/Html.py b/source/Html.py
index 7f405bc..51521f4 100644
--- a/source/Html.py
+++ b/source/Html.py
@@ -1,4 +1,3 @@
-from requests import ReadTimeout
from requests import exceptions
from requests import get
@@ -37,7 +36,7 @@ class Html:
exceptions.SSLError,
exceptions.ChunkedEncodingError,
exceptions.ConnectionError,
- ReadTimeout,
+ exceptions.ReadTimeout,
):
print("获取网页源码失败,请尝试设置 Cookie 后重试!")
return ""
diff --git a/source/Settings.py b/source/Settings.py
index 0576559..10444d3 100644
--- a/source/Settings.py
+++ b/source/Settings.py
@@ -2,7 +2,7 @@ from json import dump
from json import load
from pathlib import Path
-__all__ = ['Settings', 'Batch']
+__all__ = ['Settings']
class Settings:
@@ -13,7 +13,7 @@ class Settings:
"cookie": "",
"proxies": None,
"timeout": 10,
- "chunk": 256 * 1024,
+ "chunk": 1024 * 1024,
}
def run(self):
@@ -25,19 +25,9 @@ class Settings:
def create(self) -> dict:
with self.file.open("w", encoding="utf-8") as f:
- dump(self.default, f, indent=2)
+ dump(self.default, f, indent=4)
return self.default
def update(self, data: dict):
with self.file.open("w", encoding="utf-8") as f:
- dump(data, f, indent=2, ensure_ascii=False)
-
-
-class Batch:
- file = Path("../xhs.txt")
-
- def read_txt(self) -> list:
- if self.file.is_file():
- with self.file.open("r") as f:
- return [i.rstrip('\n') for i in f.readlines()]
- return []
+ dump(data, f, indent=4, ensure_ascii=False)
diff --git a/source/__init__.py b/source/__init__.py
index 64206fb..a427dbb 100644
--- a/source/__init__.py
+++ b/source/__init__.py
@@ -18,7 +18,6 @@ from .Download import Download
from .Explore import Explore
from .Html import Html
from .Image import Image
-from .Settings import Batch
from .Settings import Settings
from .Video import Video
@@ -45,7 +44,7 @@ class XHS:
cookie=None,
proxies=None,
timeout=10,
- chunk=256 * 1024,
+ chunk=1024 * 1024,
):
self.__update_cookie(cookie)
self.html = Html(self.headers, proxies, timeout)
@@ -72,16 +71,14 @@ class XHS:
self.download.run(url, self.__naming_rules(container), 0, log)
container["下载地址"] = url
- def extract(self, url: str, download=False, log=None) -> dict:
+ def extract(self, url: str, download=False, log=None) -> dict | list[dict]:
if not self.__check(url):
- print(f"无效的作品链接: {url}")
return {}
html = self.html.get_html(url)
if not html:
return {}
data = self.explore.run(html)
if not data:
- print(f"获取作品数据失败: {url}")
return {}
if data["作品类型"] == "视频":
self.__get_video(data, html, download, log)
@@ -105,21 +102,20 @@ class XHS:
class XHSDownloader(App):
VERSION = 1.6
Beta = True
- CSS_PATH = Path(__file__).resolve().parent.parent.joinpath(
+ ROOT = Path(__file__).resolve().parent.parent
+ CSS_PATH = ROOT.joinpath(
"static/XHS-Downloader.tcss")
BINDINGS = [
Binding(key="q", action="quit", description="退出程序"),
("d", "toggle_dark", "切换主题"),
]
APP = XHS(**Settings().run())
- Batch = Batch()
def compose(self) -> ComposeResult:
yield Header()
- yield ScrollableContainer(Label("请输入小红书图文/视频作品链接:"),
+ yield ScrollableContainer(Label("请输入小红书图文/视频作品链接(多个链接使用空格分隔):"),
Input(placeholder="URL"),
- HorizontalScroll(Button("下载无水印图片/视频", id="solo"),
- Button("读取 xhs.txt 文件并批量下载作品", id="batch"),
+ HorizontalScroll(Button("下载无水印图片/视频", id="deal"),
Button("读取剪贴板", id="paste"),
Button("清空输入框", id="reset"), ))
yield Log(auto_scroll=True)
@@ -129,26 +125,22 @@ class XHSDownloader(App):
self.title = f"小红书作品采集工具 V{self.VERSION}{" Beta" if self.Beta else ""}"
def on_button_pressed(self, event: Button.Pressed) -> None:
- if event.button.id == "solo":
- self.solo()
- elif event.button.id == "batch":
- self.batch()
+ if event.button.id == "deal":
+ self.deal()
elif event.button.id == "reset":
self.query_one(Input).value = ""
elif event.button.id == "paste":
self.query_one(Input).value = paste()
- def solo(self):
+ def deal(self):
url = self.query_one(Input).value
log = self.query_one(Log)
- log.write_line(f"当前作品链接: {url}")
- self.APP.extract(url, True, log)
-
- def batch(self):
- urls = self.Batch.read_txt()
- log = self.query_one(Log)
- if not urls:
- log.write_line("未检测到 xhs.txt 文件 或者 该文件为空!")
- for url in urls:
- log.write_line(f"当前作品链接: {url}")
+ if not url:
+ log.write_line("未输入任何作品链接!")
+ else:
self.APP.extract(url, True, log)
+ self.query_one(Input).value = ""
+
+
+class FakeGUI:
+ pass
diff --git a/static/XHS-Downloader.tcss b/static/XHS-Downloader.tcss
index e8ac86e..2f39944 100644
--- a/static/XHS-Downloader.tcss
+++ b/static/XHS-Downloader.tcss
@@ -10,10 +10,7 @@ Button {
margin: 1 1;
text-style: bold;
}
-Button#solo {
- tint: green 35%;
-}
-Button#batch {
+Button#deal {
tint: green 35%;
}
Button#paste {
diff --git a/static/微信赞助二维码.png b/static/微信赞助二维码.png
new file mode 100644
index 0000000..ab6a46e
Binary files /dev/null and b/static/微信赞助二维码.png differ
diff --git a/static/支付宝赞助二维码.png b/static/支付宝赞助二维码.png
new file mode 100644
index 0000000..18676ab
Binary files /dev/null and b/static/支付宝赞助二维码.png differ