scrapeunblocker 0.15.1 → 0.17.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f62e1ad297dc0829c5aad20c1c09208595bb459b733b87d862c585fe64e12e5
4
- data.tar.gz: 9ce26e1db98023c5373d90229f0f9545fc11f71f28ba143e82710305aab6a811
3
+ metadata.gz: 4a9fdb57b21c1b655ba3ec6bc4c87f0907872ccdf9ad279035e028192b7f4414
4
+ data.tar.gz: adfa7124cb12d1eac3aed2a818070be619a80e8a243e6d1816b34f534cb4601a
5
5
  SHA512:
6
- metadata.gz: 150e385abf9ae36cde1653f4c411ab43d3735f6267fb6c8aab24d43caf37aa3da4dd8c7f6833dd6b207f45b374d01e6112f4a27e4a7007b4bcba2c812ce83b3e
7
- data.tar.gz: 2a7c1c9b01e7821b80dfd590e650a2766b56ecccaa28ae16c1b219f6ce2022d7b4d33c2108e33eed17319f794e9c052dbe6977a00964a201b15853fdadeefbf2
6
+ metadata.gz: c6765faaf5a348e030ea3c102d5574b05d3f0105526b1141d4bb9b2257eb8fb3ec5c9ab96c6b934f8d0d6b2d026eaec0821a247670fb18c9382243ac32fc2206
7
+ data.tar.gz: 806142bbf00967541f0a32b88afa96485416f46505266647b41ee2ed13bbbe53c0c0f50210ec53138c13118ae5df4c9afdb701b2d0e6e601311e07055c95a22b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.0 (2026-10-30)
4
+
5
+ - 29 new plugin methods on `Client`:
6
+ - E-commerce, new sites: `mediamarkt_search(query)` and `mediamarkt_product(product_id)` (MediaMarkt in ten countries and Saturn), `cdiscount_search(query)` and `cdiscount_product(sku)`, `idealo_search(query)` and `idealo_offers(product_id)` (price comparison in six countries), `rakuten_search(query)` and `rakuten_product()` (Rakuten Ichiba, Japan), `indiamart_search(query)` and `indiamart_product()`, `bedbathandbeyond_search(query)` and `bedbathandbeyond_product(product)`, `petco_search(query)` and `petco_product(product)`, `neobits_product(product)`, `lowes_search(query)` and `lowes_product(product_id)`, `menards_search(query)` and `menards_product()`, `grainger_search(query)` and `grainger_product(sku)`.
7
+ - Product pages next to existing searches: `walmart_product()`, `ebay_product()`, `etsy_product()`, `bestbuy_product(sku)`, `target_category(category)` and `target_product(tcin)`, `aliexpress_product(product_id)`.
8
+ - AI: `chatgpt(prompt)` (ChatGPT's answer with the sites it cites).
9
+ - The first argument of the product methods that also take a link, and of the searches that also take a search link, is optional, for calls that pass `url:` instead. `rakuten_product`, `indiamart_product`, `menards_product`, `walmart_product`, `ebay_product` and `etsy_product` take keyword options only (`product_id:` / `sku:` / `item_id:` / `listing_id:` or `url:`).
10
+ - Plugin method comments no longer describe exit or proxy details (`exitProvider`); API responses no longer carry them.
11
+
12
+ No breaking changes.
13
+
14
+ ## 0.16.0 (2026-10-29)
15
+
16
+ - Add `maps_reviews`: Google Maps reviews of a place in Google's sort orders (relevant, newest, highest, lowest) with exact ISO dates, original and translated text, authors, photos, owner replies and page tokens. `POST /maps/reviews`.
17
+
3
18
  ## 0.15.1 (2026-10-29)
4
19
 
5
20
  - `shopee_product` and `shopee_search` docs: describe `availability` and `inStock`, sold-out variations (`models[].available`, `tierIndex`), `categories` as the breadcrumb path plus `browseCategories`, `isPixPrice` (Brazilian Pix prices) and the JSON `{"status": "not_found", ...}` answer for a product that does not exist. Signatures are unchanged.
data/README.md CHANGED
@@ -149,11 +149,11 @@ jobs = su.career_site_jobs("https://jobs.ashbyhq.com/ramp", keyword: "engineer")
149
149
  | Category | Methods |
150
150
  | --- | --- |
151
151
  | Travel | `skyscanner.flights`, `skyscanner.hotels`, `skyscanner.carhire`, `booking_hotels`, `booking_reviews`, `airbnb_search`, `airbnb_room`, `airbnb_reviews`, `tripadvisor_list`, `tripadvisor_reviews` |
152
- | Google | `google_local`, `google_images`, `maps_place_details`, `google_trends`, `google_shopping`, `google_jobs`, `google_hotels`, `google_hotels_property`, `google_news`, `google_ads_transparency`, `google_ads_transparency_advertisers`, `google_ai_mode`, `google_lens` |
153
- | AI | `gemini` |
152
+ | Google | `google_local`, `google_images`, `maps_place_details`, `maps_reviews`, `google_trends`, `google_shopping`, `google_jobs`, `google_hotels`, `google_hotels_property`, `google_news`, `google_ads_transparency`, `google_ads_transparency_advertisers`, `google_ai_mode`, `google_lens` |
153
+ | AI | `gemini`, `chatgpt` |
154
154
  | Search engines | `bing_search`, `bing_images`, `duckduckgo_search`, `yahoo_search`, `yahoo_images`, `brave_search`, `brave_images` |
155
- | E-commerce | `amazon_product`, `amazon_search`, `amazon_bestsellers`, `amazon_reviews`, `amazon_offers`, `amazon_seller`, `walmart_search`, `target_search`, `bestbuy_search`, `homedepot_search`, `costco_search`, `costco_product`, `etsy_search`, `shein_search`, `zalando_search`, `aliexpress_search`, `alibaba_search`, `alibaba_product`, `alibaba1688_search`, `alibaba1688_product`, `tiktok_shop_search`, `tiktok_shop_product`, `tiktok_shop_store`, `oopbuy_search`, `smyths_inventory`, `smyths_details`, `smyths_search`, `smyths_category`, `wish_search`, `wish_product`, `shopee_search`, `shopee_product`, `taobao_search`, `taobao_product`, `flipkart_search`, `flipkart_product`, `lazada_search`, `lazada_product`, `allegro_search`, `allegro_product`, `falabella_search`, `falabella_product`, `magazineluiza_search`, `magazineluiza_product` |
156
- | Classifieds & Resale | `ebay_search`, `vinted_search`, `leboncoin_search` |
155
+ | E-commerce | `amazon_product`, `amazon_search`, `amazon_bestsellers`, `amazon_reviews`, `amazon_offers`, `amazon_seller`, `walmart_search`, `walmart_product`, `target_search`, `target_category`, `target_product`, `bestbuy_search`, `bestbuy_product`, `homedepot_search`, `costco_search`, `costco_product`, `etsy_search`, `etsy_product`, `shein_search`, `zalando_search`, `aliexpress_search`, `aliexpress_product`, `alibaba_search`, `alibaba_product`, `alibaba1688_search`, `alibaba1688_product`, `tiktok_shop_search`, `tiktok_shop_product`, `tiktok_shop_store`, `oopbuy_search`, `smyths_inventory`, `smyths_details`, `smyths_search`, `smyths_category`, `wish_search`, `wish_product`, `shopee_search`, `shopee_product`, `taobao_search`, `taobao_product`, `flipkart_search`, `flipkart_product`, `lazada_search`, `lazada_product`, `allegro_search`, `allegro_product`, `falabella_search`, `falabella_product`, `magazineluiza_search`, `magazineluiza_product`, `mediamarkt_search`, `mediamarkt_product`, `cdiscount_search`, `cdiscount_product`, `idealo_search`, `idealo_offers`, `rakuten_search`, `rakuten_product`, `indiamart_search`, `indiamart_product`, `bedbathandbeyond_search`, `bedbathandbeyond_product`, `petco_search`, `petco_product`, `neobits_product`, `lowes_search`, `lowes_product`, `menards_search`, `menards_product`, `grainger_search`, `grainger_product` |
156
+ | Classifieds & Resale | `ebay_product`, `ebay_search`, `vinted_search`, `leboncoin_search` |
157
157
  | Groceries | `woolworths_search`, `woolworths_category`, `woolworths_specials`, `woolworths_product`, `coles_search`, `coles_category`, `coles_specials`, `coles_product`, `aldi_au_search`, `aldi_au_category`, `aldi_au_specials`, `aldi_au_product`, `kroger_search`, `kroger_product`, `instacart_search`, `instacart_product`, `publix_search`, `publix_product` |
158
158
  | Real estate | `zillow_search`, `zillow_detail`, `redfin_search`, `redfin_detail`, `rightmove_search`, `idealista_search`, `idealista_detail`, `immobilienscout24_search` |
159
159
  | Vehicles | `mobile_de`, `autoscout24_search` |
@@ -79,8 +79,8 @@ module ScrapeUnblocker
79
79
  # `reviewsGated` is `true` and `reviews` is empty; the rating, histogram and customers-say
80
80
  # data, including its review excerpts, are still returned. Every field is always present and
81
81
  # is `null` when the page does not show it. `proxy_country` defaults to the marketplace's
82
- # home country; the proxy that served the request is reported as `exitCountry` (its country)
83
- # and `exitProvider` (its type: `isp`, `residential` or `datacenter`).
82
+ # home country; the country of the proxy that served the request is reported as
83
+ # `exitCountry`.
84
84
  #
85
85
  # @param asin [String] Amazon product id (10-char ASIN, e.g. 'B07PXGQC1Q'; books use their
86
86
  # ISBN-10). Give either `asin` (with `marketplace`) or a product `url`.
@@ -121,8 +121,8 @@ module ScrapeUnblocker
121
121
  # call with `pages`. Filter with `condition`, `free_shipping` and `prime`. `shippingPrice`
122
122
  # is 0 for free delivery and null when Amazon shows no delivery promise for the location.
123
123
  # `proxy_country` defaults to the marketplace's home country so prices and delivery are the
124
- # ones a local shopper sees; the proxy that served the request is reported as `exitCountry`
125
- # and `exitProvider`.
124
+ # ones a local shopper sees; the country of the proxy that served the request is reported as
125
+ # `exitCountry`.
126
126
  #
127
127
  # @param asin [String] Amazon product id (10-char ASIN, e.g. 'B07VGRJDFY'; books use their
128
128
  # ISBN-10). Give either `asin` (with `marketplace`) or a product `url`.
@@ -230,6 +230,38 @@ module ScrapeUnblocker
230
230
  })
231
231
  end
232
232
 
233
+ # Scrape one Walmart product's full detail.
234
+ #
235
+ # Fetches one Walmart product page (by `item_id` or `url`) and returns it as JSON: `itemId`,
236
+ # `title`, `brand`, `model`, `upc`, `price`, `wasPrice`, `listPrice`, `unitPrice` (e.g. per
237
+ # ounce, where Walmart shows one), `currency`, `rollback` / `clearance`, `availability` and
238
+ # `inStock`, `condition`, `seller` (name, Walmart or marketplace seller, its rating and
239
+ # review count), `additionalSellerCount`, `fulfillment` (shipping, pickup and delivery:
240
+ # available or not, date, fee, store or place), `returnPolicy`, `rating`, `reviewCount`,
241
+ # `reviewSummary` (star histogram, recommend percentage, aspect scores), the first
242
+ # `reviews`, `categories`, `shortDescription`, `description`, `highlights`,
243
+ # `specifications`, `warranty`, `variantOptions` and every `variants` entry (its own item
244
+ # id, attributes, price, stock), `images` and `videos`. Fulfillment dates and the store are
245
+ # what Walmart quotes for the US location it assigns to the request (`location` names it),
246
+ # not a ZIP code or store you choose. Other sellers' offers are not on the product page:
247
+ # only their count (`additionalSellerCount`) is returned. Companion to
248
+ # `/marketplace/walmart-search`.
249
+ #
250
+ # @param item_id [String] Walmart item id - the number at the end of a product link, e.g.
251
+ # '18638703162' for walmart.com/ip/.../18638703162.
252
+ # @param url [String] Instead of `item_id`: a walmart.com product link, e.g.
253
+ # https://www.walmart.com/ip/HP-15-6-inch-Laptop/18638703162.
254
+ # @param proxy_country [String] Proxy country the request is sent from (ISO-2). Defaults to
255
+ # US: walmart.com refuses most other countries.
256
+ # Calls POST /marketplace/walmart-product.
257
+ def walmart_product(item_id: nil, url: nil, proxy_country: nil)
258
+ post_json("/marketplace/walmart-product", {
259
+ item_id: item_id,
260
+ url: url,
261
+ proxy_country: proxy_country,
262
+ })
263
+ end
264
+
233
265
  # Scrape Target product search.
234
266
  #
235
267
  # Searches Target for `query` and returns the products as JSON: `tcin`, `title`, `brand`,
@@ -257,6 +289,70 @@ module ScrapeUnblocker
257
289
  })
258
290
  end
259
291
 
292
+ # Scrape a Target category listing.
293
+ #
294
+ # Lists the products of one Target category (by id or category link; a brand page's id or
295
+ # link works too) as JSON: `category` (id, name, link, and `type`: category or brand),
296
+ # `breadcrumbs`, `totalResults`, `totalPages`, and `products` with `tcin`, `title`, `brand`,
297
+ # `price` (`priceMax` for a family priced as a range), `originalPrice` and `priceType` when
298
+ # on sale, `formattedPrice`, `currency`, `rating`, `ratingCount`, `promotions`, `image` and
299
+ # `url`. Sort with `sort`, start at `page` and collect up to `max_results` across pages
300
+ # (Target serves at most 50 pages of 24). Filters in a category link (...Z<facet>) are not
301
+ # applied. Each page fetched is billed as one request (`pagesFetched`).
302
+ #
303
+ # @param category [String] Target category: its id (e.g. '5xtro', the part after N- in a
304
+ # category link) or a target.com category link, e.g. https://www.target.com/c/coffee-makers-
305
+ # tea-espresso-kitchen-appliances-dining/-/N-5xtro. A brand page (/b/<brand>/-/N-<id>) lists
306
+ # that brand.
307
+ # @param sort [String] Order: relevance, price_low, price_high, rating, best_selling,
308
+ # newest. API default: relevance.
309
+ # @param page [Integer] 1-based page to start from (1-50, 24 products per page). API
310
+ # default: 1.
311
+ # @param max_results [Integer] Products to collect across pages (1-240); each page fetched
312
+ # is billed as one request. API default: 24.
313
+ # Calls POST /marketplace/target-category.
314
+ def target_category(category, sort: nil, page: nil, max_results: nil)
315
+ post_json("/marketplace/target-category", {
316
+ category: category,
317
+ sort: sort,
318
+ page: page,
319
+ max_results: max_results,
320
+ })
321
+ end
322
+
323
+ # Scrape one Target product.
324
+ #
325
+ # Returns one Target product by `tcin` or `url` as JSON: `tcin` (and `parentTcin` when it is
326
+ # one variant of a product family), `title`, `brand`, `url`, `dpci`, `upc`, `productType`,
327
+ # `price` (`priceMax` for a family priced as a range), `originalPrice` / `savings` /
328
+ # `savingsPercent` / `priceType` when on sale, `priceNote` (e.g. 'When purchased online'),
329
+ # `currency` (USD), `promotions`, `rating`, `ratingCount`, `reviewCount`,
330
+ # `ratingDistribution`, `recommendedPercent`, `questionCount`, `description`, `highlights`,
331
+ # `specifications`, `image` / `images`, `category` / `categories`, `selectedVariant` and
332
+ # `variants` (every colour / size with its own TCIN, price, link, image and shipping / store
333
+ # availability), `fulfillment` (sold out, shipping status and delivery dates to `zip`,
334
+ # pickup status, date and quantity at `store_id`, aisle) and `packageDimensions`. Prices are
335
+ # target.com's online prices. Companion to `/marketplace/target-search`, whose `tcin` it
336
+ # takes. One unit per call.
337
+ #
338
+ # @param tcin [String] Target item number (TCIN), e.g. '52580270' (the number after A- in a
339
+ # product link).
340
+ # @param url [String] Instead of `tcin`: a target.com product link, e.g.
341
+ # https://www.target.com/p/hamilton-beach-coffee-maker/-/A-52580270 (a `?preselect=` variant
342
+ # in the link is honoured).
343
+ # @param store_id [String] Target store whose pickup and shelf stock is reported, e.g.
344
+ # '1375' (default 1375, Minneapolis Nicollet Mall).
345
+ # @param zip [String] US ZIP code shipping dates are quoted for (default 55403).
346
+ # Calls POST /marketplace/target-product.
347
+ def target_product(tcin = nil, url: nil, store_id: nil, zip: nil)
348
+ post_json("/marketplace/target-product", {
349
+ tcin: tcin,
350
+ url: url,
351
+ store_id: store_id,
352
+ zip: zip,
353
+ })
354
+ end
355
+
260
356
  # Scrape Best Buy product search.
261
357
  #
262
358
  # Searches Best Buy (US) for `query` and returns the products as JSON: `sku`, `title`,
@@ -288,6 +384,32 @@ module ScrapeUnblocker
288
384
  })
289
385
  end
290
386
 
387
+ # Scrape one Best Buy product.
388
+ #
389
+ # Returns one Best Buy (US) product by `sku` or `url` as JSON: `sku`, `title`, `brand`,
390
+ # `model`, `upc`, `productType`, `condition`, `url`, `price`, `originalPrice` / `savings` /
391
+ # `savingsPercent` (when on sale), `currency` (USD), `available` with `availableForShipping`
392
+ # / `availableForPickup` / `availableForDelivery` (nationwide, not for one store or ZIP
393
+ # code), `rating`, `reviewCount`, `description`, `features`, `includedItems`,
394
+ # `specifications` (group / name / value), `image` and `images` (full size), `category` and
395
+ # `categories` (root to leaf), `seller` (Best Buy or a Marketplace seller id),
396
+ # `openBoxOffers` (Excellent / Good / Fair with their prices and links), `dimensions` and
397
+ # `releaseDate`. Companion to `/marketplace/bestbuy-search`, whose `sku` it takes. One unit
398
+ # per call.
399
+ #
400
+ # @param sku [String] Best Buy SKU, e.g. '6613868' (the number after /sku/ in a product
401
+ # link, or its skuId=).
402
+ # @param url [String] Instead of `sku`: a bestbuy.com product link, e.g.
403
+ # https://www.bestbuy.com/product/hp-omnibook-x-flip/JJGQJRKGTJ/sku/6613868 or
404
+ # https://www.bestbuy.com/site/-/6613868.p?skuId=6613868.
405
+ # Calls POST /marketplace/bestbuy-product.
406
+ def bestbuy_product(sku = nil, url: nil)
407
+ post_json("/marketplace/bestbuy-product", {
408
+ sku: sku,
409
+ url: url,
410
+ })
411
+ end
412
+
291
413
  # Scrape Home Depot product search.
292
414
  #
293
415
  # Searches Home Depot for `query` and returns the products as JSON: `itemId`, `title`,
@@ -416,6 +538,39 @@ module ScrapeUnblocker
416
538
  })
417
539
  end
418
540
 
541
+ # Scrape one Etsy listing's full detail.
542
+ #
543
+ # Fetches one Etsy listing (by `listing_id` or `url`) and returns it as JSON: `listingId`,
544
+ # `title`, `price` (the lowest price when variations differ, `priceMax` the highest),
545
+ # `originalPrice` / `onSale` / `discountPercent` / `saleEnds` during a sale, `currency` and
546
+ # `shopperRegion`, `availability` and `quantityAvailable`, `rating` and `reviewCount`,
547
+ # `reviewSummary` (item quality, shipping and service scores, recommend percentage, review
548
+ # tags and categories), the first `reviews`, `shop` (name, id, owner, location, rating,
549
+ # review count, sales, years on Etsy, Star Seller), `variations` (each menu with its options
550
+ # and their prices), `description`, `materials`, `highlights`, `category`, `shipping` (cost,
551
+ # origin, ships from, estimated delivery, processing time, returns), `images` and `video`.
552
+ # Prices, shipping cost and VAT follow the shopper location Etsy assigns to the request,
553
+ # which can differ from `proxy_country`: `currency` and `shopperRegion` say which one a
554
+ # response used (e.g. EUR / BE), so read them before comparing prices. Shop review and sales
555
+ # counts are Etsy's rounded figures ("4.7k sales" is 4700). Companion to `/marketplace/etsy-
556
+ # search`.
557
+ #
558
+ # @param listing_id [String] Etsy listing number, e.g. '1702915637' (the number in
559
+ # etsy.com/listing/1702915637/...).
560
+ # @param url [String] Instead of `listing_id`: an etsy.com listing link, e.g.
561
+ # https://www.etsy.com/listing/1702915637/solstice-mug.
562
+ # @param proxy_country [String] Proxy country the request is sent from (ISO-2). Defaults to
563
+ # US. Etsy prices in the currency of the shopper location it assigns, which can differ from
564
+ # this country; `currency` and `shopperRegion` say which one a response used.
565
+ # Calls POST /marketplace/etsy-product.
566
+ def etsy_product(listing_id: nil, url: nil, proxy_country: nil)
567
+ post_json("/marketplace/etsy-product", {
568
+ listing_id: listing_id,
569
+ url: url,
570
+ proxy_country: proxy_country,
571
+ })
572
+ end
573
+
419
574
  # Scrape SHEIN product search.
420
575
  #
421
576
  # Searches SHEIN (US store) for `query` and returns the products as JSON: `id`, `sku`,
@@ -501,6 +656,40 @@ module ScrapeUnblocker
501
656
  })
502
657
  end
503
658
 
659
+ # Scrape one AliExpress product.
660
+ #
661
+ # Returns one AliExpress item by `product_id` or `url`, priced in `currency` and shipped to
662
+ # `country`, as JSON: `productId`, `url`, `title`, `price` (the default SKU), `priceMin` /
663
+ # `priceMax` across SKUs, `priceFormatted`, `originalPrice` / `originalPriceMax`, `discount`
664
+ # and `discountPercent`, `currency`, `rating`, `reviewCount`, `soldText` and `orders`,
665
+ # `inStock`, `store` (name, ids, link, country, open since, positive feedback, ratings),
666
+ # `shipping` (each option: method, fee, free, ships from / to, delivery days and dates,
667
+ # deliverable), `skuProperties` (e.g. colour, size, ships from, with images), `variants`
668
+ # (every SKU with its attributes, price, original price, availability, stock and image),
669
+ # `specifications`, `images`, `categoryId` and `descriptionUrl` (the seller's HTML
670
+ # description). One unit per call.
671
+ #
672
+ # @param product_id [String] AliExpress item id, e.g. '1005010503016514' (the number in
673
+ # /item/<id>.html; `productId` from /goods/aliexpress-search).
674
+ # @param url [String] Instead of `product_id`: an AliExpress item link, e.g.
675
+ # https://www.aliexpress.com/item/1005010503016514.html (any storefront: .com, .us, de., fr.
676
+ # ...).
677
+ # @param country [String] Ship-to country (ISO-2, e.g. 'US', 'DE', 'GB'). Shipping options,
678
+ # delivery times and whether the item is sold at all depend on it. API default: US.
679
+ # @param currency [String] Price currency, e.g. 'USD', 'EUR', 'GBP'. One of: USD, EUR, GBP,
680
+ # CAD, AUD, NZD, CHF, SEK, NOK, DKK, PLN, CZK, HUF, RON, BGN, TRY, ILS, AED, SAR, JPY, KRW,
681
+ # SGD, MYR, THB, IDR, PHP, VND, INR, BRL, MXN, CLP, COP, PEN, ZAR, UAH, KZT. API default:
682
+ # USD.
683
+ # Calls POST /goods/aliexpress-product.
684
+ def aliexpress_product(product_id = nil, url: nil, country: nil, currency: nil)
685
+ post_json("/goods/aliexpress-product", {
686
+ product_id: product_id,
687
+ url: url,
688
+ country: country,
689
+ currency: currency,
690
+ })
691
+ end
692
+
504
693
  # Scrape Alibaba.com product search results.
505
694
  #
506
695
  # Searches Alibaba.com for `q` and returns the products as JSON: `productId`, `title`,
@@ -1286,6 +1475,734 @@ module ScrapeUnblocker
1286
1475
  })
1287
1476
  end
1288
1477
 
1478
+ # Scrape MediaMarkt search.
1479
+ #
1480
+ # Searches a MediaMarkt shop (`country` de, at, ch, nl, be, es, it = MediaWorld, pl, hu, tr;
1481
+ # `banner=saturn` for Saturn Germany) for `query` and returns `products`, each with
1482
+ # `position`, `productId`, `offerId` (marketplace offers), `title`, `brand`, `ean`, `url`,
1483
+ # `image`, `breadcrumbs`, `price`, `strikePrice` and `strikePriceType` (RRP = manufacturer's
1484
+ # recommended price, LOP = lowest price of the last 30 days), `discountPercent`, `currency`,
1485
+ # `installment`, `marketplace`, `seller` (marketplace seller with rating), `rating`,
1486
+ # `reviewCount`, `availability` (online status, deliverable, store pickup, delivery window
1487
+ # and shipping cost), `energyEfficiency`, `highlights` (key features), `badges`,
1488
+ # `refurbishedFrom` and `sponsored`. Also `total`, `lastPage`, `nextPage` and `listingUrl`
1489
+ # (the category or brand listing MediaMarkt sends this query to, when it does). `sort`
1490
+ # orders the results; `page` and `max_results` page through them (MediaMarkt shows 12 per
1491
+ # page and 30 pages at most). One unit per results page used.
1492
+ #
1493
+ # @param query [String] What to search for, e.g. 'iphone 17' or 'waschmaschine'.
1494
+ # @param country [String] MediaMarkt shop: de, at, ch, nl, be, es, it, pl, hu, tr (default
1495
+ # de; it = MediaWorld). API default: de.
1496
+ # @param banner [String] mediamarkt (default) or saturn (Saturn Germany, with country=de).
1497
+ # API default: mediamarkt.
1498
+ # @param language [String] Site language where the shop has several: be = nl or fr, ch = de,
1499
+ # fr or it. Default: the shop's first.
1500
+ # @param sort [String] Result order: relevance, price_asc, price_desc, rating, bestseller,
1501
+ # newest. API default: relevance.
1502
+ # @param page [Integer] First results page to read (1-30). API default: 1.
1503
+ # @param max_results [Integer] Products to collect across pages, 1-120. A page holds 12
1504
+ # products; each page is one unit. API default: 12.
1505
+ # Calls POST /marketplace/mediamarkt-search.
1506
+ def mediamarkt_search(query, country: nil, banner: nil, language: nil, sort: nil, page: nil, max_results: nil)
1507
+ post_json("/marketplace/mediamarkt-search", {
1508
+ query: query,
1509
+ country: country,
1510
+ banner: banner,
1511
+ language: language,
1512
+ sort: sort,
1513
+ page: page,
1514
+ max_results: max_results,
1515
+ })
1516
+ end
1517
+
1518
+ # Scrape a MediaMarkt product.
1519
+ #
1520
+ # Returns one MediaMarkt / Saturn / MediaWorld product by `product_id` (with `country` /
1521
+ # `banner`) or `url`: `productId`, `title`, `rawTitle`, `brand`, `ean`, `url`,
1522
+ # `breadcrumbs`, `kind`, `price`, `strikePrice`, `strikePriceType`, `discountPercent`,
1523
+ # `currency`, `vatRate`, `installment`, `marketplace`, `seller`, `rating`, `reviewCount`,
1524
+ # `ratingBreakdown` (1-5 stars), `availability` (online status, deliverable, store pickup,
1525
+ # delivery window and shipping cost), `energyEfficiency` (class, label and data sheet),
1526
+ # `highlights`, `specifications` (group / name / value / unit), `images`, `variants`
1527
+ # (dimension, value, product id, price, online status), `badges`, `refurbishedFrom`,
1528
+ # `description` and the latest `reviews`. Store-level stock needs a chosen store and is not
1529
+ # included. One unit per call.
1530
+ #
1531
+ # @param product_id [String] MediaMarkt product number, e.g. 3071615 (the number at the end
1532
+ # of a product link, or `productId` from the search results).
1533
+ # @param url [String] A product link, e.g. https://www.mediamarkt.de/de/product/_apple-
1534
+ # iphone-18-pro-max-256gb-silver-3071615.html. Used instead of `product_id`; its shop and
1535
+ # language win over `country`, `banner` and `language`.
1536
+ # @param country [String] MediaMarkt shop: de, at, ch, nl, be, es, it, pl, hu, tr (default
1537
+ # de; it = MediaWorld). API default: de.
1538
+ # @param banner [String] mediamarkt (default) or saturn (Saturn Germany, with country=de).
1539
+ # API default: mediamarkt.
1540
+ # @param language [String] Site language where the shop has several: be = nl or fr, ch = de,
1541
+ # fr or it. Default: the shop's first.
1542
+ # Calls POST /marketplace/mediamarkt-product.
1543
+ def mediamarkt_product(product_id = nil, url: nil, country: nil, banner: nil, language: nil)
1544
+ post_json("/marketplace/mediamarkt-product", {
1545
+ product_id: product_id,
1546
+ url: url,
1547
+ country: country,
1548
+ banner: banner,
1549
+ language: language,
1550
+ })
1551
+ end
1552
+
1553
+ # Scrape Cdiscount search.
1554
+ #
1555
+ # Searches Cdiscount (France) for `query` and returns `products`, each with `position`,
1556
+ # `productId` (the SKU), `offerId`, `title`, `url`, `image`, `images`, `price`,
1557
+ # `strikePrice` (the crossed-out reference price, only when Cdiscount shows one),
1558
+ # `discountPercent`, `currency` (EUR), `rating`, `reviewCount`, `seller` (id, name,
1559
+ # `isCdiscount`), `marketplace`, `fulfilledByCdiscount`, `cdiscountAVolonte`,
1560
+ # `freeShipping`, `deliveryLabel`, `condition`, `highlights` (key specs), `badges`
1561
+ # (promotions) and `brandId`. Also `total`, `lastPage` and `nextPage`. Search results show
1562
+ # the brand only as an id; the product endpoint has the brand name. `page` and `max_results`
1563
+ # page through the results. One unit per Cdiscount page read.
1564
+ #
1565
+ # @param query [String] What to search for, e.g. 'iphone 15' or 'machine a laver'.
1566
+ # @param page [Integer] First Cdiscount results page to read (1-100). API default: 1.
1567
+ # @param max_results [Integer] Products to collect across pages, 1-300. A page holds about
1568
+ # 47 products; each page is one unit. API default: 47.
1569
+ # Calls POST /marketplace/cdiscount-search.
1570
+ def cdiscount_search(query, page: nil, max_results: nil)
1571
+ post_json("/marketplace/cdiscount-search", {
1572
+ query: query,
1573
+ page: page,
1574
+ max_results: max_results,
1575
+ })
1576
+ end
1577
+
1578
+ # Scrape a Cdiscount product.
1579
+ #
1580
+ # Returns one Cdiscount (France) product by `sku` or `url`: `productId`, `offerId`, `title`,
1581
+ # `brand`, `ean`, `manufacturerReference`, `url`, `breadcrumbs`, `price`, `priceWithoutVat`,
1582
+ # `strikePrice` and `strikePriceType`, `discountPercent`, `ecoParticipation`, `currency`,
1583
+ # `available`, `maxQuantity`, `preorder`, `condition`, `seller` (Cdiscount or the
1584
+ # marketplace seller), `marketplace`, `fulfilledByCdiscount`, `cdiscountAVolonte`,
1585
+ # `delivery` (free shipping, label, ships from), `offers` (count of new and used offers and
1586
+ # the lowest price of each), `rating`, `reviewCount`, `ratingBreakdown` (1-5 stars),
1587
+ # `criteriaRatings`, `highlights`, `specifications` (group / name / value), `description`,
1588
+ # `images`, `videos`, `variants` (attributes, price, url), `energyClass`,
1589
+ # `repairabilityIndex`, `installments`, `badges`, `documents` and the latest `reviews`. The
1590
+ # individual marketplace offers and their sellers' ratings are not included. One unit per
1591
+ # call.
1592
+ #
1593
+ # @param sku [String] Cdiscount product id (SKU), e.g. ip17256black - the part after
1594
+ # f-<number>- in a product link, or `productId` from the search results.
1595
+ # @param url [String] A Cdiscount product link, e.g.
1596
+ # https://www.cdiscount.com/telephonie/telephone-mobile/apple-iphone-17-256gb-
1597
+ # black/f-14404-ip17256black.html. Used instead of `sku`.
1598
+ # Calls POST /marketplace/cdiscount-product.
1599
+ def cdiscount_product(sku = nil, url: nil)
1600
+ post_json("/marketplace/cdiscount-product", {
1601
+ sku: sku,
1602
+ url: url,
1603
+ })
1604
+ end
1605
+
1606
+ # Scrape idealo search.
1607
+ #
1608
+ # Searches idealo (price comparison; `country` de, at, uk, fr, it or es) for `query` and
1609
+ # returns `products`, each with `position`, `type` (product = a price comparison of many
1610
+ # shops, offer = a single shop offer idealo has not matched to a product), `productId`,
1611
+ # `offerId`, `title`, `subtitle`, `characteristics`, `url` (the product's price comparison,
1612
+ # or the shop link of a single offer), `image`, `lowestPrice`, `basePrice` (unit price text,
1613
+ # when idealo shows one), `offerCount`, `usedOnly`, `cheapestShop` (id, name, shipping cost,
1614
+ # delivery, free-return days), `rating` (stars, rounded to half a star by idealo),
1615
+ # `reviewCount`, `testGrade` (the average press test grade, where 1 is best), `energyClass`,
1616
+ # `bargainSavingPercent`, `bestsellerRank`, `categoryId` and `variantOf`. Also `total`,
1617
+ # `productCount`, `lastPage` and `nextPage`, and `currency`. `sort` orders the results
1618
+ # (relevance or price_asc); `page` and `max_results` page through them. Use
1619
+ # `/marketplace/idealo-offers` for all shop offers of one product. One unit per idealo page
1620
+ # read.
1621
+ #
1622
+ # @param query [String] What to search for, e.g. 'iphone 17' or 'kaffeevollautomat'.
1623
+ # @param country [String] idealo site: de, at, uk, fr, it, es (default de; uk =
1624
+ # idealo.co.uk). API default: de.
1625
+ # @param sort [String] Result order: relevance, price_asc (price_asc = cheapest first). API
1626
+ # default: relevance.
1627
+ # @param page [Integer] First idealo results page to read (1-100). API default: 1.
1628
+ # @param max_results [Integer] Products to collect across pages, 1-300. A page holds 60
1629
+ # products; each page is one unit. API default: 60.
1630
+ # Calls POST /marketplace/idealo-search.
1631
+ def idealo_search(query, country: nil, sort: nil, page: nil, max_results: nil)
1632
+ post_json("/marketplace/idealo-search", {
1633
+ query: query,
1634
+ country: country,
1635
+ sort: sort,
1636
+ page: page,
1637
+ max_results: max_results,
1638
+ })
1639
+ end
1640
+
1641
+ # Scrape idealo offers of a product.
1642
+ #
1643
+ # Returns one idealo price comparison by `product_id` or `url` (`country` de, at, uk, fr, it
1644
+ # or es): the product (`productId`, `title`, `brand`, `url`, `images`, `lowestPrice`,
1645
+ # `highestPrice`, `currency`, `offerCount`, `rating`, `reviewCount`, `pros`, `cons`,
1646
+ # `variants` with their own price range and offer count) and `offers`, cheapest first, each
1647
+ # with `position`, `offerKey`, `title` (the shop's own product title), `price`,
1648
+ # `shippingCost`, `totalPrice`, `delivery` (the shop's delivery estimate as idealo prints
1649
+ # it), `carriers`, `freeReturns`, `paymentMethods`, `shop` (id, name, rating, rating count,
1650
+ # marketplace and the marketplace seller), `variantId`, `variantName` and `url` (idealo's
1651
+ # click-out link). Offers are the new-item offers idealo lists by default; `max_results`
1652
+ # collects more than the first 20. One unit for the product and its first 20 offers, plus
1653
+ # one per further block of 20.
1654
+ #
1655
+ # @param product_id [String] idealo product id, e.g. 207643424 (the number in a price
1656
+ # comparison link, or `productId` from the search results).
1657
+ # @param url [String] An idealo price comparison link, e.g.
1658
+ # https://www.idealo.de/preisvergleich/OffersOfProduct/207643424_-iphone-17-apple.html. Used
1659
+ # instead of `product_id`; its site sets the country.
1660
+ # @param country [String] idealo site: de, at, uk, fr, it, es (default de; uk =
1661
+ # idealo.co.uk).
1662
+ # @param max_results [Integer] Offers to collect, 1-200. The first 20 come with the product;
1663
+ # each further block of 20 is one more unit. API default: 20.
1664
+ # Calls POST /marketplace/idealo-offers.
1665
+ def idealo_offers(product_id = nil, url: nil, country: nil, max_results: nil)
1666
+ post_json("/marketplace/idealo-offers", {
1667
+ product_id: product_id,
1668
+ url: url,
1669
+ country: country,
1670
+ max_results: max_results,
1671
+ })
1672
+ end
1673
+
1674
+ # Scrape Rakuten Ichiba (Japan) product search.
1675
+ #
1676
+ # Searches Rakuten Ichiba (rakuten.co.jp) for `query` and returns `products`, each with
1677
+ # `position`, `itemId`, `itemCode`, `shopId` / `shopCode` / `shopName`, `title`, `subtitle`,
1678
+ # `url`, `price` (yen, tax included; `priceMax` when variants are priced differently),
1679
+ # `points` (Rakuten points a signed-out shopper earns) and `pointMultiplier`, `rating`,
1680
+ # `reviewCount`, `shippingFee` / `freeShipping`, `deliveryEstimate`, `nextDayDelivery`,
1681
+ # `unitPrice` / `unitPriceText` / `packCount`, `subscriptionPrice`, `saleEnds`, `ranking`
1682
+ # (daily genre rank), `soldOut`, `used`, `preOrder`, `superDeal`, `hasVariants`, `genreId` /
1683
+ # `genres`, `tags` and `image` / `images`. Rakuten's sponsored results come back in
1684
+ # `sponsored` (same fields). Also `totalResults`, `reachableResults` (how far Rakuten lets
1685
+ # the search be paged), `relatedKeywords` and `nextPage`. Sort with `sort`, filter with
1686
+ # `min_price` / `max_price` / `genre_id`, start at `page` and collect up to `max_results`
1687
+ # across pages (45 per page, each page billed as one request, see `pagesFetched`). `url`
1688
+ # takes a Rakuten search link instead of `query`.
1689
+ #
1690
+ # @param query [String] What to search, in Japanese or English, e.g. 'iphone', 'コーヒー' or
1691
+ # 'ナイキ スニーカー'.
1692
+ # @param sort [String] Order: relevance, price_low, price_high, newest, review_count,
1693
+ # review_score. API default: relevance.
1694
+ # @param page [Integer] 1-based results page to start from (1-150; Rakuten lets a search be
1695
+ # paged through to 6750 items). API default: 1.
1696
+ # @param min_price [Integer] Lowest price, in yen.
1697
+ # @param max_price [Integer] Highest price, in yen.
1698
+ # @param genre_id [String] Limit to one Rakuten genre (category) id, e.g. '100227' (food) -
1699
+ # every result's `genreId` is one.
1700
+ # @param max_results [Integer] Items to collect across pages (1-450); Rakuten serves 45 per
1701
+ # page and each page read is billed as one request. API default: 45.
1702
+ # @param url [String] Instead of `query`: a Rakuten search link, e.g.
1703
+ # https://search.rakuten.co.jp/search/mall/coffee/?s=2 (its keyword, genre, sort, page and
1704
+ # price filter are used).
1705
+ # Calls POST /marketplace/rakuten-search.
1706
+ def rakuten_search(query = nil, sort: nil, page: nil, min_price: nil, max_price: nil, genre_id: nil, max_results: nil, url: nil)
1707
+ post_json("/marketplace/rakuten-search", {
1708
+ query: query,
1709
+ sort: sort,
1710
+ page: page,
1711
+ min_price: min_price,
1712
+ max_price: max_price,
1713
+ genre_id: genre_id,
1714
+ max_results: max_results,
1715
+ url: url,
1716
+ })
1717
+ end
1718
+
1719
+ # Scrape one Rakuten Ichiba (Japan) item's full detail.
1720
+ #
1721
+ # Fetches one Rakuten Ichiba item (by `product_id` '<shopCode>/<itemCode>' or `url`) and
1722
+ # returns it as JSON: `itemId`, `itemCode`, `shopId` / `shopCode` / `shopName`, `url`,
1723
+ # `title`, `tagline`, `description`, `condition`, `price` / `priceMax` (yen, tax included),
1724
+ # `freeShipping`, `available`, `stockQuantity` (when the shop shares it), `deliveryMessage`,
1725
+ # `orderLimit`, `rating`, `reviewCount`, `reviewsUrl`, `genreId`, `breadcrumbs`,
1726
+ # `shopCategories`, `attributes` (name / value / unit), `variantOptions`, `variants` (every
1727
+ # SKU with its options, price, availability, stock, JAN code and image) and `images`. The
1728
+ # top-level price and stock are those of `variant_id` when given. Rakuten points are shown
1729
+ # on search results (`/marketplace/rakuten-search`), not here. Companion to
1730
+ # `/marketplace/rakuten-search`.
1731
+ #
1732
+ # @param product_id [String] The item as '<shopCode>/<itemCode>', e.g. 'dai-one/15-128-a'
1733
+ # (the two path parts of an item link; search results give them as `shopCode` and
1734
+ # `itemCode`).
1735
+ # @param url [String] Instead of `product_id`: a Rakuten item link, e.g.
1736
+ # https://item.rakuten.co.jp/dai-one/15-128-a/ (a `variantId` in it is used).
1737
+ # @param variant_id [String] SKU whose price and stock fill the top-level fields, e.g.
1738
+ # 'r-sku00003161'; by default the item's lowest price and overall availability. Every SKU is
1739
+ # listed in `variants` either way.
1740
+ # Calls POST /marketplace/rakuten-product.
1741
+ def rakuten_product(product_id: nil, url: nil, variant_id: nil)
1742
+ post_json("/marketplace/rakuten-product", {
1743
+ product_id: product_id,
1744
+ url: url,
1745
+ variant_id: variant_id,
1746
+ })
1747
+ end
1748
+
1749
+ # Scrape IndiaMART B2B product search.
1750
+ #
1751
+ # Searches IndiaMART for `query` and returns `products`, each with `position`, `productId`,
1752
+ # `title`, `url` (the IndiaMART product page, or the supplier's catalogue page when
1753
+ # `hasProductPage` is false - only products with a page can be fetched with
1754
+ # `/marketplace/indiamart-product`), `price` (number, null when the supplier asks for a
1755
+ # quote) and `priceText`, `currency`, `unit` (the price is per this unit),
1756
+ # `minOrderQuantity`, `category` / `categoryId`, `specifications` (name / value),
1757
+ # `description`, `image`, `brochureUrl`, `supplier` (`id`, `name`, `city`, `district`,
1758
+ # `state`, `country`, `businessType`, `verifiedExporter`, `trustSeal`, `gstVerified`,
1759
+ # `iecVerified`, `rating`, `ratingCount`, `memberSince`, `exporterSince`, `exportsTo`,
1760
+ # `website`) and `moreFromSupplier` (the supplier's other matching products). IndiaMART
1761
+ # shows visitors outside India its export catalogue, so results are IndiaMART's verified
1762
+ # exporters, 10 a page and 2 pages (up to 20 products per search); `totalResults` is
1763
+ # IndiaMART's own count of all matches. Supplier phone numbers, e-mails and contact names
1764
+ # are not returned. `url` takes an IndiaMART search link instead of `query`.
1765
+ #
1766
+ # @param query [String] What to search, e.g. 'steel pipe', 'cotton t shirt' or 'solar
1767
+ # panel'.
1768
+ # @param page [Integer] 1-based results page to start from (1-2); 10 products a page. API
1769
+ # default: 1.
1770
+ # @param max_results [Integer] Products to collect across pages (1-20); IndiaMART serves 10
1771
+ # per page and shows 2 pages. Each page read is billed as one request. API default: 20.
1772
+ # @param url [String] Instead of `query`: an IndiaMART search link, e.g.
1773
+ # https://dir.indiamart.com/search.mp?ss=steel+pipe (its keyword is used).
1774
+ # Calls POST /marketplace/indiamart-search.
1775
+ def indiamart_search(query = nil, page: nil, max_results: nil, url: nil)
1776
+ post_json("/marketplace/indiamart-search", {
1777
+ query: query,
1778
+ page: page,
1779
+ max_results: max_results,
1780
+ url: url,
1781
+ })
1782
+ end
1783
+
1784
+ # Scrape one IndiaMART product and its supplier.
1785
+ #
1786
+ # Fetches one IndiaMART product (by `product_id` or `url`) and returns it as JSON:
1787
+ # `productId`, `title`, `name`, `url`, `price` (null when the supplier asks for a quote) /
1788
+ # `priceText`, `currency`, `unit`, `minOrderQuantity`, `description`, `specifications` (name
1789
+ # / value), `category` / `categoryId` / `parentCategory` / `group`, `deliveryTime`,
1790
+ # `packagingDetails`, `productionCapacity`, `portOfDispatch`, `paymentTerms`, `image` /
1791
+ # `images`, `brochureUrl` and `supplier` (`id`, `name`, `city`, `state`, `country`,
1792
+ # `businessType`, `additionalBusiness`, `yearEstablished`, `employees`, `annualTurnover`,
1793
+ # `legalStatus`, `gstVerified`, `trustSeal`, `mobileVerified`, `emailVerified`, `rating`,
1794
+ # `ratingCount`, `memberSince`, `topExportCountries`, `website`, `logo`). Supplier phone
1795
+ # numbers, e-mails, people's names and street addresses are not returned. Companion to
1796
+ # `/marketplace/indiamart-search`.
1797
+ #
1798
+ # @param product_id [String] IndiaMART product id, e.g. '2854548650133' (the number at the
1799
+ # end of a /proddetail/ link; search results give it as `productId`).
1800
+ # @param url [String] Instead of `product_id`: an IndiaMART product link, e.g.
1801
+ # https://www.indiamart.com/proddetail/stainless-steel-347h-pipes-2854548650133.html.
1802
+ # Calls POST /marketplace/indiamart-product.
1803
+ def indiamart_product(product_id: nil, url: nil)
1804
+ post_json("/marketplace/indiamart-product", {
1805
+ product_id: product_id,
1806
+ url: url,
1807
+ })
1808
+ end
1809
+
1810
+ # Scrape Bed Bath & Beyond product search.
1811
+ #
1812
+ # Searches Bed Bath & Beyond (bedbathandbeyond.com, US) for `query` and returns the products
1813
+ # as JSON: `productId`, `sku`, `title`, `url`, `image`, `price` (the lowest option price)
1814
+ # and `priceMax` (the top of the range when options differ), `priceText`, `priceType` (SALE
1815
+ # or STANDARD), `currency` (USD), `comparePrice` with `compareType` (MSRP, COMPARE_AT or
1816
+ # WAS), `discountPercent`, `regularPrice`, `hasOptions`, `optionCount`, `rating`,
1817
+ # `reviewCount`, `badge` (e.g. Best Seller), `onSale`, `fastDelivery`, `rewards` (Welcome
1818
+ # Rewards dollars) and `sponsored`. Sort with `sort`, start at `page`, and collect up to
1819
+ # `max_results` across pages (about 60 per page, each page billed as one request, see
1820
+ # `pagesFetched`). Keywords the site maps to a department (e.g. 'rugs') return that
1821
+ # department's listing, named in `redirectedTo`. `url` takes a search link instead of
1822
+ # `query`.
1823
+ #
1824
+ # @param query [String] What to search, e.g. 'bath towels', 'office chair' or 'table lamp'.
1825
+ # @param sort [String] Order: relevance, on_sale, best_selling, price_low, price_high,
1826
+ # rating, newest. API default: relevance.
1827
+ # @param page [Integer] 1-based results page to start from (1-100). API default: 1.
1828
+ # @param max_results [Integer] Products to collect across pages (1-300); the site serves
1829
+ # about 60 per page and each page fetched is billed as one request. API default: 60.
1830
+ # @param url [String] Instead of `query`: a Bed Bath & Beyond search link, e.g.
1831
+ # https://www.bedbathandbeyond.com/search?keywords=towels (its sort and page are used).
1832
+ # Calls POST /marketplace/bedbathandbeyond-search.
1833
+ def bedbathandbeyond_search(query = nil, sort: nil, page: nil, max_results: nil, url: nil)
1834
+ post_json("/marketplace/bedbathandbeyond-search", {
1835
+ query: query,
1836
+ sort: sort,
1837
+ page: page,
1838
+ max_results: max_results,
1839
+ url: url,
1840
+ })
1841
+ end
1842
+
1843
+ # Scrape one Bed Bath & Beyond product's full detail.
1844
+ #
1845
+ # Fetches one Bed Bath & Beyond product (by id or link) and returns it as JSON: `productId`,
1846
+ # `sku`, `url`, `title`, `brand`, `brandUrl`, `manufacturerPartNumber`, `price` with
1847
+ # `priceLabel` (e.g. 'Sale Starts at' when options are priced differently), `comparePrice`
1848
+ # with `compareLabel` (MSRP, Was, At other retailer), `savings`, `savingsPercent`,
1849
+ # `currency` (USD), `inStock`, `rating`, `reviewCount`, `ratingHistogram`, `badge`,
1850
+ # `shortDescription`, `description`, `countryOfOrigin`, `freeShipping`,
1851
+ # `internationalShipping`, `firstListed`, `breadcrumbs`, `specifications` (group / name /
1852
+ # value), `optionCount`, `defaultOptionId`, `options` (up to 100: option id, title, size /
1853
+ # colour attributes, price, regular price, compare price, on-sale flag, stock and quantity
1854
+ # on hand), `images` and `videos`. Prices are those shown to a signed-out shopper. Companion
1855
+ # to `/marketplace/bedbathandbeyond-search`.
1856
+ #
1857
+ # @param product [String] A Bed Bath & Beyond product id (e.g. '5296998', the number before
1858
+ # /product.html) or a product link.
1859
+ # Calls POST /marketplace/bedbathandbeyond-product.
1860
+ def bedbathandbeyond_product(product)
1861
+ post_json("/marketplace/bedbathandbeyond-product", {
1862
+ product: product,
1863
+ })
1864
+ end
1865
+
1866
+ # Scrape Petco product search.
1867
+ #
1868
+ # Searches Petco (petco.com, US) for `query` and returns the products as JSON: `sku`,
1869
+ # `productId`, `title`, `familyName`, `brand`, `url`, `image`, `price`, `listPrice`,
1870
+ # `autoshipPrice` (the Repeat Delivery price), `onSale`, `currency` (USD), `rating`,
1871
+ # `reviewCount`, `description`, `category`, `autoshipEligible`, `pickupEligible`,
1872
+ # `sameDayDeliveryEligible`, `inStoreOnly`, `prescriptionFood`, `attributes` (brand,
1873
+ # flavour, life stage...) and `variations` (every size / colour with its SKU, url and
1874
+ # prices). Sort with `sort`, narrow with `brand`, `fulfillment` (delivery, autoship, pickup,
1875
+ # same_day) and `min_price` / `max_price`, start at `page` and collect up to `max_results`
1876
+ # (48 per page, each page billed as one request, see `pagesFetched`). A term Petco sends to
1877
+ # a brand or category page (e.g. a brand name) returns that page's listing, named in
1878
+ # `redirectedTo`. Prices are the online prices a signed-out shopper sees; store-specific
1879
+ # stock and member (Vital Care) prices are not included.
1880
+ #
1881
+ # @param query [String] What to search, e.g. 'dog food', 'cat litter' or 'fish tank'.
1882
+ # @param sort [String] Order: relevance, price_low, price_high, rating, popular, newest,
1883
+ # name_asc, name_desc. API default: relevance.
1884
+ # @param page [Integer] 1-based results page to start from (1-200), 48 products per page as
1885
+ # on petco.com. API default: 1.
1886
+ # @param max_results [Integer] Products to collect across pages (1-480); each page of 48
1887
+ # fetched is billed as one request. API default: 48.
1888
+ # @param brand [String] Only this brand, as petco.com names it (e.g. 'Purina Pro Plan'; the
1889
+ # `brands` list of a search shows the names).
1890
+ # @param fulfillment [String] Only products offered this way: delivery, autoship, pickup,
1891
+ # same_day.
1892
+ # @param min_price [Float] Lowest price to include (USD).
1893
+ # @param max_price [Float] Highest price to include (USD).
1894
+ # @param url [String] Instead of `query`: a petco.com search link, e.g.
1895
+ # https://www.petco.com/shop/en/petcostore/search?query=dog%20food.
1896
+ # Calls POST /marketplace/petco-search.
1897
+ def petco_search(query = nil, sort: nil, page: nil, max_results: nil, brand: nil, fulfillment: nil, min_price: nil, max_price: nil, url: nil)
1898
+ post_json("/marketplace/petco-search", {
1899
+ query: query,
1900
+ sort: sort,
1901
+ page: page,
1902
+ max_results: max_results,
1903
+ brand: brand,
1904
+ fulfillment: fulfillment,
1905
+ min_price: min_price,
1906
+ max_price: max_price,
1907
+ url: url,
1908
+ })
1909
+ end
1910
+
1911
+ # Scrape one Petco product's full detail.
1912
+ #
1913
+ # Fetches one Petco product (by SKU or link) and returns it as JSON: `sku`, `catEntryId`,
1914
+ # `parentSku`, `url`, `title`, `brand`, `upc`, `price`, `listPrice`, `autoshipPrice`,
1915
+ # `pickupPrice`, `onSale`, `currency` (USD), `availability`, `inStock`, `availableQuantity`
1916
+ # (online stock), `rating`, `reviewCount`, `ratingHistogram`, `recommendedPercent`,
1917
+ # `description`, `highlights`, `ingredients`, `directions`, `specifications` (group / name /
1918
+ # value), `attributes` (size / weight / colour of this variant), `dimensions`, `petType`,
1919
+ # `category`, `breadcrumbs`, fulfillment flags (`autoshipEligible`, `pickupEligible`,
1920
+ # `sameDayDeliveryEligible`, `onlineOnly`, `inStoreOnly`), `prescriptionRequired`,
1921
+ # `discontinued`, `images`, `variants` (every size / colour with its SKU, url, prices and
1922
+ # stock) and the first `reviews` (up to 10). A link's own variant is returned; a SKU picks
1923
+ # that variant. Prices are the online prices a signed-out shopper sees (no member or store
1924
+ # prices). Companion to `/marketplace/petco-search`.
1925
+ #
1926
+ # @param product [String] A Petco SKU (the number a product link ends in, e.g. '3748364') or
1927
+ # a petco.com product link.
1928
+ # Calls POST /marketplace/petco-product.
1929
+ def petco_product(product)
1930
+ post_json("/marketplace/petco-product", {
1931
+ product: product,
1932
+ })
1933
+ end
1934
+
1935
+ # Scrape one Neobits product.
1936
+ #
1937
+ # Fetches one product from Neobits (neobits.com, US B2B electronics and IT reseller) by item
1938
+ # number or link and returns it as JSON: `itemNumber`, `url`, `title`, `brand`, `brandUrl`,
1939
+ # `mfrPartNumber`, `price`, `listPrice`, `savings`, `discountPercent`, `priceDrop`,
1940
+ # `currency` (USD), `stockStatus` (e.g. In Stock, SHIPS SOON), `inStock`, `stockNote`,
1941
+ # `leadTime` (the brand's average lead time when shown), `rating`, `reviewCount`,
1942
+ # `questionCount`, `description`, `specifications` (name / value), `breadcrumbs` and
1943
+ # `images`. Neobits search is not offered: the site gates its search and listing pages
1944
+ # behind a reCAPTCHA for automated traffic.
1945
+ #
1946
+ # @param product [String] A Neobits item number (the 'Item #' on a product page, e.g.
1947
+ # '27956233') or a neobits.com product link (ending in _p<item>.html).
1948
+ # Calls POST /marketplace/neobits-product.
1949
+ def neobits_product(product)
1950
+ post_json("/marketplace/neobits-product", {
1951
+ product: product,
1952
+ })
1953
+ end
1954
+
1955
+ # Scrape Lowe's product search.
1956
+ #
1957
+ # Searches Lowe's (lowes.com, US) for `query` at one store and returns `products`:
1958
+ # `productId` (Lowe's item id), `itemNumber`, `modelNumber`, `brand`, `title`, `url`,
1959
+ # `image`, `rating`, `reviewCount`, `price`, `wasPrice`, `savings`, `savingsPercent` and
1960
+ # `saleEnds` (promotions), `clearance`, `minPrice` / `maxPrice` (items with options),
1961
+ # `priceType` (store, network = Lowe's online price, sos = special order), `currency`,
1962
+ # `availability` (`pickup` with the units on hand at the store, `parcel`, `delivery`,
1963
+ # `expeditedDelivery`), `sponsored`, `marketplace`, `bullets` and `specifications`, plus
1964
+ # `store` (the store the prices and stock are for) and paging totals. Set the store with
1965
+ # `store_id` or `zip` (default: store 1845, Chicago-Brickyard, IL). Results come in Lowe's
1966
+ # own order; `free_delivery` keeps free-delivery items only. Start at `page` and collect up
1967
+ # to `max_results` across pages (24 per page, each page billed as one request, see
1968
+ # `pagesFetched`). A broad keyword Lowe's sends to a category landing page (e.g. patio
1969
+ # furniture) is answered from the landing page's first category tile that names the keyword;
1970
+ # `category` names it (null for a plain search). A landing page without such a tile answers
1971
+ # 404: search a more specific term.
1972
+ #
1973
+ # @param query [String] What to search, e.g. 'cordless drill', 'garden hose' or 'interior
1974
+ # paint'.
1975
+ # @param page [Integer] 1-based results page to start from (1-30, 24 products per page). API
1976
+ # default: 1.
1977
+ # @param max_results [Integer] Products to collect across pages (1-72); each page fetched is
1978
+ # billed as one request. API default: 24.
1979
+ # @param store_id [String] Lowe's store number whose prices and stock to return, e.g.
1980
+ # '1845'. Give this or `zip`; with neither, store 1845 (Chicago-Brickyard, IL) is used. The
1981
+ # store used is named in `store`.
1982
+ # @param zip [String] US ZIP code; the nearest Lowe's store is used, e.g. '60639'.
1983
+ # @param free_delivery [Boolean] Only items Lowe's delivers for free. API default: false.
1984
+ # @param url [String] Instead of `query`: a Lowe's search link, e.g.
1985
+ # https://www.lowes.com/search?searchTerm=garden+hose (its offset and storeId are used).
1986
+ # Calls POST /marketplace/lowes-search.
1987
+ def lowes_search(query = nil, page: nil, max_results: nil, store_id: nil, zip: nil, free_delivery: nil, url: nil)
1988
+ post_json("/marketplace/lowes-search", {
1989
+ query: query,
1990
+ page: page,
1991
+ max_results: max_results,
1992
+ store_id: store_id,
1993
+ zip: zip,
1994
+ free_delivery: free_delivery,
1995
+ url: url,
1996
+ })
1997
+ end
1998
+
1999
+ # Scrape one Lowe's product.
2000
+ #
2001
+ # Fetches one Lowe's product (by `product_id` or `url`) priced for one store and returns it
2002
+ # as JSON: `productId`, `itemNumber`, `modelNumber`, `upc`, `brand`, `title`, `url`,
2003
+ # `rating`, `reviewCount`, `price`, `wasPrice`, `savings`, `savingsPercent`, `saleEnds`,
2004
+ # `clearance`, `priceType`, `currency`, `storeId`, `availability` (`pickup` with the units
2005
+ # on hand at the store and at `nearbyStores`, `parcel`, `delivery`, `expeditedDelivery` with
2006
+ # lead times), `description`, `bullets`, `specifications` (name / value / group), `images`,
2007
+ # `videos`, `documents`, `category`, `dimensions`, `weightLbs`, `buyable` and `status`, plus
2008
+ # `store`. Set the store with `store_id` or `zip` (default: store 1845, Chicago-Brickyard,
2009
+ # IL). Companion to `/marketplace/lowes-search`.
2010
+ #
2011
+ # @param product_id [String] Lowe's item id, e.g. '5016412045' (the number at the end of a
2012
+ # product link; the `productId` of a search result).
2013
+ # @param url [String] Instead of `product_id`: a Lowe's product link, e.g.
2014
+ # https://www.lowes.com/pd/CRAFTSMAN-20-volt-Max-Drill/5016412045.
2015
+ # @param store_id [String] Lowe's store number whose prices and stock to return, e.g.
2016
+ # '1845'. Give this or `zip`; with neither, store 1845 (Chicago-Brickyard, IL) is used. The
2017
+ # store used is named in `store`.
2018
+ # @param zip [String] US ZIP code; the nearest Lowe's store is used, e.g. '60639'.
2019
+ # Calls POST /marketplace/lowes-product.
2020
+ def lowes_product(product_id = nil, url: nil, store_id: nil, zip: nil)
2021
+ post_json("/marketplace/lowes-product", {
2022
+ product_id: product_id,
2023
+ url: url,
2024
+ store_id: store_id,
2025
+ zip: zip,
2026
+ })
2027
+ end
2028
+
2029
+ # Scrape Menards product search.
2030
+ #
2031
+ # Searches Menards (menards.com, US) for `query` and returns `products`: `itemId`, `sku`
2032
+ # (the Menards SKU), `modelNumber` (when Menards lists it), `title`, `brand`, `url`,
2033
+ # `image`, `price` (shelf price before the mail-in rebate), `regularPrice` (everyday low
2034
+ # price), `onSale`, `rebate` and `rebateLabel` (Menards' rebate, usually 11%),
2035
+ # `priceAfterRebate` (null when the maker's advertised-price policy moves it to checkout:
2036
+ # `priceInCheckout` true, `minimumAdvertisedPrice`), `unitOfMeasure`, `currency`,
2037
+ # `availability` (`pickup`, `delivery`, `stockAtStore`, `stockMessage`, `deliveryMessage`),
2038
+ # `variationCount` and `categoryId`, plus `totalResults`, `facets` and `store` (the store
2039
+ # the prices and stock are for). Set the store with `store_id` or `zip`; without one Menards
2040
+ # shows its default online prices and no store stock. Sort with `sort`, filter with
2041
+ # `min_price` / `max_price`, `in_stock_today`, `delivery_eligible` and `pickup_eligible`,
2042
+ # start at `page` and collect up to `max_results` across pages (40 per page, each page
2043
+ # billed as one request, see `pagesFetched`). A keyword Menards sends to a category returns
2044
+ # that category's products (`redirectedTo`); a Menards SKU returns no products and the
2045
+ # product link in `redirectedTo`. A keyword Menards sends to a page of category tiles (e.g.
2046
+ # interior paint) or one with no matches answers 404.
2047
+ #
2048
+ # @param query [String] What to search, e.g. 'cordless drill', 'garden hose' or '2x4
2049
+ # lumber'.
2050
+ # @param sort [String] Order: relevance, price_low, price_high, title_asc, title_desc,
2051
+ # brand_asc, brand_desc. API default: relevance.
2052
+ # @param page [Integer] 1-based results page to start from (1-100, 40 products per page).
2053
+ # API default: 1.
2054
+ # @param max_results [Integer] Products to collect across pages (1-120); each page fetched
2055
+ # is billed as one request. API default: 40.
2056
+ # @param min_price [Float] Lowest price to include (USD).
2057
+ # @param max_price [Float] Highest price to include (USD).
2058
+ # @param store_id [String] Menards store number whose prices and stock to return, e.g.
2059
+ # '3181'. Give this or `zip`; with neither, Menards' default (online) prices are returned
2060
+ # and `stockAtStore` is 0. The store used is named in `store`.
2061
+ # @param zip [String] US ZIP code; the nearest Menards store is used, e.g. '55401'.
2062
+ # @param in_stock_today [Boolean] Only items in stock today at the store (needs `store_id`
2063
+ # or `zip`). API default: false.
2064
+ # @param delivery_eligible [Boolean] Only items eligible for delivery. API default: false.
2065
+ # @param pickup_eligible [Boolean] Only items eligible for in-store pickup. API default:
2066
+ # false.
2067
+ # Calls POST /marketplace/menards-search.
2068
+ def menards_search(query, sort: nil, page: nil, max_results: nil, min_price: nil, max_price: nil, store_id: nil, zip: nil, in_stock_today: nil, delivery_eligible: nil, pickup_eligible: nil)
2069
+ post_json("/marketplace/menards-search", {
2070
+ query: query,
2071
+ sort: sort,
2072
+ page: page,
2073
+ max_results: max_results,
2074
+ min_price: min_price,
2075
+ max_price: max_price,
2076
+ store_id: store_id,
2077
+ zip: zip,
2078
+ in_stock_today: in_stock_today,
2079
+ delivery_eligible: delivery_eligible,
2080
+ pickup_eligible: pickup_eligible,
2081
+ })
2082
+ end
2083
+
2084
+ # Scrape one Menards product.
2085
+ #
2086
+ # Fetches one Menards product (by `url` or `sku`) and returns it as JSON: `itemId`, `sku`,
2087
+ # `modelNumber`, `title`, `brand`, `url`, `price` (shelf price), `regularPrice` (everyday
2088
+ # low price), `onSale` and `saleEnds`, `minimumAdvertisedPrice` and `priceInCheckout` (items
2089
+ # whose maker lets Menards show its price only in checkout: `price` is then null), `rebate`,
2090
+ # `rebateLabel`, `rebateEnds`, `priceAfterRebate`, `offerPrice`, `currency`, `availability`,
2091
+ # `storeId`, `description`, `features`, `specifications` (name / value), `images` and
2092
+ # `breadcrumbs`. Prices are Menards' default online prices (the store in `storeId`); for one
2093
+ # store's prices and stock use `/marketplace/menards-search` with `store_id` or `zip`.
2094
+ #
2095
+ # @param url [String] A Menards product link, e.g.
2096
+ # https://www.menards.com/main/electrical/electrical-tools-accessories/electrical-hand-
2097
+ # tools/southwire-reg-7-1-2-mc-rotary-cutter/mccut/p-60893668339-c-6455.htm (the `url` of a
2098
+ # search result).
2099
+ # @param sku [String] Instead of `url`: the Menards SKU shown on the product page and in
2100
+ # search results, e.g. '3646903'.
2101
+ # Calls POST /marketplace/menards-product.
2102
+ def menards_product(url: nil, sku: nil)
2103
+ post_json("/marketplace/menards-product", {
2104
+ url: url,
2105
+ sku: sku,
2106
+ })
2107
+ end
2108
+
2109
+ # Scrape Grainger product search.
2110
+ #
2111
+ # Searches Grainger (grainger.com, US industrial supplies) for `query` and returns
2112
+ # Grainger's first result rows (up to 25 items, in Grainger's order) as `products`:
2113
+ # `position`, `sku` (Grainger item number), `productId`, `title`, `brand`,
2114
+ # `manufacturerModel`, `url`, `image`, `price` (Grainger's signed-out Web Price),
2115
+ # `priceLabel`, `priceType`, `wasPrice`, `quantityPricing`, `currency`, `status` (e.g.
2116
+ # Sellable) and `specifications` (name / value, e.g. thread size, voltage, material).
2117
+ # Grainger answers a keyword with the product category that matches it best: `category`
2118
+ # names it, `totalResults` counts that category's matches, and `categories` lists the other
2119
+ # matching categories with counts and links (search one of them by passing its link as
2120
+ # `url`). A keyword that leads to a department page (subcategory tiles, no products) is
2121
+ # answered from the subcategory holding the product line that matches it most often:
2122
+ # `category` names that subcategory, `totalAcrossCategories` counts the department and
2123
+ # `categories` lists its subcategories. Only the first result rows are returned (no paging).
2124
+ # Stock is not included: Grainger checks it per ZIP code after the page loads.
2125
+ #
2126
+ # @param query [String] What to search, e.g. 'safety glasses', 'hex bolt', 'cordless drill'
2127
+ # or a manufacturer model.
2128
+ # @param max_results [Integer] Items to return (1-25); Grainger's first result rows for the
2129
+ # keyword. API default: 25.
2130
+ # @param url [String] Instead of `query`: a Grainger search link, e.g.
2131
+ # https://www.grainger.com/search?searchQuery=hex+bolt.
2132
+ # Calls POST /marketplace/grainger-search.
2133
+ def grainger_search(query = nil, max_results: nil, url: nil)
2134
+ post_json("/marketplace/grainger-search", {
2135
+ query: query,
2136
+ max_results: max_results,
2137
+ url: url,
2138
+ })
2139
+ end
2140
+
2141
+ # Scrape one Grainger product.
2142
+ #
2143
+ # Fetches one Grainger item (by `sku`, the Grainger item number, or `url`) and returns it as
2144
+ # JSON: `sku`, `productId`, `title`, `brand`, `manufacturerModel`, `url`, `price` (signed-
2145
+ # out Web Price), `priceLabel`, `priceType`, `wasPrice`, `unitOfMeasure` (e.g. 'pkg. of
2146
+ # 100'), `quantityPricing`, `currency`, `status`, `discontinued`, `sellInfo`,
2147
+ # `shippingWeight`, `description`, `specifications` (name / value, including UNSPSC and
2148
+ # country of origin), `images`, `documents` (spec sheets, drawings), `alternateSkus` and
2149
+ # `breadcrumbs`. Stock is not included: Grainger checks it per ZIP code after the page
2150
+ # loads.
2151
+ #
2152
+ # @param sku [String] Grainger item number, e.g. '1XE66' or '22TA59' (the `sku` of a search
2153
+ # result).
2154
+ # @param url [String] Instead of `sku`: a Grainger product link, e.g.
2155
+ # https://www.grainger.com/product/Hex-Head-Cap-Screw-Stainless-1XE66.
2156
+ # Calls POST /marketplace/grainger-product.
2157
+ def grainger_product(sku = nil, url: nil)
2158
+ post_json("/marketplace/grainger-product", {
2159
+ sku: sku,
2160
+ url: url,
2161
+ })
2162
+ end
2163
+
2164
+ # Scrape one eBay listing's full detail.
2165
+ #
2166
+ # Fetches one eBay listing (by `item_id` + `marketplace`, or `url`) on any supported eBay
2167
+ # site and returns it as JSON: `itemId`, `title`, `status` (active / ended), `price` +
2168
+ # `currency`, `originalPrice` (list or was price), `listingFormat` (buy_it_now, auction,
2169
+ # auction_with_buy_it_now) with `buyItNowPrice`, `currentBid`, `bidCount`, `reserveMet` and
2170
+ # `endsAt`, `listingPrice` / `listingCurrency` when the seller lists in another currency,
2171
+ # `condition` (with `conditionCode` and the seller's `conditionNotes`), `availability`,
2172
+ # `quantityAvailable`, `quantitySold`, `watchers`, `seller` (username, store name, feedback
2173
+ # score, positive percentage, business or private), `shippingRates` (cost per destination
2174
+ # country), `shipping`, `itemLocation`, `delivery`, `importFees`, `returns`, `brand`, `mpn`,
2175
+ # `gtin`, `itemSpecifics`, `categories`, `paymentMethods`, `variationOptions` and
2176
+ # `variations` (each with its own price and stock), `images` and the seller's `description`
2177
+ # as text. Labels and texts follow the site's language (ebay.de answers in German).
2178
+ # Shipping, delivery dates and, on EU sites, VAT-inclusive prices are quoted for the country
2179
+ # the request comes from: pass `proxy_country` to fix it. Companion to `/marketplace/ebay-
2180
+ # search`.
2181
+ #
2182
+ # @param item_id [String] eBay item number, e.g. '335761219642' (the number in
2183
+ # ebay.com/itm/335761219642).
2184
+ # @param url [String] Instead of `item_id`: a listing link on any supported eBay site, e.g.
2185
+ # https://www.ebay.de/itm/860089403886. The site is taken from the link.
2186
+ # @param marketplace [String] eBay site to open `item_id` on (prices, currency and language
2187
+ # follow it). One of: ebay.com, ebay.co.uk, ebay.de, ebay.fr, ebay.it, ebay.es, ebay.nl,
2188
+ # ebay.pl, ebay.at, ebay.ch, ebay.be, ebay.ie, ebay.ca, ebay.com.au, ebay.in, ebay.com.sg,
2189
+ # ebay.com.my, ebay.com.hk. Default ebay.com.
2190
+ # @param include_description [Boolean] Also fetch the seller's description text (a second,
2191
+ # light request). Set false for a faster call without `description`. API default: true.
2192
+ # @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
2193
+ # 'DE'). eBay quotes shipping, delivery dates and, on EU sites, VAT-inclusive prices for the
2194
+ # visitor's country, so set it to get them for one country.
2195
+ # Calls POST /marketplace/ebay-product.
2196
+ def ebay_product(item_id: nil, url: nil, marketplace: nil, include_description: nil, proxy_country: nil)
2197
+ post_json("/marketplace/ebay-product", {
2198
+ item_id: item_id,
2199
+ url: url,
2200
+ marketplace: marketplace,
2201
+ include_description: include_description,
2202
+ proxy_country: proxy_country,
2203
+ })
2204
+ end
2205
+
1289
2206
  # Scrape Vinted product search.
1290
2207
  #
1291
2208
  # Searches Vinted for `query` and returns the listings as JSON: `title`, `price` and
@@ -2615,8 +3532,8 @@ module ScrapeUnblocker
2615
3532
  # `url`, or a raw `feature_id` (0xHEX:0xHEX). Location-neutral - the feature id resolves the
2616
3533
  # place directly; `proxy_country` defaults to a US proxy to clear Google's consent wall.
2617
3534
  #
2618
- # @param url [String] A Google Maps place URL (share link or /maps/place/... URL). The
2619
- # feature id or place_id is read out of it.
3535
+ # @param url [String] A Google Maps place URL: a /maps/place/... URL, a maps.app.goo.gl
3536
+ # share link or a maps?cid= link. The place is read out of it.
2620
3537
  # @param place_id [String] A Google place_id, e.g. 'ChIJN1t_tDeuEmsRUsoyG83frY4'.
2621
3538
  # @param feature_id [String] A Maps feature id '0xHEX:0xHEX', e.g.
2622
3539
  # '0x47e66e2964e34e2d:0x8ddca9ee380ef7e0'. Fastest - no resolve step.
@@ -2638,6 +3555,51 @@ module ScrapeUnblocker
2638
3555
  })
2639
3556
  end
2640
3557
 
3558
+ # Scrape Google Maps reviews.
3559
+ #
3560
+ # Returns one Google Maps place's reviews as JSON, sorted the way Google sorts them:
3561
+ # `relevant`, `newest`, `highest` or `lowest`. Each review has `rating` (1-5), `date` (exact
3562
+ # ISO 8601, UTC) + `timestamp`, `relativeDate`, `text` (original) + `language`,
3563
+ # `translatedText` (into `hl`, when the review is in another language), `author`, `photos`,
3564
+ # `details` (guided answers such as 'Rooms: 5'), `ownerResponse` and `reviewUrl`. The answer
3565
+ # also carries a `place` summary and `nextPageToken` for paging. Identify the place with
3566
+ # `feature_id` (0xHEX:0xHEX), `place_id` (ChIJ...) or a Maps `url`. Reviews come in pages of
3567
+ # 20; each page fetched is one billed unit.
3568
+ #
3569
+ # @param url [String] A Google Maps place URL: a /maps/place/... URL, a maps.app.goo.gl
3570
+ # share link or a maps?cid= link. The place is read out of it.
3571
+ # @param place_id [String] A Google place_id, e.g. 'ChIJN1t_tDeuEmsRUsoyG83frY4'.
3572
+ # @param feature_id [String] A Maps feature id '0xHEX:0xHEX', e.g.
3573
+ # '0x4776901a5d4813b3:0x2a497c8b414893c'. Fastest - no resolve step.
3574
+ # @param sort [String] Review order: 'relevant' (Google's default), 'newest', 'highest' or
3575
+ # 'lowest'. SerpApi's 'qualityScore', 'newestFirst', 'ratingHigh' and 'ratingLow' are
3576
+ # accepted too. API default: relevant.
3577
+ # @param max_reviews [Integer] How many reviews to return, 1-200. Reviews come in pages of
3578
+ # 20; each page fetched is one billed unit. API default: 20.
3579
+ # @param next_page_token [String] Continue from a previous answer's `nextPageToken` (same
3580
+ # place and sort). When `max_reviews` is not a multiple of 20 the next page can repeat a few
3581
+ # reviews - dedupe on `reviewId`.
3582
+ # @param hl [String] Language for Google's labels and the review translation
3583
+ # (`translatedText`), e.g. 'en', 'de'. The original text is always returned in `text`. API
3584
+ # default: en.
3585
+ # @param gl [String] Google country, ISO-2 lowercase, e.g. 'us'. API default: us.
3586
+ # @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
3587
+ # 'DE'). Reviews are the same from any country. API default: us.
3588
+ # Calls POST /maps/reviews.
3589
+ def maps_reviews(url: nil, place_id: nil, feature_id: nil, sort: nil, max_reviews: nil, next_page_token: nil, hl: nil, gl: nil, proxy_country: nil)
3590
+ post_json("/maps/reviews", {
3591
+ url: url,
3592
+ place_id: place_id,
3593
+ feature_id: feature_id,
3594
+ sort: sort,
3595
+ max_reviews: max_reviews,
3596
+ next_page_token: next_page_token,
3597
+ hl: hl,
3598
+ gl: gl,
3599
+ proxy_country: proxy_country,
3600
+ })
3601
+ end
3602
+
2641
3603
  # Scrape Google Hotels search results (prices, ratings, amenities).
2642
3604
  #
2643
3605
  # Runs a Google Hotels search for `q` and returns the properties as JSON: `name`, `type`
@@ -2928,6 +3890,31 @@ module ScrapeUnblocker
2928
3890
  })
2929
3891
  end
2930
3892
 
3893
+ # Ask ChatGPT and get its answer and cited sites.
3894
+ #
3895
+ # Asks ChatGPT (chatgpt.com, signed out) one question and returns its finished answer:
3896
+ # `answer` (plain text) and `answerMarkdown`, `citations` (the source pills ChatGPT attaches
3897
+ # to claims: `position`, `siteName`, `domain`, `moreSources` - how many further sources the
3898
+ # pill groups - and `citedText`, the answer text it backs), `links` (links written into the
3899
+ # answer: `position`, `title`, `url`, `domain`), `sources` (every site cited or linked,
3900
+ # once), `webSearch` (whether ChatGPT searched the web), `model` (null: signed-out ChatGPT
3901
+ # does not show it) and `conversationId`. Signed-out ChatGPT shows the full URL of a cited
3902
+ # page only on hover, so citations carry the site and domain, not the page URL. `country`
3903
+ # asks from that country. Answers take 15-60 s and vary between identical calls, as they do
3904
+ # for people. One unit per call; a 503 when ChatGPT capacity is busy is not billed.
3905
+ #
3906
+ # @param prompt [String] The question to ask ChatGPT, as a user would type it, e.g. 'best
3907
+ # CRM for small business' (max 2000 characters). Each call starts a new conversation.
3908
+ # @param country [String] Two-letter country code to ask from, e.g. US, GB, DE. ChatGPT
3909
+ # tailors local results to where the visitor is. Leave blank for any location.
3910
+ # Calls POST /ai/chatgpt.
3911
+ def chatgpt(prompt, country: nil)
3912
+ post_json("/ai/chatgpt", {
3913
+ prompt: prompt,
3914
+ country: country,
3915
+ })
3916
+ end
3917
+
2931
3918
  # Search Bing.
2932
3919
  #
2933
3920
  # Searches Bing for `keyword` in a real browser and returns the results page as JSON:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ScrapeUnblocker
4
- VERSION = "0.15.1"
4
+ VERSION = "0.17.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scrapeunblocker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ScrapeUnblocker