skander101 commited on
Commit
5441c2f
·
1 Parent(s): 48aff15

feat: extract dates from HTML-scraped articles

Browse files
Files changed (1) hide show
  1. src/html_scraper.py +66 -2
src/html_scraper.py CHANGED
@@ -1,5 +1,7 @@
1
  import logging
 
2
  import time
 
3
  from urllib.parse import urljoin, urlparse
4
 
5
  import requests
@@ -60,6 +62,7 @@ class HTMLSiteScraper:
60
  continue
61
  seen_urls.add(full_url)
62
  domain = site.get("domain") or urlparse(full_url).netloc
 
63
  post = RedditPost(
64
  id=full_url,
65
  title=title,
@@ -69,8 +72,8 @@ class HTMLSiteScraper:
69
  num_comments=0,
70
  source_domain=domain,
71
  image_url="",
72
- published="",
73
- published_iso="",
74
  )
75
  posts.append(post)
76
  except Exception as exc:
@@ -78,6 +81,28 @@ class HTMLSiteScraper:
78
  time.sleep(1.0)
79
  return posts
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  @staticmethod
82
  def _find_article_links(soup: BeautifulSoup, site: dict) -> list:
83
  for selector in site["selectors"]:
@@ -85,3 +110,42 @@ class HTMLSiteScraper:
85
  if found:
86
  return found
87
  return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import logging
2
+ import re
3
  import time
4
+ from datetime import datetime
5
  from urllib.parse import urljoin, urlparse
6
 
7
  import requests
 
62
  continue
63
  seen_urls.add(full_url)
64
  domain = site.get("domain") or urlparse(full_url).netloc
65
+ published, published_iso = self._extract_date(soup, a_tag)
66
  post = RedditPost(
67
  id=full_url,
68
  title=title,
 
72
  num_comments=0,
73
  source_domain=domain,
74
  image_url="",
75
+ published=published,
76
+ published_iso=published_iso,
77
  )
78
  posts.append(post)
79
  except Exception as exc:
 
81
  time.sleep(1.0)
82
  return posts
83
 
84
+ @staticmethod
85
+ def _extract_date(soup: BeautifulSoup, a_tag) -> tuple[str, str]:
86
+ for parent_tag in ("div", "article", "li", "section"):
87
+ parent = a_tag.find_parent(parent_tag)
88
+ if not parent:
89
+ continue
90
+ time_tag = parent.find("time")
91
+ if time_tag:
92
+ raw = time_tag.get("datetime") or time_tag.get_text(strip=True)
93
+ if raw:
94
+ parsed = _parse_date_str(raw)
95
+ if parsed:
96
+ return parsed
97
+ date_el = parent.find(["span", "div"], class_=re.compile(r"date|time", re.I))
98
+ if date_el:
99
+ raw = date_el.get("datetime") or date_el.get_text(strip=True)
100
+ if raw:
101
+ parsed = _parse_date_str(raw)
102
+ if parsed:
103
+ return parsed
104
+ return ("", "")
105
+
106
  @staticmethod
107
  def _find_article_links(soup: BeautifulSoup, site: dict) -> list:
108
  for selector in site["selectors"]:
 
110
  if found:
111
  return found
112
  return []
113
+
114
+
115
+ _DATE_FORMATS = [
116
+ "%Y-%m-%dT%H:%M:%S%z",
117
+ "%Y-%m-%dT%H:%M:%S",
118
+ "%Y-%m-%d",
119
+ "%d %b %Y",
120
+ "%d %B %Y",
121
+ "%b %d, %Y",
122
+ "%B %d, %Y",
123
+ "%d/%m/%Y",
124
+ "%m/%d/%Y",
125
+ ]
126
+
127
+
128
+ def _parse_date_str(raw: str) -> tuple[str, str] | None:
129
+ raw = raw.strip()
130
+ if not raw:
131
+ return None
132
+ for fmt in _DATE_FORMATS:
133
+ try:
134
+ dt = datetime.strptime(raw, fmt)
135
+ if dt.tzinfo:
136
+ display = dt.strftime("%d %b %Y")
137
+ iso = dt.strftime("%Y-%m-%d")
138
+ else:
139
+ display = dt.strftime("%d %b %Y")
140
+ iso = dt.strftime("%Y-%m-%d")
141
+ return (display, iso)
142
+ except ValueError:
143
+ continue
144
+ try:
145
+ dt = datetime.fromisoformat(raw)
146
+ display = dt.strftime("%d %b %Y")
147
+ iso = dt.strftime("%Y-%m-%d")
148
+ return (display, iso)
149
+ except (ValueError, TypeError):
150
+ pass
151
+ return None