Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import itertools
- from datetime import datetime, timedelta
- import time
- from typing import List, Optional, Tuple
- import requests
- PIXIV_ARTWORKS_URL = "https://www.pixiv.net/artworks/"
- ARTWORKS_DETAIL_ENDPOINT = "https://www.pixiv.net/ajax/illust/"
- ARTWORKS_EXT_LIST = ("jpg", "png", "gif") #複数の拡張子を混ぜるとjpgに変換されるのでjpg優先
- ARTWORKS_TEMPLATE = (
- "https://i.pximg.net/img-original/img/{timestamp}/{id}_p{number}.{ext}"
- )
- session = requests.Session()
- session.headers.update(
- {
- "Referer": "https://pixiv.net/",
- "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/135.0.7049.53 Mobile/15E148 Safari/604.1",
- }
- )
- def get_artwork_timestamp(artwork_id: int) -> Optional[str]:
- try:
- response = session.get(f"{ARTWORKS_DETAIL_ENDPOINT}{artwork_id}", timeout=10)
- response.raise_for_status()
- except requests.RequestException as e:
- print(f"IDの取得に失敗しました {artwork_id}: {e}")
- return None
- try:
- artwork_data = response.json().get("body", {}).get("userIllusts", {})
- timestamp = artwork_data.get(str(artwork_id), {}).get("updateDate")
- if not timestamp:
- print(f"タイムスタンプが見つかりませんでした {artwork_id}")
- return timestamp
- except ValueError as e:
- print(f"Jsonのパースに失敗しました {artwork_id}: {e}")
- return None
- def find_valid_id(
- start_id: int, step: int, max_attempts: int = 30, interval: float = 0.5
- ) -> Optional[Tuple[int, str]]:
- current_id = start_id
- for attempt in range(max_attempts):
- timestamp = get_artwork_timestamp(current_id)
- if timestamp is not None:
- print(f"有効なIDを見つけました: {current_id} タイムスタンプ: {timestamp}")
- return current_id, timestamp
- else:
- print(f"タイムスタンプの取得に失敗しました: {current_id}, 次のIDを取得します...")
- current_id += step
- time.sleep(interval)
- print(
- f"ID {start_id} から {max_attempts} 回試行しましたが、有効なIDを見つけられませんでした"
- )
- return None
- def generate_timestamps(start: datetime, end: datetime):
- current = start
- while current <= end:
- yield current.strftime("%Y/%m/%d/%H/%M/%S")
- current += timedelta(seconds=1)
- def check_all_pattern_artworks(
- start: datetime, end: datetime, artwork_id: int, interval: float = 0.5
- ) -> Optional[Tuple[str, str, str]]:
- for ext in ARTWORKS_EXT_LIST:
- for ts in generate_timestamps(start, end):
- url = ARTWORKS_TEMPLATE.format(
- timestamp=ts, id=artwork_id, number=0, ext=ext
- )
- response = session.head(url, timeout=10)
- if response.status_code == 200:
- print("ベースリンクの取得に成功しました:" + url)
- return url, ts, ext
- else:
- print("URLが見つかりませんでした:" + url)
- time.sleep(interval)
- return None
- def get_all_artworks_images(artwork_id: int, timestamp: str, ext: str, interval: float = 0.5) -> List[str]:
- urls = []
- for i in itertools.count():
- url = ARTWORKS_TEMPLATE.format(
- timestamp=timestamp, id=artwork_id, number=i, ext=ext
- )
- response = session.head(url, timeout=10)
- if response.status_code == 200:
- urls.append(url)
- print("取得に成功しました:" + url)
- time.sleep(interval)
- else:
- break
- return urls
- def salvage_pixiv(artwork_id: int, interval: float = 0.5) -> Optional[List[str]]:
- start_result = find_valid_id(start_id=artwork_id - 1, step=-1, interval=interval)
- if start_result is None:
- return None
- start_id, start_timestamp = start_result
- end_result = find_valid_id(start_id=artwork_id + 1, step=1)
- if end_result is None:
- return None
- end_id, end_timestamp = end_result
- start_datetime = datetime.fromisoformat(start_timestamp)
- end_datetime = datetime.fromisoformat(end_timestamp)
- result = check_all_pattern_artworks(start_datetime, end_datetime, artwork_id, interval)
- if result is None:
- return None
- url, ts, ext = result
- return get_all_artworks_images(artwork_id, ts, ext, interval)
- if "__main__" == __name__:
- artwork_id = int(input("IDを入力してください:").strip())
- interval = 0.75 #HEADがメインなので0.5秒くらいでも多分大丈夫。ただ長ければ長いほど安全
- result = salvage_pixiv(artwork_id, interval=interval)
- if result is not None:
- BAR_LENGTH = 80
- print("=" * BAR_LENGTH)
- print(f"{len(result)}件の画像をサルベージしました")
- print("-" * BAR_LENGTH)
- for i, url in enumerate(result, start=1):
- print(f"[{i:02d}] {url}")
- print("=" * BAR_LENGTH)
- else:
- print("サルベージに失敗しました")
Advertisement
Add Comment
Please, Sign In to add comment