scrapeunblocker-haystack 0.4.2__tar.gz → 0.5.0__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.
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/CHANGELOG.md +11 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/PKG-INFO +19 -1
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/README.md +18 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/src/scrapeunblocker_haystack/search.py +10 -0
- scrapeunblocker_haystack-0.5.0/src/scrapeunblocker_haystack/version.py +1 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/tests/test_components.py +31 -1
- scrapeunblocker_haystack-0.4.2/src/scrapeunblocker_haystack/version.py +0 -1
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/.github/workflows/publish.yml +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/.github/workflows/test.yml +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/.gitignore +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/LICENSE +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/pyproject.toml +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/src/scrapeunblocker_haystack/__init__.py +0 -0
- {scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/src/scrapeunblocker_haystack/fetcher.py +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
- `ScrapeUnblockerWebSearch` takes `full_urls` (default `False`): wait until
|
|
6
|
+
Google gives out every result's real URL. Google releases a results page's
|
|
7
|
+
links a few at a time, the last ones up to about 40 seconds after the search.
|
|
8
|
+
Without the flag the call returns sooner, and a result whose link has not
|
|
9
|
+
come yet has the site's home page as its `link` (or a Google redirect link
|
|
10
|
+
when Google shows no site). With it, the call takes up to about 40 seconds
|
|
11
|
+
longer. Billed the same. Sent to `/serpApi` only when `True`, and saved with
|
|
12
|
+
the component in `to_dict()`.
|
|
13
|
+
|
|
3
14
|
## 0.4.2
|
|
4
15
|
|
|
5
16
|
- `ScrapeUnblockerWebSearch` adds `sitelinks` (the extra links under a result:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scrapeunblocker-haystack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Haystack integration for ScrapeUnblocker - scrape pages behind anti-bot protections
|
|
5
5
|
Project-URL: Homepage, https://www.scrapeunblocker.com
|
|
6
6
|
Project-URL: Documentation, https://docs.scrapeunblocker.com
|
|
@@ -205,6 +205,24 @@ for doc in result["documents"]:
|
|
|
205
205
|
| `pages_to_check` | `1` | How many result pages to scrape |
|
|
206
206
|
| `proxy_country` | `None` | Two-letter country code for localised results |
|
|
207
207
|
| `top_k` | `None` | Keep at most this many results |
|
|
208
|
+
| `full_urls` | `False` | Wait until Google gives out every result's real URL (see below) |
|
|
209
|
+
| `base_url` | `https://api.scrapeunblocker.com` | API base URL |
|
|
210
|
+
| `timeout` | `180` | HTTP timeout in seconds |
|
|
211
|
+
|
|
212
|
+
#### Every result's real URL
|
|
213
|
+
|
|
214
|
+
Google releases a results page's links a few at a time, the last ones up to
|
|
215
|
+
about 40 seconds after the search. By default the search returns sooner, so
|
|
216
|
+
most results carry their real URL in `meta["link"]`, and a result whose link
|
|
217
|
+
has not come yet has the site's home page there (or a Google redirect link when
|
|
218
|
+
Google shows no site). Set `full_urls=True` when you need the exact page of
|
|
219
|
+
every result, for example to fetch or cite them:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
search = ScrapeUnblockerWebSearch(full_urls=True)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The call then takes up to about 40 seconds longer. It is billed the same.
|
|
208
226
|
|
|
209
227
|
## In a pipeline
|
|
210
228
|
|
|
@@ -180,6 +180,24 @@ for doc in result["documents"]:
|
|
|
180
180
|
| `pages_to_check` | `1` | How many result pages to scrape |
|
|
181
181
|
| `proxy_country` | `None` | Two-letter country code for localised results |
|
|
182
182
|
| `top_k` | `None` | Keep at most this many results |
|
|
183
|
+
| `full_urls` | `False` | Wait until Google gives out every result's real URL (see below) |
|
|
184
|
+
| `base_url` | `https://api.scrapeunblocker.com` | API base URL |
|
|
185
|
+
| `timeout` | `180` | HTTP timeout in seconds |
|
|
186
|
+
|
|
187
|
+
#### Every result's real URL
|
|
188
|
+
|
|
189
|
+
Google releases a results page's links a few at a time, the last ones up to
|
|
190
|
+
about 40 seconds after the search. By default the search returns sooner, so
|
|
191
|
+
most results carry their real URL in `meta["link"]`, and a result whose link
|
|
192
|
+
has not come yet has the site's home page there (or a Google redirect link when
|
|
193
|
+
Google shows no site). Set `full_urls=True` when you need the exact page of
|
|
194
|
+
every result, for example to fetch or cite them:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
search = ScrapeUnblockerWebSearch(full_urls=True)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The call then takes up to about 40 seconds longer. It is billed the same.
|
|
183
201
|
|
|
184
202
|
## In a pipeline
|
|
185
203
|
|
|
@@ -41,6 +41,7 @@ class ScrapeUnblockerWebSearch:
|
|
|
41
41
|
top_k: Optional[int] = None,
|
|
42
42
|
base_url: str = DEFAULT_BASE_URL,
|
|
43
43
|
timeout: int = DEFAULT_TIMEOUT,
|
|
44
|
+
full_urls: bool = False,
|
|
44
45
|
) -> None:
|
|
45
46
|
"""
|
|
46
47
|
:param api_key: ScrapeUnblocker API key. Read from `SCRAPEUNBLOCKER_API_KEY` by default.
|
|
@@ -49,6 +50,11 @@ class ScrapeUnblockerWebSearch:
|
|
|
49
50
|
:param top_k: Keep at most this many results. `None` keeps all of them.
|
|
50
51
|
:param base_url: API base URL. Override to target a different environment.
|
|
51
52
|
:param timeout: HTTP timeout in seconds.
|
|
53
|
+
:param full_urls: Wait until Google gives out every result's real URL. Google releases a
|
|
54
|
+
results page's links a few at a time, the last ones up to about 40 seconds after the
|
|
55
|
+
search. Without this flag the call returns sooner, and a result whose link has not come
|
|
56
|
+
yet has the site's home page as its `link` (or a Google redirect link when Google shows
|
|
57
|
+
no site). With it, the call takes up to about 40 seconds longer. Billed the same.
|
|
52
58
|
"""
|
|
53
59
|
self.api_key = api_key
|
|
54
60
|
self.pages_to_check = pages_to_check
|
|
@@ -56,6 +62,7 @@ class ScrapeUnblockerWebSearch:
|
|
|
56
62
|
self.top_k = top_k
|
|
57
63
|
self.base_url = base_url.rstrip("/")
|
|
58
64
|
self.timeout = timeout
|
|
65
|
+
self.full_urls = full_urls
|
|
59
66
|
|
|
60
67
|
def to_dict(self) -> Dict[str, Any]:
|
|
61
68
|
"""Serialize this component to a dictionary."""
|
|
@@ -67,6 +74,7 @@ class ScrapeUnblockerWebSearch:
|
|
|
67
74
|
top_k=self.top_k,
|
|
68
75
|
base_url=self.base_url,
|
|
69
76
|
timeout=self.timeout,
|
|
77
|
+
full_urls=self.full_urls,
|
|
70
78
|
)
|
|
71
79
|
|
|
72
80
|
@classmethod
|
|
@@ -86,6 +94,8 @@ class ScrapeUnblockerWebSearch:
|
|
|
86
94
|
params: Dict[str, Any] = {"keyword": query, "pages_to_check": self.pages_to_check}
|
|
87
95
|
if self.proxy_country:
|
|
88
96
|
params["proxy_country"] = self.proxy_country
|
|
97
|
+
if self.full_urls:
|
|
98
|
+
params["full_urls"] = "true"
|
|
89
99
|
|
|
90
100
|
response = requests.post(
|
|
91
101
|
f"{self.base_url}/serpApi",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.0"
|
|
@@ -259,12 +259,42 @@ class TestWebSearch:
|
|
|
259
259
|
|
|
260
260
|
assert search.run(query="q")["documents"] == []
|
|
261
261
|
|
|
262
|
+
@patch("scrapeunblocker_haystack.search.requests.post")
|
|
263
|
+
def test_full_urls_off_by_default(self, mock_post):
|
|
264
|
+
mock_post.return_value = _response(json_data={"organic": []})
|
|
265
|
+
search = ScrapeUnblockerWebSearch(api_key=API_KEY)
|
|
266
|
+
assert search.full_urls is False
|
|
267
|
+
|
|
268
|
+
search.run(query="q")
|
|
269
|
+
|
|
270
|
+
_, kwargs = mock_post.call_args
|
|
271
|
+
assert "full_urls" not in kwargs["params"]
|
|
272
|
+
|
|
273
|
+
@patch("scrapeunblocker_haystack.search.requests.post")
|
|
274
|
+
def test_full_urls_sent_when_on(self, mock_post):
|
|
275
|
+
mock_post.return_value = _response(json_data={"organic": []})
|
|
276
|
+
search = ScrapeUnblockerWebSearch(api_key=API_KEY, full_urls=True)
|
|
277
|
+
|
|
278
|
+
search.run(query="q")
|
|
279
|
+
|
|
280
|
+
_, kwargs = mock_post.call_args
|
|
281
|
+
assert kwargs["params"]["full_urls"] == "true"
|
|
282
|
+
|
|
262
283
|
def test_to_dict_and_back(self):
|
|
263
|
-
search = ScrapeUnblockerWebSearch(api_key=ENV_KEY, top_k=5, proxy_country="us")
|
|
284
|
+
search = ScrapeUnblockerWebSearch(api_key=ENV_KEY, top_k=5, proxy_country="us", full_urls=True)
|
|
264
285
|
data = search.to_dict()
|
|
286
|
+
assert data["init_parameters"]["full_urls"] is True
|
|
265
287
|
restored = ScrapeUnblockerWebSearch.from_dict(data)
|
|
266
288
|
assert restored.top_k == 5
|
|
267
289
|
assert restored.proxy_country == "us"
|
|
290
|
+
assert restored.full_urls is True
|
|
291
|
+
|
|
292
|
+
def test_from_dict_of_older_version(self):
|
|
293
|
+
data = ScrapeUnblockerWebSearch(api_key=ENV_KEY).to_dict()
|
|
294
|
+
del data["init_parameters"]["full_urls"]
|
|
295
|
+
|
|
296
|
+
restored = ScrapeUnblockerWebSearch.from_dict(data)
|
|
297
|
+
assert restored.full_urls is False
|
|
268
298
|
|
|
269
299
|
|
|
270
300
|
class TestTargetNotFound:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.2"
|
{scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/.github/workflows/publish.yml
RENAMED
|
File without changes
|
{scrapeunblocker_haystack-0.4.2 → scrapeunblocker_haystack-0.5.0}/.github/workflows/test.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|