更新无水印视频提取逻辑
18
README.md
@ -55,6 +55,7 @@ multiple_demo = f"{image_demo} {video_demo}"
|
||||
path = "" # 作品数据/文件保存根路径,默认值:项目根路径
|
||||
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
||||
user_agent = "" # 请求头 User-Agent
|
||||
cookie = "" # 小红书网页版 Cookie,无需登录
|
||||
proxy = "" # 网络代理
|
||||
timeout = 5 # 网络请求超时限制,单位:秒,默认值:10
|
||||
chunk = 1024 * 1024 # 下载文件时,每次从服务器获取的数据块大小,单位:字节
|
||||
@ -64,6 +65,7 @@ max_retry = 2 # 请求数据失败时,重试的最大次数,单位:秒,
|
||||
async with XHS(path=path,
|
||||
folder_name=folder_name,
|
||||
user_agent=user_agent,
|
||||
cookie=cookie,
|
||||
proxy=proxy,
|
||||
timeout=timeout,
|
||||
chunk=chunk,
|
||||
@ -106,6 +108,12 @@ async with XHS(path=path,
|
||||
<td align="center">默认 UA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">cookie</td>
|
||||
<td align="center">str</td>
|
||||
<td align="center">小红书网页版 Cookie,无需登录</td>
|
||||
<td align="center">默认 Cookie</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">proxy</td>
|
||||
<td align="center">str</td>
|
||||
<td align="center">设置代理</td>
|
||||
@ -131,6 +139,16 @@ async with XHS(path=path,
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1>🌐 Cookie</h1>
|
||||
<ol>
|
||||
<li>打开浏览器(可选无痕模式启动),访问小红书任意网页</li>
|
||||
<li>按 <code>F12</code> 打开开发人员工具</li>
|
||||
<li>选择 <code>控制台</code> 选项卡</li>
|
||||
<li>输入 <code>document.cookie</code> 后回车确认</li>
|
||||
<li>输出内容即为所需 Cookie</li>
|
||||
</ol>
|
||||
<br>
|
||||
<img src="static/获取Cookie示意图.png" alt="">
|
||||
<h1>♥️ 支持项目</h1>
|
||||
<p>如果 <b>XHS-Downloader</b> 对您有帮助,请考虑为它点个 <b>Star</b> ⭐,感谢您的支持!</p>
|
||||
<table>
|
||||
|
||||
2
main.py
@ -15,6 +15,7 @@ async def example():
|
||||
path = "" # 作品数据/文件保存根路径,默认值:项目根路径
|
||||
folder_name = "Download" # 作品文件储存文件夹名称(自动创建),默认值:Download
|
||||
user_agent = "" # 请求头 User-Agent
|
||||
cookie = "" # 小红书网页版 Cookie,无需登录
|
||||
proxy = "" # 网络代理
|
||||
timeout = 5 # 网络请求超时限制,单位:秒,默认值:10
|
||||
chunk = 1024 * 1024 # 下载文件时,每次从服务器获取的数据块大小,单位:字节
|
||||
@ -24,6 +25,7 @@ async def example():
|
||||
async with XHS(path=path,
|
||||
folder_name=folder_name,
|
||||
user_agent=user_agent,
|
||||
cookie=cookie,
|
||||
proxy=proxy,
|
||||
timeout=timeout,
|
||||
chunk=chunk,
|
||||
|
||||
@ -29,7 +29,7 @@ class Download:
|
||||
self.proxy = proxy
|
||||
self.chunk = chunk
|
||||
self.session = ClientSession(
|
||||
headers=manager.headers,
|
||||
headers={"User-Agent": manager.headers["User-Agent"]},
|
||||
timeout=ClientTimeout(connect=timeout))
|
||||
self.retry = retry_
|
||||
|
||||
@ -60,16 +60,16 @@ class Download:
|
||||
return True
|
||||
try:
|
||||
async with self.session.get(url, proxy=self.proxy) as response:
|
||||
self.__create_progress(
|
||||
bar, int(
|
||||
response.headers.get(
|
||||
'content-length', 0)) or None)
|
||||
# self.__create_progress(
|
||||
# bar, int(
|
||||
# response.headers.get(
|
||||
# 'content-length', 0)) or None)
|
||||
with temp.open("wb") as f:
|
||||
async for chunk in response.content.iter_chunked(self.chunk):
|
||||
f.write(chunk)
|
||||
self.__update_progress(bar, len(chunk))
|
||||
# self.__update_progress(bar, len(chunk))
|
||||
self.manager.move(temp, file)
|
||||
self.__create_progress(bar, None)
|
||||
# self.__create_progress(bar, None)
|
||||
self.rich_log(log, f"{name} 下载成功")
|
||||
return True
|
||||
except (
|
||||
@ -77,19 +77,19 @@ class Download:
|
||||
ServerDisconnectedError,
|
||||
):
|
||||
self.manager.delete(temp)
|
||||
self.__create_progress(bar, None)
|
||||
# self.__create_progress(bar, None)
|
||||
self.rich_log(log, f"{name} 下载失败", "bright_red")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __create_progress(bar, total: int | None):
|
||||
if bar:
|
||||
bar.update(total=total)
|
||||
# @staticmethod
|
||||
# def __create_progress(bar, total: int | None):
|
||||
# if bar:
|
||||
# bar.update(total=total)
|
||||
|
||||
@staticmethod
|
||||
def __update_progress(bar, advance: int):
|
||||
if bar:
|
||||
bar.advance(advance)
|
||||
# @staticmethod
|
||||
# def __update_progress(bar, advance: int):
|
||||
# if bar:
|
||||
# bar.advance(advance)
|
||||
|
||||
@staticmethod
|
||||
def rich_log(log, text, style="bright_green"):
|
||||
|
||||
@ -6,11 +6,18 @@ __all__ = ["Manager"]
|
||||
|
||||
|
||||
class Manager:
|
||||
def __init__(self, root: Path, ua: str, retry: int):
|
||||
def __init__(self, root: Path, ua: str, cookie: str, retry: int):
|
||||
self.temp = root.joinpath("./temp")
|
||||
self.headers = {
|
||||
"User-Agent": ua or "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", }
|
||||
"Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0",
|
||||
"Cookie": cookie or "abRequestId=54c534bb-a2c6-558f-8e03-5b4c5c45635c; xsecappid=xhs-pc-web; a1=18c286a400"
|
||||
"4jy56qvzejvp631col0hd3032h4zjez50000106381; webId=779c977da3a15b5623015be94bdcc9e9; g"
|
||||
"id=yYSJYK0qDW8KyYSJYK048quV84Vv2KAhudVhJduUKqySlx2818xfq4888y8KqYy8y2y2f8Jy; web_sess"
|
||||
"ion=030037a259ce5f15c8d560dc12224a9fdc2ed1; webBuild=3.19.4; websectiga=984412fef754c"
|
||||
"018e472127b8effd174be8a5d51061c991aadd200c69a2801d6; sec_poison_id=3dd48845-d604-4535"
|
||||
"-bcc2-a859e97518bf; unread={%22ub%22:%22655eb3d60000000032033955%22%2C%22ue%22:%22656"
|
||||
"e9ef2000000003801ff3d%22%2C%22uc%22:29}; cache_feeds=[]"}
|
||||
self.retry = retry
|
||||
|
||||
@staticmethod
|
||||
|
||||
@ -10,6 +10,7 @@ class Settings:
|
||||
"path": "",
|
||||
"folder_name": "Download",
|
||||
"user_agent": "",
|
||||
"cookie": "",
|
||||
"proxy": "",
|
||||
"timeout": 10,
|
||||
"chunk": 1024 * 1024,
|
||||
|
||||
@ -6,7 +6,7 @@ __all__ = ['Video']
|
||||
|
||||
|
||||
class Video:
|
||||
VIDEO_TOKEN = compile(r'"originVideoKey":"(\S+?\\u002F\S+?)"')
|
||||
VIDEO_TOKEN = compile(r'"originVideoKey":"(\S+?)"')
|
||||
|
||||
def get_video_link(self, html: str) -> list:
|
||||
return [Html.format_url(f"https://sns-video-hw.xhscdn.com/{
|
||||
|
||||
@ -6,7 +6,7 @@ from rich.text import Text
|
||||
from textual.app import App
|
||||
from textual.app import ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Center
|
||||
# from textual.containers import Center
|
||||
from textual.containers import HorizontalScroll
|
||||
from textual.containers import ScrollableContainer
|
||||
from textual.widgets import Button
|
||||
@ -28,8 +28,8 @@ from .Video import Video
|
||||
__all__ = ['XHS', 'XHSDownloader']
|
||||
|
||||
RELEASES = "https://github.com/JoeanAmier/XHS-Downloader/releases/latest"
|
||||
VERSION = 1.6
|
||||
BETA = False
|
||||
VERSION = 1.7
|
||||
BETA = True
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
@ -49,13 +49,14 @@ class XHS:
|
||||
path="",
|
||||
folder_name="Download",
|
||||
user_agent: str = None,
|
||||
cookie: str = None,
|
||||
proxy: str = "",
|
||||
timeout=10,
|
||||
chunk=1024 * 1024,
|
||||
max_retry=5,
|
||||
**kwargs,
|
||||
):
|
||||
self.manager = Manager(ROOT, user_agent, max_retry)
|
||||
self.manager = Manager(ROOT, user_agent, cookie, max_retry)
|
||||
self.html = Html(
|
||||
self.manager.headers,
|
||||
proxy,
|
||||
@ -175,10 +176,10 @@ class XHSDownloader(App):
|
||||
HorizontalScroll(Button("下载无水印图片/视频", id="deal"),
|
||||
Button("读取剪贴板", id="paste"),
|
||||
Button("清空输入框", id="reset"), ),
|
||||
Label(Text("程序状态", style="b bright_blue")),
|
||||
# Label(Text("程序状态", style="b bright_blue")),
|
||||
)
|
||||
with Center():
|
||||
yield ProgressBar(total=None)
|
||||
# with Center():
|
||||
# yield ProgressBar(total=None)
|
||||
yield RichLog(markup=True)
|
||||
yield Footer()
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 158 KiB |
BIN
static/获取Cookie示意图.png
Normal file
|
After Width: | Height: | Size: 15 KiB |