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.
@@ -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.4.2
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"