mirror of
https://github.com/PaiGramTeam/HonkaiStarRailWikiDataParser.git
synced 2025-01-30 18:38:36 +00:00
✨ support: raiders
This commit is contained in:
parent
7f6dc1a1cd
commit
0d13c764bf
49
func/fetch_raiders.py
Normal file
49
func/fetch_raiders.py
Normal file
@ -0,0 +1,49 @@
|
||||
import asyncio
|
||||
|
||||
import aiofiles
|
||||
from pathlib import Path
|
||||
|
||||
import ujson
|
||||
|
||||
from func.fetch_all import get_list
|
||||
from modules.apihelper.client.components.hyperion import Hyperion
|
||||
|
||||
data_path = Path("data/raiders")
|
||||
data_path.mkdir(exist_ok=True)
|
||||
hyperion = Hyperion()
|
||||
|
||||
|
||||
async def fetch_and_save_photo(name: str, url: str):
|
||||
print(f"Fetch raider photo: {name} {url}")
|
||||
pid = int(url.split("/")[-1])
|
||||
img_list = await hyperion.get_images_by_post_id(6, pid)
|
||||
if not img_list:
|
||||
return
|
||||
if len(img_list) < 3:
|
||||
return
|
||||
img = img_list[2]
|
||||
async with aiofiles.open(data_path / f"{name}.png", "wb") as f:
|
||||
await f.write(img.data)
|
||||
|
||||
|
||||
async def get_raiders():
|
||||
lists = await get_list("63")
|
||||
maps = {}
|
||||
for children in lists:
|
||||
char_name = children.name
|
||||
final_content = None
|
||||
for content in children.list:
|
||||
if content.article_user_name == "初始镜像OriginMirror":
|
||||
final_content = content
|
||||
break
|
||||
if not final_content:
|
||||
continue
|
||||
if not final_content.bbs_url:
|
||||
continue
|
||||
maps[char_name] = final_content.bbs_url
|
||||
tasks = []
|
||||
for key, value in maps.items():
|
||||
tasks.append(fetch_and_save_photo(key, value))
|
||||
await asyncio.gather(*tasks)
|
||||
async with aiofiles.open(data_path / "info.json", "w", encoding="utf-8") as f:
|
||||
await f.write(ujson.dumps(list(maps.keys()), ensure_ascii=False, indent=4))
|
42
main.py
42
main.py
@ -6,12 +6,13 @@ from func.fetch_light_cones import fetch_light_cones, fetch_light_cones_infos, d
|
||||
from func.fetch_materials import fetch_materials, fetch_materials_infos, dump_materials, read_materials
|
||||
from func.fetch_monsters import fetch_monsters, fetch_monsters_infos, dump_monsters, read_monsters
|
||||
from func.fetch_relics import fetch_relics, fetch_relics_infos, dump_relics, read_relics
|
||||
from func.fetch_raiders import get_raiders
|
||||
|
||||
data_path = Path("data")
|
||||
data_path.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
async def main(
|
||||
async def wiki(
|
||||
override_materials: bool = True,
|
||||
override_avatars: bool = True,
|
||||
override_light_cones: bool = True,
|
||||
@ -55,16 +56,35 @@ async def main(
|
||||
await read_relics(data_path / "relics.json")
|
||||
|
||||
|
||||
async def bbs_photos():
|
||||
await get_raiders()
|
||||
|
||||
|
||||
async def main(
|
||||
override_materials: bool = True,
|
||||
override_avatars: bool = True,
|
||||
override_light_cones: bool = True,
|
||||
override_monsters: bool = True,
|
||||
override_relics: bool = True,
|
||||
override_bbs_photos: bool = True,
|
||||
):
|
||||
await wiki(override_materials, override_avatars, override_light_cones, override_monsters, override_relics)
|
||||
if override_bbs_photos:
|
||||
await bbs_photos()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
override_material = True
|
||||
override_avatar = True
|
||||
override_light_cone = True
|
||||
override_monster = True
|
||||
override_relic = True
|
||||
override_material_ = True
|
||||
override_avatar_ = True
|
||||
override_light_cone_ = True
|
||||
override_monster_ = True
|
||||
override_relic_ = True
|
||||
override_bbs_photo_ = True
|
||||
asyncio.run(main(
|
||||
override_material,
|
||||
override_avatar,
|
||||
override_light_cone,
|
||||
override_monster,
|
||||
override_relic,
|
||||
override_material_,
|
||||
override_avatar_,
|
||||
override_light_cone_,
|
||||
override_monster_,
|
||||
override_relic_,
|
||||
override_bbs_photo_,
|
||||
))
|
||||
|
@ -15,6 +15,10 @@ class Content(BaseModel):
|
||||
"""摘要"""
|
||||
title: str
|
||||
"""标题"""
|
||||
article_user_name: str = ""
|
||||
"""作者"""
|
||||
bbs_url: str = ""
|
||||
"""BBS对应地址"""
|
||||
|
||||
@property
|
||||
def data(self) -> Dict:
|
||||
|
0
modules/__init__.py
Normal file
0
modules/__init__.py
Normal file
0
modules/apihelper/__init__.py
Normal file
0
modules/apihelper/__init__.py
Normal file
0
modules/apihelper/client/__init__.py
Normal file
0
modules/apihelper/client/__init__.py
Normal file
0
modules/apihelper/client/base/__init__.py
Normal file
0
modules/apihelper/client/base/__init__.py
Normal file
34
modules/apihelper/client/base/httpxrequest.py
Normal file
34
modules/apihelper/client/base/httpxrequest.py
Normal file
@ -0,0 +1,34 @@
|
||||
from contextlib import AbstractAsyncContextManager
|
||||
from types import TracebackType
|
||||
from typing import Optional, Type
|
||||
|
||||
import httpx
|
||||
|
||||
__all__ = ("HTTPXRequest",)
|
||||
|
||||
|
||||
class HTTPXRequest(AbstractAsyncContextManager):
|
||||
def __init__(self, *args, headers=None, **kwargs):
|
||||
self._client = httpx.AsyncClient(headers=headers, *args, **kwargs)
|
||||
|
||||
async def __aenter__(self):
|
||||
try:
|
||||
await self.initialize()
|
||||
return self
|
||||
except Exception as exc:
|
||||
await self.shutdown()
|
||||
raise exc
|
||||
|
||||
async def __aexit__(
|
||||
self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
|
||||
) -> None:
|
||||
await self.initialize()
|
||||
|
||||
async def initialize(self):
|
||||
if self._client.is_closed:
|
||||
self._client = httpx.AsyncClient()
|
||||
|
||||
async def shutdown(self):
|
||||
if self._client.is_closed:
|
||||
return
|
||||
await self._client.aclose()
|
66
modules/apihelper/client/base/hyperionrequest.py
Normal file
66
modules/apihelper/client/base/hyperionrequest.py
Normal file
@ -0,0 +1,66 @@
|
||||
from typing import Union
|
||||
|
||||
import httpx
|
||||
from httpx import Response
|
||||
|
||||
from .httpxrequest import HTTPXRequest
|
||||
from ...error import NetworkException, ResponseException, APIHelperTimedOut
|
||||
from ...typedefs import POST_DATA, JSON_DATA
|
||||
|
||||
__all__ = ("HyperionRequest",)
|
||||
|
||||
|
||||
class HyperionRequest(HTTPXRequest):
|
||||
async def get(
|
||||
self, url: str, *args, de_json: bool = True, re_json_data: bool = False, **kwargs
|
||||
) -> Union[POST_DATA, JSON_DATA, Response]:
|
||||
try:
|
||||
response = await self._client.get(url=url, *args, **kwargs)
|
||||
except httpx.TimeoutException as err:
|
||||
raise APIHelperTimedOut from err
|
||||
except httpx.HTTPError as exc:
|
||||
raise NetworkException(f"Unknown error in HTTP implementation: {repr(exc)}") from exc
|
||||
if response.is_error:
|
||||
raise ResponseException(message=f"response error in status code: {response.status_code}")
|
||||
if not de_json:
|
||||
return response
|
||||
json_data = response.json()
|
||||
return_code = json_data.get("retcode", None)
|
||||
data = json_data.get("data", None)
|
||||
message = json_data.get("message", None)
|
||||
if return_code is None:
|
||||
return json_data
|
||||
if return_code != 0:
|
||||
if message is None:
|
||||
raise ResponseException(message=f"response error in return code: {return_code}")
|
||||
raise ResponseException(response=json_data)
|
||||
if not re_json_data and data is not None:
|
||||
return data
|
||||
return json_data
|
||||
|
||||
async def post(
|
||||
self, url: str, *args, de_json: bool = True, re_json_data: bool = False, **kwargs
|
||||
) -> Union[POST_DATA, JSON_DATA, Response]:
|
||||
try:
|
||||
response = await self._client.post(url=url, *args, **kwargs)
|
||||
except httpx.TimeoutException as err:
|
||||
raise APIHelperTimedOut from err
|
||||
except httpx.HTTPError as exc:
|
||||
raise NetworkException(f"Unknown error in HTTP implementation: {repr(exc)}") from exc
|
||||
if response.is_error:
|
||||
raise ResponseException(message=f"response error in status code: {response.status_code}")
|
||||
if not de_json:
|
||||
return response
|
||||
json_data = response.json()
|
||||
return_code = json_data.get("retcode", None)
|
||||
data = json_data.get("data", None)
|
||||
message = json_data.get("message", None)
|
||||
if return_code is None:
|
||||
return json_data
|
||||
if return_code != 0:
|
||||
if message is None:
|
||||
raise ResponseException(message=f"response error in return code: {return_code}")
|
||||
raise ResponseException(response=json_data)
|
||||
if not re_json_data and data is not None:
|
||||
return data
|
||||
return json_data
|
0
modules/apihelper/client/components/__init__.py
Normal file
0
modules/apihelper/client/components/__init__.py
Normal file
142
modules/apihelper/client/components/hyperion.py
Normal file
142
modules/apihelper/client/components/hyperion.py
Normal file
@ -0,0 +1,142 @@
|
||||
import asyncio
|
||||
import os
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
from ..base.hyperionrequest import HyperionRequest
|
||||
from ...models.genshin.hyperion import PostInfo, ArtworkImage
|
||||
from ...typedefs import JSON_DATA
|
||||
|
||||
__all__ = ("Hyperion",)
|
||||
|
||||
|
||||
class Hyperion:
|
||||
"""米忽悠bbs相关API请求
|
||||
|
||||
该名称来源于米忽悠的安卓BBS包名结尾,考虑到大部分重要的功能确实是在移动端实现了
|
||||
"""
|
||||
|
||||
POST_FULL_URL = "https://bbs-api.miyoushe.com/post/wapi/getPostFull"
|
||||
POST_FULL_IN_COLLECTION_URL = "https://bbs-api.miyoushe.com/post/wapi/getPostFullInCollection"
|
||||
GET_NEW_LIST_URL = "https://bbs-api.miyoushe.com/post/wapi/getNewsList"
|
||||
GET_OFFICIAL_RECOMMENDED_POSTS_URL = "https://bbs-api.miyoushe.com/post/wapi/getOfficialRecommendedPosts"
|
||||
|
||||
USER_AGENT = (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/90.0.4430.72 Safari/537.36"
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.client = HyperionRequest(headers=self.get_headers(), *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def extract_post_id(text: str) -> int:
|
||||
"""
|
||||
:param text:
|
||||
# https://bbs.mihoyo.com/ys/article/8808224
|
||||
# https://m.bbs.mihoyo.com/ys/article/8808224
|
||||
# https://www.miyoushe.com/ys/article/32497914
|
||||
# https://m.miyoushe.com/ys/#/article/32497914
|
||||
:return: post_id
|
||||
"""
|
||||
rgx = re.compile(r"(?:bbs|www\.)?(?:miyoushe|mihoyo)\.com/[^.]+/article/(?P<article_id>\d+)")
|
||||
matches = rgx.search(text)
|
||||
if matches is None:
|
||||
return -1
|
||||
entries = matches.groupdict()
|
||||
if entries is None:
|
||||
return -1
|
||||
try:
|
||||
art_id = int(entries.get("article_id"))
|
||||
except (IndexError, ValueError, TypeError):
|
||||
return -1
|
||||
return art_id
|
||||
|
||||
def get_headers(self, referer: str = "https://www.miyoushe.com/ys/"):
|
||||
return {"User-Agent": self.USER_AGENT, "Referer": referer}
|
||||
|
||||
@staticmethod
|
||||
def get_list_url_params(forum_id: int, is_good: bool = False, is_hot: bool = False, page_size: int = 20) -> dict:
|
||||
return {
|
||||
"forum_id": forum_id,
|
||||
"gids": 2,
|
||||
"is_good": is_good,
|
||||
"is_hot": is_hot,
|
||||
"page_size": page_size,
|
||||
"sort_type": 1,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_images_params(
|
||||
resize: int = 600, quality: int = 80, auto_orient: int = 0, interlace: int = 1, images_format: str = "jpg"
|
||||
):
|
||||
"""
|
||||
image/resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,jpg
|
||||
:param resize: 图片大小
|
||||
:param quality: 图片质量
|
||||
:param auto_orient: 自适应
|
||||
:param interlace: 未知
|
||||
:param images_format: 图片格式
|
||||
:return:
|
||||
"""
|
||||
params = (
|
||||
f"image/resize,s_{resize}/quality,q_{quality}/auto-orient,"
|
||||
f"{auto_orient}/interlace,{interlace}/format,{images_format}"
|
||||
)
|
||||
return {"x-oss-process": params}
|
||||
|
||||
async def get_official_recommended_posts(self, gids: int) -> JSON_DATA:
|
||||
params = {"gids": gids}
|
||||
response = await self.client.get(url=self.GET_OFFICIAL_RECOMMENDED_POSTS_URL, params=params)
|
||||
return response
|
||||
|
||||
async def get_post_full_in_collection(self, collection_id: int, gids: int = 2, order_type=1) -> JSON_DATA:
|
||||
params = {"collection_id": collection_id, "gids": gids, "order_type": order_type}
|
||||
response = await self.client.get(url=self.POST_FULL_IN_COLLECTION_URL, params=params)
|
||||
return response
|
||||
|
||||
async def get_post_info(self, gids: int, post_id: int, read: int = 1) -> PostInfo:
|
||||
params = {"gids": gids, "post_id": post_id, "read": read}
|
||||
response = await self.client.get(self.POST_FULL_URL, params=params)
|
||||
return PostInfo.paste_data(response)
|
||||
|
||||
async def get_images_by_post_id(self, gids: int, post_id: int) -> List[ArtworkImage]:
|
||||
post_info = await self.get_post_info(gids, post_id)
|
||||
art_list = []
|
||||
task_list = [
|
||||
self.download_image(post_info.post_id, post_info.image_urls[page], page)
|
||||
for page in range(len(post_info.image_urls))
|
||||
]
|
||||
result_list = await asyncio.gather(*task_list)
|
||||
for result in result_list:
|
||||
if isinstance(result, ArtworkImage):
|
||||
art_list.append(result)
|
||||
|
||||
def take_page(elem: ArtworkImage):
|
||||
return elem.page
|
||||
|
||||
art_list.sort(key=take_page)
|
||||
return art_list
|
||||
|
||||
async def download_image(self, art_id: int, url: str, page: int = 0) -> ArtworkImage:
|
||||
filename = os.path.basename(url)
|
||||
_, file_extension = os.path.splitext(filename)
|
||||
is_image = bool(file_extension in ".jpg" or file_extension in ".png")
|
||||
response = await self.client.get(
|
||||
url, params=self.get_images_params(resize=2000) if is_image else None, timeout=10, de_json=False
|
||||
)
|
||||
return ArtworkImage(
|
||||
art_id=art_id, page=page, file_name=filename, file_extension=url.split(".")[-1], data=response.content
|
||||
)
|
||||
|
||||
async def get_new_list(self, gids: int, type_id: int, page_size: int = 20):
|
||||
"""
|
||||
?gids=2&page_size=20&type=3
|
||||
:return:
|
||||
"""
|
||||
params = {"gids": gids, "page_size": page_size, "type": type_id}
|
||||
response = await self.client.get(url=self.GET_NEW_LIST_URL, params=params)
|
||||
return response
|
||||
|
||||
async def close(self):
|
||||
await self.client.shutdown()
|
41
modules/apihelper/error.py
Normal file
41
modules/apihelper/error.py
Normal file
@ -0,0 +1,41 @@
|
||||
from typing import Any, Mapping, Optional
|
||||
|
||||
|
||||
class APIHelperException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NetworkException(APIHelperException):
|
||||
pass
|
||||
|
||||
|
||||
class APIHelperTimedOut(APIHelperException):
|
||||
pass
|
||||
|
||||
|
||||
class ResponseException(APIHelperException):
|
||||
code: int = 0
|
||||
message: str = ""
|
||||
|
||||
def __init__(self, response: Optional[Mapping[str, Any]] = None, message: Optional[str] = None) -> None:
|
||||
if response is None:
|
||||
self.message = message
|
||||
_message = message
|
||||
else:
|
||||
self.code = response.get("retcode", self.code)
|
||||
self.message = response.get("message", "")
|
||||
_message = f"[{self.code}] {self.message}"
|
||||
|
||||
super().__init__(_message)
|
||||
|
||||
|
||||
class DataNotFoundError(ResponseException):
|
||||
def __init__(self):
|
||||
message = "response data not find"
|
||||
super().__init__(message=message)
|
||||
|
||||
|
||||
class ReturnCodeError(ResponseException):
|
||||
def __init__(self):
|
||||
message = "response return code error"
|
||||
super().__init__(message=message)
|
0
modules/apihelper/models/__init__.py
Normal file
0
modules/apihelper/models/__init__.py
Normal file
0
modules/apihelper/models/genshin/__init__.py
Normal file
0
modules/apihelper/models/genshin/__init__.py
Normal file
66
modules/apihelper/models/genshin/hyperion.py
Normal file
66
modules/apihelper/models/genshin/hyperion.py
Normal file
@ -0,0 +1,66 @@
|
||||
from io import BytesIO
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from pydantic import BaseModel, PrivateAttr
|
||||
|
||||
__all__ = ("ArtworkImage", "PostInfo")
|
||||
|
||||
|
||||
class ArtworkImage(BaseModel):
|
||||
art_id: int
|
||||
page: int = 0
|
||||
data: bytes = b""
|
||||
file_name: Optional[str] = None
|
||||
file_extension: Optional[str] = None
|
||||
is_error: bool = False
|
||||
|
||||
@property
|
||||
def format(self) -> Optional[str]:
|
||||
if not self.is_error:
|
||||
try:
|
||||
with BytesIO(self.data) as stream, Image.open(stream) as im:
|
||||
return im.format
|
||||
except UnidentifiedImageError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
class PostInfo(BaseModel):
|
||||
_data: dict = PrivateAttr()
|
||||
post_id: int
|
||||
user_uid: int
|
||||
subject: str
|
||||
image_urls: List[str]
|
||||
created_at: int
|
||||
video_urls: List[str]
|
||||
|
||||
def __init__(self, _data: dict, **data: Any):
|
||||
super().__init__(**data)
|
||||
self._data = _data
|
||||
|
||||
@classmethod
|
||||
def paste_data(cls, data: dict) -> "PostInfo":
|
||||
_data_post = data["post"]
|
||||
post = _data_post["post"]
|
||||
post_id = post["post_id"]
|
||||
subject = post["subject"]
|
||||
image_list = _data_post["image_list"]
|
||||
image_urls = [image["url"] for image in image_list]
|
||||
vod_list = _data_post["vod_list"]
|
||||
video_urls = [vod["resolutions"][-1]["url"] for vod in vod_list]
|
||||
created_at = post["created_at"]
|
||||
user = _data_post["user"] # 用户数据
|
||||
user_uid = user["uid"] # 用户ID
|
||||
return PostInfo(
|
||||
_data=data,
|
||||
post_id=post_id,
|
||||
user_uid=user_uid,
|
||||
subject=subject,
|
||||
image_urls=image_urls,
|
||||
video_urls=video_urls,
|
||||
created_at=created_at,
|
||||
)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self._data[item]
|
6
modules/apihelper/typedefs.py
Normal file
6
modules/apihelper/typedefs.py
Normal file
@ -0,0 +1,6 @@
|
||||
from typing import Any, Dict
|
||||
|
||||
__all__ = ("POST_DATA", "JSON_DATA")
|
||||
|
||||
POST_DATA = Dict[str, Any]
|
||||
JSON_DATA = Dict[str, Any]
|
82
poetry.lock
generated
82
poetry.lock
generated
@ -240,6 +240,86 @@ html5 = ["html5lib"]
|
||||
htmlsoup = ["BeautifulSoup4"]
|
||||
source = ["Cython (>=0.29.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "9.5.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"},
|
||||
{file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"},
|
||||
{file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"},
|
||||
{file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"},
|
||||
{file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"},
|
||||
{file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"},
|
||||
{file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"},
|
||||
{file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"},
|
||||
{file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"},
|
||||
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"},
|
||||
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"},
|
||||
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"},
|
||||
{file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"},
|
||||
{file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"},
|
||||
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"},
|
||||
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"},
|
||||
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"},
|
||||
{file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"},
|
||||
{file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.7"
|
||||
@ -407,4 +487,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "92029b38a714a18b26df688fd37a5257054a4ba90bf34454f08fc851a82dda5c"
|
||||
content-hash = "728bb8f13eb465e9b8068848bd66dae954aad973ea5a0251c94f5c5b24da368f"
|
||||
|
@ -15,6 +15,7 @@ pydantic = "^1.10.7"
|
||||
beautifulsoup4 = "^4.12.2"
|
||||
aenum = "^3.1.12"
|
||||
lxml = "^4.9.2"
|
||||
pillow = "^9.5.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
@ -8,6 +8,7 @@ httpcore==0.17.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httpx==0.24.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
idna==3.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
lxml==4.9.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pillow==9.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pydantic==1.10.7 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sniffio==1.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
soupsieve==2.4.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
|
Loading…
Reference in New Issue
Block a user