추가 수정했는데 안되네.

This commit is contained in:
2026-06-07 13:03:52 +09:00
parent 012ee66b88
commit be74808db7
2 changed files with 99 additions and 42 deletions
Binary file not shown.
+100 -43
View File
@@ -3,14 +3,29 @@ from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError from urllib.error import URLError, HTTPError
import re import re
from html import unescape from html import unescape
from urllib.parse import urlparse, parse_qs, unquote
from html.parser import HTMLParser
TARGET_URL = "https://m.slrclub.com/l/free" TARGET_URL = "https://m.slrclub.com/l/free"
class ProxyHandler(BaseHTTPRequestHandler): class ProxyHandler(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
requested_path = self.path # parse query params for skip/limit and optional path override
if requested_path == "/" or requested_path == "": parsed = urlparse(self.path)
requested_path = "/l/free" qs = parse_qs(parsed.query)
try:
skip = int(qs.get('skip', ['0'])[0])
except Exception:
skip = 0
try:
limit = int(qs.get('limit', ['10'])[0])
except Exception:
limit = 10
# Path to fetch on the remote site. If `path` query provided, use it; otherwise use request path or default.
requested_path = qs.get('path', [unquote(parsed.path or '')])[0]
if requested_path in ('', '/', None):
requested_path = '/l/free'
target_url = f"https://m.slrclub.com{requested_path}" target_url = f"https://m.slrclub.com{requested_path}"
@@ -27,46 +42,87 @@ class ProxyHandler(BaseHTTPRequestHandler):
charset = response.headers.get_content_charset(failobj="utf-8") charset = response.headers.get_content_charset(failobj="utf-8")
raw_html = response.read().decode(charset, errors="replace") raw_html = response.read().decode(charset, errors="replace")
# Extract up to 10 post entries (제목 + 링크) and render a simple list. # Extract links using HTMLParser to better preserve anchor text, titles, and img alts
items = [] class LinkExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.stack = []
self.anchors = []
self.current = None
# First try: find anchors inside list items (common for post lists) def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
self.stack.append((tag, attrs))
if tag == 'a':
self.current = {
'href': attrs.get('href', '').strip(),
'title': attrs.get('title', '').strip(),
'text': '',
'ancestors': [t for t, a in self.stack[:-1]],
}
if tag == 'img' and self.current is not None:
alt = attrs.get('alt') or attrs.get('title') or ''
if alt:
self.current.setdefault('img_alt', alt.strip())
def handle_data(self, data):
if self.current is not None:
self.current['text'] += data
def handle_endtag(self, tag):
if not self.stack:
return
top_tag, top_attrs = self.stack.pop()
if tag == 'a' and self.current is not None:
href = (self.current.get('href') or '').strip()
text = (self.current.get('text') or '').strip()
title = (self.current.get('title') or '').strip()
img_alt = (self.current.get('img_alt') or '').strip()
final = text or title or img_alt
ancestors = self.current.get('ancestors', [])
self.anchors.append({'href': href, 'text': unescape(final), 'ancestors': ancestors})
self.current = None
parser = LinkExtractor()
parser.feed(raw_html)
# Prepare li blocks to help extract nearby text when anchor text is empty
li_blocks = re.findall(r"<li[^>]*>(.*?)</li>", raw_html, flags=re.DOTALL | re.IGNORECASE) li_blocks = re.findall(r"<li[^>]*>(.*?)</li>", raw_html, flags=re.DOTALL | re.IGNORECASE)
items = []
for a in parser.anchors:
href = a['href']
txt = (a['text'] or '').strip()
if not href:
continue
if href.lower().startswith('javascript:'):
continue
# skip anchors inside nav/header/footer elements
anc = ' '.join(a.get('ancestors', [])).lower()
if any(k in anc for k in ('nav', 'header', 'footer', 'menu', 'notice', 'gnb', 'util')):
continue
# If anchor text is empty, try to find text inside the same <li> block
if not txt:
for block in li_blocks: for block in li_blocks:
m = re.search(r"<a[^>]+href=[\"']([^\"']+)[\"'][^>]*>(.*?)</a>", block, flags=re.DOTALL | re.IGNORECASE) if href in block:
if m: cand = re.sub(r"<[^>]+>", "", block).strip()
href = m.group(1).strip() # pick the first non-empty line as title
anchor_html = m.group(0) for line in cand.splitlines():
inner_html = m.group(2) line = line.strip()
txt = re.sub(r"<[^>]+>", "", inner_html).strip() if line:
txt = unescape(txt) txt = unescape(line)
break
# If inner text is empty, try anchor title or image alt attributes
if not txt:
t = re.search(r'title=["\']([^"\']+)["\']', anchor_html, flags=re.IGNORECASE)
if t:
txt = unescape(t.group(1).strip())
if not txt:
img_alt = re.search(r'<img[^>]+alt=["\']([^"\']+)["\']', anchor_html, flags=re.IGNORECASE)
if img_alt:
txt = unescape(img_alt.group(1).strip())
# Only append if we have a non-empty title
if txt: if txt:
break
# still empty? skip
if not txt:
continue
items.append((href, txt)) items.append((href, txt))
# Fallback: collect anchors from whole page if no list-items found # Deduplicate while preserving order
if not items:
anchors = re.findall(r"<a[^>]+href=[\"']([^\"']+)[\"'][^>]*>(.*?)</a>", raw_html, flags=re.DOTALL | re.IGNORECASE)
for href, txt_html in anchors:
href = href.strip()
txt = re.sub(r"<[^>]+>", "", txt_html).strip()
txt = unescape(txt)
if txt and not href.lower().startswith("javascript:"):
items.append((href, txt))
# Deduplicate and filter out obvious navigation/header links
seen = set() seen = set()
filtered = [] filtered = []
for href, txt in items: for href, txt in items:
@@ -74,22 +130,23 @@ class ProxyHandler(BaseHTTPRequestHandler):
if key in seen: if key in seen:
continue continue
seen.add(key) seen.add(key)
lowtxt = (txt or "").strip().lower() # ignore trivial/empty titles
if href in ("#", "/", "", "/l/free"): if not txt:
continue continue
if lowtxt in ("홈", "로그인", "검색", "공지", "more", "더보기"): if href in ('#', '/', '', '/l/free'):
continue continue
filtered.append((href, txt)) filtered.append((href, txt))
# Skip the top 5 posts and show the next 10 # Exclude notices (공지) anywhere in the title, then apply skip/limit
posts = filtered[5:5+10] filtered_no_notice = [(h, t) for (h, t) in filtered if '공지' not in (t or '').lower()]
posts = filtered_no_notice[skip:skip+limit]
# Build simple HTML list for posts only # Build simple HTML list for posts only
host = self.headers.get("Host", f"localhost:{self.server.server_port}") host = self.headers.get("Host", f"localhost:{self.server.server_port}")
out_lines = [ out_lines = [
'<!doctype html>', '<!doctype html>',
'<html><head><meta charset="utf-8"><title>SLRClub - 게시글 목록</title></head><body>', '<html><head><meta charset="utf-8"><title>SLRClub - 게시글 목록</title></head><body>',
'<h1>게시글 (최대 10개)</h1>', f'<h1>게시글 (skip={skip}, limit={limit})</h1>',
'<ul>' '<ul>'
] ]
for href, txt in posts: for href, txt in posts: