กู้รูปเว็บเก่าที่หายไป ด้วย Wayback Machine CDX API + Python
เว็บที่เจ้าของเสียชีวิตไปแล้ว ครอบครัวอยากคงไว้เป็นที่ระลึกตามสภาพเดิม แต่รูปที่ hotlink จากเว็บอื่นกลายเป็นกรอบแตกทั้งเว็บ — archive.org มี API ให้กู้กลับมาได้ ฟรี และได้ผลเกินคาด
พอดีมีเว็บเก่าอายุสิบกว่าปีอยู่เว็บหนึ่งครับ คนทำเว็บเสียชีวิตไปแล้ว ครอบครัวอยากคงเว็บไว้เป็นที่ระลึกตามสภาพเดิมทุกอย่าง ปัญหาคือรูปในเว็บจำนวนมากเจ้าของเคย hotlink มาจากเว็บอื่น — Facebook CDN บ้าง เว็บฝากรูปที่ปิดตัวไปแล้วบ้าง พอต้นทางตาย รูปเลยกลายเป็นกรอบแตกทั้งเว็บ
จะแก้มือด้วยการไล่หารูปทีละรูปไม่ไหวแน่ (ผมนับได้สามร้อยกว่ารูป) เลยเขียนสคริปต์ให้ archive.org ช่วย — สคริปต์ในบทความนี้คือตัวที่ใช้จริง แก้แค่ path กับชื่อโดเมนเป็นค่าสมมติ
หลักการ: CDX API
Wayback Machine มี API ชื่อ CDX ไว้ query ว่า "โดเมนนี้เคยถูก archive อะไรไว้บ้าง" ตัวอย่าง:
http://web.archive.org/cdx/search/cdx?url=oldsite.com&matchType=domain
&filter=statuscode:200
&filter=mimetype:image/(jpeg|png|gif)
&collapse=urlkey
&output=json&limit=5000
&fl=timestamp,original
matchType=domainเอาทั้งโดเมนรวม subdomainfilter=mimetype:image/...เอาเฉพาะรูปcollapse=urlkeyURL ซ้ำเอา record เดียว- ได้ JSON เป็นคู่
[timestamp, url เดิม]
แล้วเวลาดึงไฟล์จริง ใช้ URL รูปแบบนี้:
http://web.archive.org/web/<timestamp>id_/<url เดิม>
แปลว่า "เอาไฟล์ดิบตามต้นฉบับ" — ถ้าไม่ใส่ archive.org จะฉีด toolbar/rewrite HTML มาให้ ซึ่งกับไฟล์รูปคือได้ไฟล์เสีย
แนวคิด 3 ขั้น — ไม่แตะ HTML เลย
หัวใจคือโหลดรูปมาวางที่ path เดิมที่ HTML อ้าง — โครงเว็บเดิมทุกตัวอักษร ไม่ต้อง rewrite อะไรทั้งสิ้น
สคริปต์เต็ม
# -*- coding: utf-8 -*-
# กู้รูปที่หายจาก archive.org Wayback -> วางที่ path เดิมที่ HTML อ้าง (ไม่แตะ HTML)
import os, re, glob, json, urllib.parse, urllib.request, sys, time
DR = '/home/webuser/domains/oldsite.com/public_html'
# 1) รวบรวม missing refs (path ที่ HTML อ้างแต่ไฟล์ไม่มี)
missing = {} # rel_path -> basename(lower)
for f in glob.glob(DR + '/**/*.htm*', recursive=True):
try:
s = open(f, encoding='latin-1', errors='ignore').read()
except Exception:
continue
for m in re.findall(r'src=["\']([^"\']+\.(?:jpg|jpeg|png|gif))["\']', s, re.I):
if m.startswith(('http://', 'https://', '//')):
continue
rel = urllib.parse.unquote(m.split('?')[0]).lstrip('/')
p1 = os.path.normpath(os.path.join(os.path.dirname(f), rel))
p2 = os.path.normpath(os.path.join(DR, rel))
if os.path.exists(p1) or os.path.exists(p2):
continue
missing[rel] = os.path.basename(rel).lower()
print(f'missing refs: {len(missing)}')
# 2) ดึงรายการรูปที่ archive ไว้ทั้งโดเมน
def fetch(url, timeout=60):
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0 recovery'})
return urllib.request.urlopen(req, timeout=timeout).read()
cdx = ("http://web.archive.org/cdx/search/cdx?url=oldsite.com&matchType=domain"
"&filter=statuscode:200&filter=mimetype:image/(jpeg|png|gif)&collapse=urlkey"
"&output=json&limit=5000&fl=timestamp,original")
rows = json.loads(fetch(cdx))
rows = rows[1:] if rows and rows[0][0] == 'timestamp' else rows
arch = {} # basename(lower) -> (timestamp, original) เอา snapshot ล่าสุด
for ts, orig in rows:
bn = urllib.parse.unquote(orig.split('?')[0]).rsplit('/', 1)[-1].lower()
if bn:
arch[bn] = (ts, orig)
print(f'archived images: {len(arch)}')
# 3) จับคู่ด้วย basename แล้วโหลดมาวาง path เดิม
rec = lost = fail = 0
for rel, bn in missing.items():
if bn not in arch:
lost += 1
continue
ts, orig = arch[bn]
way = f'http://web.archive.org/web/{ts}id_/{orig}'
dest = os.path.normpath(os.path.join(DR, rel))
if not dest.startswith(DR) or os.path.exists(dest):
continue
try:
data = fetch(way, timeout=45)
if len(data) < 200: # กันได้หน้า error มาแทนรูป
fail += 1
continue
os.makedirs(os.path.dirname(dest), exist_ok=True)
open(dest, 'wb').write(data)
os.chmod(dest, 0o644)
rec += 1
time.sleep(0.15) # อย่ายิงรัว เกรงใจ archive.org
except Exception:
fail += 1
print(f'RESULT: recovered={rec} lost={lost} fail={fail}')
จุดที่อยากชี้ในสคริปต์
- จับคู่ด้วย basename เพราะรูป hotlink URL ต้นทาง (เช่น CDN) กับ path ที่เว็บอ้างไม่เหมือนกัน แต่ชื่อไฟล์มักเดิม
- เช็ค len(data) < 200 — บางทีได้หน้า HTML error แทนรูป ไฟล์รูปจริงไม่มีทางเล็กขนาดนั้น
- dest.startswith(DR) กัน path traversal จากชื่อไฟล์แปลกๆ ใน HTML เก่า
- time.sleep — archive.org ให้ใช้ฟรี อย่าทำตัวเป็น DDoS ใส่เขา
ผลจริง
เคสของผม: อ้างรูปหาย 378 path กู้กลับมาได้ 35 รูป ที่เหลือคือ archive.org ไม่เคยเก็บไว้ (รูปพวก Facebook CDN ส่วนใหญ่ crawler เข้าไม่ถึงตั้งแต่แรก)
ฟังดูน้อยใช่ไหมครับ — แต่พอไล่ดูจริงๆ รูปที่หายถาวรเกือบทั้งหมดอยู่ในหน้า orphan ที่ไม่มีลิงก์จากหน้าหลักแล้ว หน้าเว็บที่คนกดเข้าถึงได้จริง รูปครบทุกหน้า ถือว่าจบงาน
อยากให้รูปอยู่กับเว็บไปนานๆ ดูดมาเก็บไว้ที่โฮสตัวเองตั้งแต่แรก อย่า hotlink — ต้นทางตายเมื่อไหร่รูปหายเมื่อนั้น
ใครมีเว็บเก่าที่รูปแตกๆ อยู่ ลองเอาสคริปต์ไปปรับใช้ได้ตามสะดวกครับ ของฟรีและได้ผลเกินคาด ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ
อยากให้เราทำให้ไหม?
ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า
เคยเจองานแบบนี้ไหม? ติดตรงไหน?
มาแลกวิธีกันต่อในบอร์ด LinuxThai



ความคิดเห็น 0
ยังไม่มีความคิดเห็น — เป็นคนแรกเลย