Skip to content

Commit 9adfc8d

Browse files
author
stlc-bot
committed
feat(scrape): add prebuilt Google Maps parsing (#1824)
Stainless-Generated-From: 8e806a9f36d3df52f3aa22964dbb78619cf2e265
1 parent 7381d58 commit 9adfc8d

3 files changed

Lines changed: 49 additions & 18 deletions

File tree

‎src/context/dev/types/web_scrape_params.py‎

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
"JsonParams",
1717
"MarkdownParams",
1818
"ParseParams",
19-
"ParseParamsRules",
20-
"ParseParamsRulesUnionMember1",
19+
"ParseParamsCustomParser",
20+
"ParseParamsCustomParserRules",
21+
"ParseParamsCustomParserRulesUnionMember1",
22+
"ParseParamsPrebuiltParser",
2123
"ProductParams",
2224
"ScreenshotParams",
2325
"ScreenshotParamsArea",
@@ -115,7 +117,7 @@ class Formats(TypedDict, total=False):
115117
"""Page content as Markdown."""
116118

117119
parse: bool
118-
"""Fields extracted with `parseParams.rules`, returned as `parsed`."""
120+
"""Fields extracted with custom rules or a prebuilt parser, returned as `parsed`."""
119121

120122
product: bool
121123
"""Product details such as name, price, and availability."""
@@ -173,7 +175,7 @@ class MarkdownParams(TypedDict, total=False):
173175
"""
174176

175177

176-
class ParseParamsRulesUnionMember1(TypedDict, total=False):
178+
class ParseParamsCustomParserRulesUnionMember1(TypedDict, total=False):
177179
selector: Required[str]
178180
"""CSS selector to match within the current page or parent rule."""
179181

@@ -187,18 +189,38 @@ class ParseParamsRulesUnionMember1(TypedDict, total=False):
187189
"""Return the first match with `item` or all matches with `list`."""
188190

189191

190-
ParseParamsRules: TypeAlias = Union[str, ParseParamsRulesUnionMember1]
192+
ParseParamsCustomParserRules: TypeAlias = Union[str, ParseParamsCustomParserRulesUnionMember1]
191193

192194

193-
class ParseParams(TypedDict, total=False):
194-
"""Requires `formats.parse: true`; required when it is set."""
195-
196-
rules: Required[Dict[str, ParseParamsRules]]
195+
class ParseParamsCustomParser(TypedDict, total=False):
196+
rules: Required[Dict[str, ParseParamsCustomParserRules]]
197197
"""Field names mapped to CSS selectors (`h1`, `a@href`) or rule objects.
198198
199199
Max 100 fields, 5 levels.
200200
"""
201201

202+
type: Literal["custom"]
203+
"""Extract fields using custom CSS rules.
204+
205+
This is the default when type is omitted.
206+
"""
207+
208+
209+
class ParseParamsPrebuiltParser(TypedDict, total=False):
210+
parser: Required[Literal["google-maps"]]
211+
"""Parse Google Maps business data into data.results.
212+
213+
Accepts Maps place, search, and internal data URLs. Uses a US exit and English
214+
labels regardless of hl or Accept-Language, and reads Maps data independently of
215+
DOM filters.
216+
"""
217+
218+
type: Required[Literal["prebuilt"]]
219+
"""Use a prebuilt parser instead of custom rules."""
220+
221+
222+
ParseParams: TypeAlias = Union[ParseParamsCustomParser, ParseParamsPrebuiltParser]
223+
202224

203225
class ProductParams(TypedDict, total=False):
204226
"""Product options. Requires formats.product: true."""
@@ -390,7 +412,8 @@ class SharedParams(TypedDict, total=False):
390412
"""Create or reuse an authenticated browser profile.
391413
392414
Requires a paid plan and an HTTPS target. Profiles persist session state, bypass
393-
shared caches, and cannot be combined with ZDR, custom headers, or raw bytes.
415+
shared caches, and cannot be combined with ZDR, custom headers, raw bytes, or
416+
prebuilt parsers.
394417
"""
395418

396419
settle_animations: Annotated[bool, PropertyInfo(alias="settleAnimations")]

‎src/context/dev/types/web_scrape_response.py‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,8 @@ class Metadata(BaseModel):
266266

267267

268268
class Parsed(BaseModel):
269-
"""Fields from `parseParams.rules`, after content filters.
270-
271-
Unmatched fields are `null` (`[]` for lists).
269+
"""
270+
Custom rules return fields after content filters; unmatched fields are null ([] for lists). The google-maps parser returns business records in data.results and reads Maps data directly, independently of DOM filters and other outputs.
272271
"""
273272

274273
data: Optional[Dict[str, object]] = None
@@ -278,6 +277,12 @@ class Parsed(BaseModel):
278277
success: Optional[bool] = None
279278
"""`true` if returned, `false` if it failed, `null` if not requested."""
280279

280+
type: Literal["custom", "google-maps"]
281+
"""
282+
The selected prebuilt parser name, or custom when type is omitted, custom rules
283+
are used, or parsing is not requested.
284+
"""
285+
281286
error_code: Optional[str] = None
282287
"""Why the output failed. Present only when `success` is `false`."""
283288

@@ -454,9 +459,10 @@ class WebScrapeResponse(BaseModel):
454459
"""Page metadata. Fields are omitted when not found."""
455460

456461
parsed: Parsed
457-
"""Fields from `parseParams.rules`, after content filters.
458-
459-
Unmatched fields are `null` (`[]` for lists).
462+
"""
463+
Custom rules return fields after content filters; unmatched fields are null ([]
464+
for lists). The google-maps parser returns business records in data.results and
465+
reads Maps data directly, independently of DOM filters and other outputs.
460466
"""
461467

462468
product: Product

‎tests/api_resources/test_web.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ def test_method_scrape_with_all_params(self, client: ContextDev) -> None:
283283
"output": "@href",
284284
"type": "list",
285285
},
286-
}
286+
},
287+
"type": "custom",
287288
},
288289
product_params={"dedupe_images": True},
289290
screenshot_params={
@@ -829,7 +830,8 @@ async def test_method_scrape_with_all_params(self, async_client: AsyncContextDev
829830
"output": "@href",
830831
"type": "list",
831832
},
832-
}
833+
},
834+
"type": "custom",
833835
},
834836
product_params={"dedupe_images": True},
835837
screenshot_params={

0 commit comments

Comments
 (0)