bep40 commited on
Commit
c40f060
·
verified ·
1 Parent(s): ab4c7e1

[FIX] VnExpress Short format scraper fallback for JS-lazy-loaded articles

Browse files
Files changed (1) hide show
  1. rewrite_slide.py +44 -5
rewrite_slide.py CHANGED
@@ -31,11 +31,14 @@ def _clean(s): return re.sub(r'\s+', ' ', str(s or '')).strip()
31
 
32
 
33
  def _scrape_article_full(url):
34
- """Scrape article: extract paragraphs + ALL images."""
 
 
35
  try:
36
  r = requests.get(url, headers=UA, timeout=15, allow_redirects=True)
37
  r.encoding = 'utf-8'
38
- soup = BeautifulSoup(r.text, 'lxml')
 
39
  for tag in soup.find_all(['script', 'style', 'nav', 'footer', 'aside', 'form']): tag.decompose()
40
 
41
  # Title
@@ -48,11 +51,11 @@ def _scrape_article_full(url):
48
  og_img = ogi.get('content', '') if ogi else ''
49
  if og_img and og_img.startswith('//'): og_img = 'https:' + og_img
50
 
51
- # Find content block
52
  block = None
53
  for sel in ['article', '.singular-content', '.detail-content', '.fck_detail', '.content-detail', '.knc-content', 'main', '.cms-body', '.article__body']:
54
- el = soup.select_one(sel)
55
- if el and len(el.find_all('p')) >= 2: block = el; break
56
  if not block: block = soup.body or soup
57
 
58
  # Extract paragraphs and images IN ORDER
@@ -79,6 +82,42 @@ def _scrape_article_full(url):
79
  images.append(src)
80
  seen_imgs.add(src)
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  return {'title': _clean(title), 'paragraphs': paragraphs, 'images': images, 'og_img': og_img}
83
  except Exception as e:
84
  return None
 
31
 
32
 
33
  def _scrape_article_full(url):
34
+ """Scrape article: extract paragraphs + ALL images.
35
+ Handles both normal HTML articles AND VnExpress JS-lazy-loaded Short format.
36
+ """
37
  try:
38
  r = requests.get(url, headers=UA, timeout=15, allow_redirects=True)
39
  r.encoding = 'utf-8'
40
+ html = r.text
41
+ soup = BeautifulSoup(html, 'lxml')
42
  for tag in soup.find_all(['script', 'style', 'nav', 'footer', 'aside', 'form']): tag.decompose()
43
 
44
  # Title
 
51
  og_img = ogi.get('content', '') if ogi else ''
52
  if og_img and og_img.startswith('//'): og_img = 'https:' + og_img
53
 
54
+ # Find content block (normal article layout)
55
  block = None
56
  for sel in ['article', '.singular-content', '.detail-content', '.fck_detail', '.content-detail', '.knc-content', 'main', '.cms-body', '.article__body']:
57
+ es = soup.select_one(sel)
58
+ if es and len(es.find_all('p')) >= 2: block = es; break
59
  if not block: block = soup.body or soup
60
 
61
  # Extract paragraphs and images IN ORDER
 
82
  images.append(src)
83
  seen_imgs.add(src)
84
 
85
+ # If no meaningful paragraphs found, try VnExpress Short format
86
+ # (JS-lazy-loaded articles where body class is "page-short")
87
+ if len(paragraphs) < 2:
88
+ body = soup.find('body')
89
+ body_class = ' '.join(body.get('class', [])) if body else ''
90
+
91
+ if 'page-short' in body_class or not paragraphs:
92
+ paragraphs = []
93
+ images = []
94
+ seen_imgs.clear()
95
+
96
+ # Extract dataCurrentDetail for title + lead
97
+ m = re.search(r'var dataCurrentDetail\s*=\s*({.*?});', html, re.DOTALL)
98
+ if m:
99
+ try:
100
+ d = json.loads(m.group(1))
101
+ lead = _clean(d.get('lead', ''))
102
+ if lead and len(lead) > 50:
103
+ paragraphs.append(lead)
104
+ thumb = d.get('thumbnail_url', '') or ''
105
+ if thumb and thumb not in seen_imgs:
106
+ images.append(thumb)
107
+ seen_imgs.add(thumb)
108
+ except: pass
109
+
110
+ # Also get OG description
111
+ ogd = soup.find('meta', property='og:description')
112
+ if ogd:
113
+ desc = _clean(ogd.get('content', ''))
114
+ if desc and len(desc) > 50 and desc not in paragraphs:
115
+ paragraphs.append(desc)
116
+
117
+ # Use title as paragraph if nothing else
118
+ if not paragraphs and title:
119
+ paragraphs.append(title[:200] + '.')
120
+
121
  return {'title': _clean(title), 'paragraphs': paragraphs, 'images': images, 'og_img': og_img}
122
  except Exception as e:
123
  return None