@danhachuel/thunderbolt 0.6.58 → 0.6.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/integrations/instagram_public.py +50 -16
- package/package.json +1 -1
|
@@ -166,29 +166,63 @@ def _extract_posts_from_html(document: str, limit: int = 10) -> list[dict[str, A
|
|
|
166
166
|
return posts
|
|
167
167
|
|
|
168
168
|
|
|
169
|
+
def _metric_text_value(value: Any) -> int | None:
|
|
170
|
+
if isinstance(value, Mapping):
|
|
171
|
+
value = value.get('count') or value.get('value')
|
|
172
|
+
text = str(value or '').strip().casefold().replace(' ', '')
|
|
173
|
+
if not text:
|
|
174
|
+
return None
|
|
175
|
+
multiplier = 1
|
|
176
|
+
if text.endswith(('k', 'mil')):
|
|
177
|
+
multiplier = 1000
|
|
178
|
+
text = text[:-1] if text.endswith('k') else text[:-3]
|
|
179
|
+
elif text.endswith(('m', 'mi', 'milhões')):
|
|
180
|
+
multiplier = 1_000_000
|
|
181
|
+
text = text[:-1] if text.endswith('m') else text[:-2] if text.endswith('mi') else text[:-7]
|
|
182
|
+
digits = re.sub(r'[^0-9]', '', text)
|
|
183
|
+
if not digits:
|
|
184
|
+
return None
|
|
185
|
+
return int(digits) * multiplier
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _embedded_profile_user(document: str, username: str) -> Mapping[str, Any]:
|
|
189
|
+
wanted = username.casefold()
|
|
190
|
+
for payload in _embedded_json_documents(document):
|
|
191
|
+
for node in _walk_json(payload):
|
|
192
|
+
if not isinstance(node, Mapping):
|
|
193
|
+
continue
|
|
194
|
+
node_username = str(node.get('username') or node.get('handle') or '').lstrip('@').casefold()
|
|
195
|
+
if node_username == wanted and any(key in node for key in ('biography', 'bio', 'edge_followed_by', 'edge_follow', 'followers', 'following')):
|
|
196
|
+
return node
|
|
197
|
+
return {}
|
|
198
|
+
|
|
199
|
+
|
|
169
200
|
def _extract_profile_user_from_html(document: str, username: str) -> dict[str, Any]:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
201
|
+
embedded_user = _embedded_profile_user(document, username)
|
|
202
|
+
seo_description = _meta(document, 'og:description')
|
|
203
|
+
biography = str(embedded_user.get('biography') or embedded_user.get('bio') or '').strip()
|
|
204
|
+
description = biography or seo_description
|
|
205
|
+
title = str(embedded_user.get('full_name') or embedded_user.get('name') or _meta(document, 'og:title') or username).split('(')[0].strip() or username
|
|
206
|
+
avatar_url = str(embedded_user.get('profile_pic_url_hd') or embedded_user.get('profile_pic_url') or _meta(document, 'og:image')).strip()
|
|
173
207
|
|
|
174
208
|
def metric(patterns: tuple[str, ...]) -> int | None:
|
|
175
209
|
for pattern in patterns:
|
|
176
|
-
found = re.search(pattern,
|
|
210
|
+
found = re.search(pattern, seo_description, flags=re.IGNORECASE)
|
|
177
211
|
if found:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
pass
|
|
212
|
+
parsed = _metric_text_value(found.group(1) + (found.group(2) or ''))
|
|
213
|
+
if parsed is not None:
|
|
214
|
+
return parsed
|
|
182
215
|
return None
|
|
183
216
|
|
|
184
|
-
followers = metric((r'([\d
|
|
185
|
-
following = metric((r'([\d
|
|
186
|
-
post_count = metric((r'([\d
|
|
187
|
-
country = ''
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
217
|
+
followers = _metric_text_value(embedded_user.get('edge_followed_by')) or _metric_text_value(embedded_user.get('followers')) or metric((r'([\d.,]+)\s*(k|mil)?\s*(?:followers|seguidores)',)) or _structured_metric(document, 'edge_followed_by', 'followers', 'follower_count') or _structured_metric_from_json(document, 'edge_followed_by', 'followers', 'follower_count', 'followerCount')
|
|
218
|
+
following = _metric_text_value(embedded_user.get('edge_follow')) or _metric_text_value(embedded_user.get('following')) or metric((r'([\d.,]+)\s*(k|mil)?\s*(?:following|seguindo)',)) or _structured_metric(document, 'edge_follow', 'follows', 'following', 'following_count', 'followingCount') or _structured_metric_from_json(document, 'edge_follow', 'follows', 'following', 'following_count', 'followingCount')
|
|
219
|
+
post_count = _metric_text_value(embedded_user.get('edge_owner_to_timeline_media')) or _metric_text_value(embedded_user.get('posts')) or metric((r'([\d.,]+)\s*(k|mil)?\s*(?:posts|publicações|publications)',)) or _structured_metric(document, 'edge_owner_to_timeline_media', 'posts', 'post_count')
|
|
220
|
+
country = _country_value(embedded_user.get('country') or embedded_user.get('country_code')) or extract_public_instagram_country(embedded_user)
|
|
221
|
+
if not country:
|
|
222
|
+
for payload in _embedded_json_documents(document):
|
|
223
|
+
country = extract_public_instagram_country(payload)
|
|
224
|
+
if country:
|
|
225
|
+
break
|
|
192
226
|
posts = _extract_posts_from_html(document, 10)
|
|
193
227
|
user: dict[str, Any] = {
|
|
194
228
|
'username': username,
|
package/package.json
CHANGED