scrapeMM 0.3.1__tar.gz → 0.3.2__tar.gz
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.
- {scrapemm-0.3.1/scrapeMM.egg-info → scrapemm-0.3.2}/PKG-INFO +1 -1
- {scrapemm-0.3.1 → scrapemm-0.3.2}/pyproject.toml +1 -1
- {scrapemm-0.3.1 → scrapemm-0.3.2/scrapeMM.egg-info}/PKG-INFO +1 -1
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/retrieval.py +5 -1
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/decodo.py +13 -17
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/util.py +5 -3
- scrapemm-0.3.2/scripts/example.py +7 -0
- scrapemm-0.3.1/scripts/example.py +0 -8
- {scrapemm-0.3.1 → scrapemm-0.3.2}/.gitignore +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/LICENSE +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/README.md +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/requirements.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapeMM.egg-info/SOURCES.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapeMM.egg-info/dependency_links.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapeMM.egg-info/requires.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapeMM.egg-info/top_level.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/__init__.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/common.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/__init__.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/base.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/bluesky.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/fb.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/instagram.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/telegram.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/tiktok.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/x.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/integrations/youtube.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/__init__.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/firecrawl.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/no_bot_domains.txt +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/scraping/ytdlp.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/secrets.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/scrapemm/util.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/setup.cfg +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/testing/test_retrieval.py +0 -0
- {scrapemm-0.3.1 → scrapemm-0.3.2}/testing/test_utils.py +0 -0
|
@@ -114,7 +114,11 @@ async def _retrieve_single(
|
|
|
114
114
|
continue
|
|
115
115
|
|
|
116
116
|
logger.debug(f"Trying method: {method_name}")
|
|
117
|
-
|
|
117
|
+
try:
|
|
118
|
+
result = await method_map[method_name]()
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.warning(f"Error while retrieving with method '{method_name}': {e}")
|
|
121
|
+
result = None
|
|
118
122
|
|
|
119
123
|
if result is not None:
|
|
120
124
|
logger.debug(f"Successfully retrieved with method: {method_name}")
|
|
@@ -111,8 +111,6 @@ class Decodo:
|
|
|
111
111
|
# Create basic auth
|
|
112
112
|
auth = aiohttp.BasicAuth(self.username, self.password)
|
|
113
113
|
|
|
114
|
-
# logger.debug(f"Decodo request payload: {payload}")
|
|
115
|
-
|
|
116
114
|
try:
|
|
117
115
|
async with session.post(
|
|
118
116
|
self.DECODO_API_URL,
|
|
@@ -121,26 +119,17 @@ class Decodo:
|
|
|
121
119
|
auth=auth,
|
|
122
120
|
timeout=aiohttp.ClientTimeout(total=timeout)
|
|
123
121
|
) as response:
|
|
124
|
-
|
|
122
|
+
# Validate response health
|
|
125
123
|
if response.status != 200:
|
|
126
|
-
|
|
127
|
-
try:
|
|
128
|
-
error_body = await response.json()
|
|
129
|
-
error_msg = error_body.get('message', error_body)
|
|
130
|
-
except:
|
|
131
|
-
error_msg = await response.text()
|
|
132
|
-
|
|
133
|
-
logger.info(
|
|
134
|
-
f"Failed to scrape {url} with Decodo\n"
|
|
135
|
-
f"Status code: {response.status} - Reason: {response.reason}\n"
|
|
136
|
-
f"Error details: {error_msg}"
|
|
137
|
-
)
|
|
138
|
-
|
|
124
|
+
logger.debug("Communication with Decodo API failed.")
|
|
139
125
|
match response.status:
|
|
126
|
+
case 400:
|
|
127
|
+
logger.debug("Error 400: Bad request. If you use JavaScript, make sure you have the "
|
|
128
|
+
"Advanced plan subscription.")
|
|
140
129
|
case 401:
|
|
141
130
|
logger.error("Error 401: Unauthorized. Check your Decodo credentials.")
|
|
142
131
|
case 402:
|
|
143
|
-
logger.
|
|
132
|
+
logger.error("Error 402: Payment required. Check your Decodo subscription.")
|
|
144
133
|
case 403:
|
|
145
134
|
logger.debug("Error 403: Forbidden.")
|
|
146
135
|
case 408:
|
|
@@ -157,6 +146,13 @@ class Decodo:
|
|
|
157
146
|
# Parse response
|
|
158
147
|
json_response = await response.json()
|
|
159
148
|
|
|
149
|
+
# Validate if scrape was successful
|
|
150
|
+
if json_response.get("status") == "failed":
|
|
151
|
+
status_code = json_response.get("status_code")
|
|
152
|
+
message = json_response.get("message")
|
|
153
|
+
logger.info(f"Decodo failed to scrape. Error {status_code}: {message}")
|
|
154
|
+
return None
|
|
155
|
+
|
|
160
156
|
# Extract HTML content from results
|
|
161
157
|
if "results" in json_response and len(json_response["results"]) > 0:
|
|
162
158
|
result = json_response["results"][0]
|
|
@@ -6,6 +6,7 @@ from typing import Optional
|
|
|
6
6
|
|
|
7
7
|
import aiohttp
|
|
8
8
|
import requests
|
|
9
|
+
from PIL import UnidentifiedImageError
|
|
9
10
|
from ezmm import MultimodalSequence, download_item, Item, Image, Video
|
|
10
11
|
from markdownify import markdownify as md
|
|
11
12
|
from requests.exceptions import ReadTimeout, ConnectionError, RetryError
|
|
@@ -159,7 +160,8 @@ def from_base64(b64_data: str, mime_type: str = "image/jpeg") -> Optional[Item]:
|
|
|
159
160
|
else:
|
|
160
161
|
raise ValueError(f"Unsupported media type: {mime_type}")
|
|
161
162
|
except binascii.Error: # base64 validation failed
|
|
162
|
-
return
|
|
163
|
+
return None
|
|
164
|
+
except UnidentifiedImageError: # Pillow could not identify image format
|
|
165
|
+
return None
|
|
163
166
|
except Exception as e:
|
|
164
|
-
logger.
|
|
165
|
-
f"{type(e).__name__}: {e}")
|
|
167
|
+
logger.debug(f"Error decoding {mime_type} base64 data. \n {type(e).__name__}: {e}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|