ЁЯОп рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдпреЛрдЧреНрдп, рдбрд┐рдЯреЗрдХреНрд╢рди-рдкреНрд░рддрд┐рд░реЛрдзреА рдХреНрд▓рд╛рдЙрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЬреЛ рд╕реНрд╡-рд╡рд┐рдХрд╕рд┐рдд Chromium рджреНрд╡рд╛рд░рд╛ рд╕рдВрдЪрд╛рд▓рд┐рдд рд╣реИ, рд╡реЗрдм рдХреНрд░реЙрд▓рд░ рдФрд░ рдПрдЖрдИ рдПрдЬреЗрдВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ред ЁЯСЙрдЕрднреА рдЖрдЬрд╝рдорд╛рдПрдВ
рд╡рд╛рдкрд╕ рдмреНрд▓реЙрдЧ рдкрд░

рдИрдЯреАрд╕реА рд╕реНрдХреНрд░реИрдкрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░реИрдкрд▓реЗрд╕ рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: рд╡реНрдпрд╛рдкрдХ рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ 2026 (рдиреЛрдб.рдЬреЗрдПрд╕)

James Thompson
James Thompson

Scraping and Proxy Management Expert

16-Apr-2026

рдореБрдЦреНрдп рдирд┐рд╖реНрдХрд░реНрд╖:

  • рд╕реНрдХреНрд░реЗрдкрд▓реЗрд╕ рд╕реНрдХреНрд░реЗрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдПрдЖрдИ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдПрдЯреАрд╕реА рдХреЗ DataDome рдПрдВрдЯреА-рдмреЙрдЯ рд▓реЗрдпрд░ рдХреЛ рдСрдЯреЛрдореЗрдЯреЗрдб рдлрд┐рдВрдЧрд░рдкреНрд░рд┐рдВрдЯрд┐рдВрдЧ, рд░реЗрдЬрд┐рдбреЗрдВрд╢рд┐рдпрд▓ рдкреНрд░реЙрдХреНрд╕реАрдЬрд╝ рдФрд░ CAPTCHA рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рд╛рде рд╕рд╛рдл рдХрд░рддрд╛ рд╣реИред
  • рдПрдХ CONFIG рдмреНрд▓реЙрдХ рд╕реЗ рдЪрд╛рд░ рдЦреЛрдЬ рдореЛрдб тАФ рдЙрддреНрдкрд╛рдж URL, рд╢реНрд░реЗрдгреА URL, рдХреАрд╡рд░реНрдб рдЦреЛрдЬ (рд╡реИрдХрд▓реНрдкрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рдХреЗ рд╕рд╛рде) рдФрд░ рджреБрдХрд╛рди URLред рдЗрдирдкреБрдЯ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░реЗрдВ, рд╡рд╣реА рдкрд╛рдЗрдкрд▓рд╛рдЗрдиред
  • рдЖрда рд╕рдВрд░рдЪрд┐рдд рдлрд╝рд┐рд▓реНрдЯрд░ (рдмрд┐рдХреНрд░реА рдкрд░, рдореБрдлреНрдд рд╢рд┐рдкрд┐рдВрдЧ, рдЕрдиреБрдХреВрд▓рди рдпреЛрдЧреНрдп, рд╢рд┐рдкреНрд╕-рдЯреВ, рдиреНрдпреВрдирддрдо/рдЕрдзрд┐рдХрддрдо рдореВрд▓реНрдп, рд╕реНрдерд┐рддрд┐, рдСрд░реНрдбрд░-рдмрд╛рдп) рдХрд┐рд╕реА рднреА рдЦреЛрдЬ рдореЛрдб рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЦреЛрдЬ рдпрд╛ рд╢реНрд░реЗрдгреА URLs рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
  • рдЖрдЙрдЯрдкреБрдЯ рд╕реНрдХреАрдорд╛ рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрдкрд╛рдж рдХреЗ рд▓рд┐рдП 30+ рдлрд╝реАрд▓реНрдб рдХреЛ рдХрд╡рд░ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ variations, breadcrumbs, listedDate, reviews[].photos рдФрд░ рдЕрджреНрд╡рд┐рддреАрдп рдорд░реНрдЪреЗрдВрдбрд╛рдЗрдЬрд┐рдВрдЧ рд╕рдВрдХреЗрдд (isBestseller, isStarSeller, isFreeShipping, inStock, favoritesCount, рдкреНрд░рддрд┐-рд░рд┐рд╡реНрдпреВ рдЙрдк-рд╕реНрдХреЛрд░) рд╢рд╛рдорд┐рд▓ рд╣реИрдВред
  • рдПрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд▓реВрдк (рдбрд┐рдлрд╝реЙрд▓реНрдЯ maxRetries: 10, рдмрдврд╝рддрд╛ рдмреИрдХрдСрдл 3 рд╕ тЖТ 47 рд╕) рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЗ рдмреАрдЪ рдПрдХ рддрд╛рдЬрд╝рд╛ рд╕рддреНрд░ рдФрд░ рд░реЗрдЬрд╝реАрдбреЗрдВрд╢рд┐рдпрд▓ рдЖрдИрдкреА рдореЗрдВ рдШреВрдорддрд╛ рд╣реИ, рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЕрд╕реНрдерд╛рдпреА 403s рдХреЛ рдЕрд╡рд╢реЛрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред

рдкрд░рд┐рдЪрдп: рдПрдВрдЯреА-рдбрд┐рдЯреЗрдХреНрд╢рди рдХреНрд▓рд╛рдЙрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рд╕рд╛рде рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдПрдЯреАрд╕реА рдХреЛ рд╕реНрдХреНрд░реЗрдк рдХрд░рдирд╛

рдПрдЯреАрд╕реА рдИ-рдХреЙрдорд░реНрд╕ рдЗрдВрдЯреЗрд▓рд┐рдЬреЗрдВрд╕ рдХреЗ рд▓рд┐рдП рд╕реЛрдиреЗ рдХреА рдЦрд╛рди рд╣реИ: рджреБрдХрд╛рди рдорд╛рд▓рд┐рдХреЛрдВ рдХреЗ рд▓рд┐рдП рддреБрд▓рдирд╛рддреНрдордХ рд╡рд┐рдХреНрд░реЗрддрд╛ рдореВрд▓реНрдп, рдПрдордПрд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рднрд╛рд╡рдирд╛-рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЙрд░реНрдкреЛрд░рд╛ рдФрд░ рдбреНрд░реЙрдкрд╢рд┐рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдирд┐рдЪреЗ рдХреА рдЦреЛрдЬ рд╕рднреА рд╡рд╣реА рд╕реВрдЪреАрдХрд░рдг рдкреГрд╖реНрдареЛрдВ рд╕реЗ рдирд┐рдХрд▓рддреА рд╣реИред рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдПрдЯреАрд╕реА рдПрдкреАрдЖрдИ рдореЗрдВ рд╕реАрдорд┐рдд рдкрд╣реБрдВрдЪ рд╣реИ рдФрд░ рдПрдХ рд▓рдВрдмреА рд╕реНрд╡реАрдХреГрддрд┐ рдЪрдХреНрд░ рд╣реЛрддреА рд╣реИ, рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдбреЗрдЯрд╛ рд░рд┐рд╕реЗрд▓рд░реНрд╕ рдорд╣рдВрдЧреЗ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рдХрд╕реНрдЯрдо рд╕реНрдХреНрд░реЗрдкрд░ рдХреЛ DataDome рдФрд░ рдПрдЯреАрд╕реА рдХреА рдлреНрд░рдВрдЯреЗрдВрдб рдкрд░ рдмрд╛рд░-рдмрд╛рд░ CSS рдХреНрд▓рд╛рд╕-рдирд╛рдо рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рд▓рдЧрд╛рддрд╛рд░ рд░рдЦрд░рдЦрд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

рдпрд╣ рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ рдПрдХ рдПрдХрд▓ TypeScript рдлрд╝рд╛рдЗрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓рддреА рд╣реИ рдЬрд┐рд╕реЗ рд╕реНрдХреНрд░реЗрдкрд▓реЗрд╕ рд╕реНрдХреНрд░реЗрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдкрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдЬреЛ рд╣рд░ рдХрдард┐рди рднрд╛рдЧ рдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ: рдПрдВрдЯреА-рдбрд┐рдЯреЗрдХреНрд╢рди рдХреНрд▓рд╛рдЙрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░, рд░реЗрдЬрд╝реАрдбреЗрдВрд╢рд┐рдпрд▓ рдкреНрд░реЙрдХреНрд╕реАрдЬрд╝, рд╕рдореАрдХреНрд╖рд╛рдУрдВ рдФрд░ рджреБрдХрд╛рди рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐-рдЙрддреНрдкрд╛рдж рд╕рдореГрджреНрдзрд┐ рдФрд░ рдмрд╣реБ-рдкреНрд░рд╢реНрди рд╡рд┐рд╕реНрддрд╛рд░ рддрдХрдиреАрдХ рдЬреЛ рдХрд┐ рдПрдХрд▓ рдореВрд▓ рдХреАрд╡рд░реНрдб рд╕реЗ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреА рд╣реИ рдЬреЛ рдПрдЯреАрд╕реА рдХреЗ рдкреНрд░рддрд┐-рдЦреЛрдЬ рд╕реАрдорд╛ рд╕рд╛рдорд╛рдиреНрдпрддрдГ рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рд╡рд╣реА рд╕реНрдХреНрд░реЗрдкрд░ рдЪрд╛рд░ рд╕реНрд╡рддрдВрддреНрд░ рдЦреЛрдЬ рдореЛрдб рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ - рдЗрд╕реЗ рдПрдХ рдЙрддреНрдкрд╛рдж URL, рдПрдХ рд╢реНрд░реЗрдгреА URL, рдПрдХ рдХреАрд╡рд░реНрдб рдЦреЛрдЬ рдпрд╛ рдПрдХ рджреБрдХрд╛рди URL рджреЗрдВ - рдФрд░ рд╣рд░ рдЖрдЙрдЯрдкреБрдЯ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╡рд╣реА рд╕рдореГрджреНрдз 30-рдлреАрд▓реНрдб рд╕реНрдХреАрдорд╛ рд╣реЛрддреА рд╣реИ рдЪрд╛рд╣реЗ рд╕реВрдЪреАрдХрд░рдг рдХреИрд╕реЗ рднреА рдЦреЛрдЬрд╛ рдЧрдпрд╛ рд╣реЛред


рдЖрдк рдЗрд╕рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

рдПрдЯреАрд╕реА рдбреЗрдЯрд╛ рдПрдХ рдмрд╣реБрдкрд░рдХрд╛рд░реА рд╕рдВрдкрддреНрддрд┐ рд╣реИ, рдЬреЛ рдЙрддреНрдкрд╛рдж рдЕрдиреБрд╕рдВрдзрд╛рди рд╕реЗ рд▓реЗрдХрд░ рдЙрдиреНрдирдд рдПрдЖрдИ рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕ рддрдХ рдЙрдЪреНрдЪ-рдкреНрд░рднрд╛рд╡ рд╡рд╛рдгрд┐рдЬреНрдпрд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рд╕рдВрдЪрд╛рд▓рд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдкрд╛рдВрдЪ рд╡рд╛рд╕реНрддрд╡рд┐рдХ-world рд╡рд╛рдгрд┐рдЬреНрдпрд┐рдХ рдЙрдкрдпреЛрдЧ рджрд┐рдП рдЧрдП рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рд╕рдорд╛рди рдХреЛрдбрдмреЗрд╕ рд╕реЗ рдкреВрд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЕрдХреНрд╕рд░ рдХреЗрд╡рд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреЗ рд╕рд╛рде:

  1. рдбреНрд░реЙрдкрд╢рд┐рдкрд┐рдВрдЧ рдЕрдиреБрд╕рдВрдзрд╛рди рдФрд░ рдЙрддреНрдкрд╛рдж рдЦреЛрдЬрдирд╛ тАФ рдХреАрд╡рд░реНрдб-рдЦреЛрдЬ рдореЛрдбред рд╕реНрдХреНрд░реЗрдкрд░ рдХреЛ "рдореИрдХреНрд░реЗрдореЗ рдкреНрд▓рд╛рдВрдЯ рд╣реИрдВрдЧрд░" рдкрд░ рдЪрд▓рд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ expandStrategy: "keywords" рд╣реЛ ["boho", "modern", "minimalist"] рдореЗрдВ, maxProducts: 200 рд╕реЗрдЯ рдХрд░реЗрдВ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ favoritesCount ├Ч rating рджреНрд╡рд╛рд░рд╛ рд░реИрдВрдХ рдХрд░реЗрдВред рдЙрди рджреБрдХрд╛рдиреЛрдВ рдХреЛ рдЫрд╛рдиреЗрдВ рдЬрд╣рд╛рдВ isStarSeller: true рд╣реИ рдФрд░ favoritesCount рдХрд╛рдлреА рдЕрдзрд┐рдХ рд╣реИ тАФ рд╡реЗ рдЖрдкрдХреЗ рдбреНрд░реЙрдкрд╢рд┐рдкрд┐рдВрдЧ рдЙрдореНрдореАрджрд╡рд╛рд░ рд╣реИрдВред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк CSV рдХреЛ рд╢реЙрдкрд┐рдлрд╛рдИ рдпрд╛ рдПрдХ рдирд┐рдЬреА рд╕рдкреНрд▓рд╛рдпрд░ рд╕реВрдЪреА рдореЗрдВ рдбрд╛рд▓реЗрдВред рдпрд╣ рдПрдЯреАрд╕реА рдХреЛ рд╕реНрдХреНрд░реЗрдк рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рдХрд╛рд░рдг рд╣реИ рдФрд░ рд░рд╛рдЬрд╕реНрд╡ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рддреЗрдЬрд╝ рд╣реИред
  2. рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд┐рдпреЛрдВ рдХреА рдореВрд▓реНрдп рдирд┐рдЧрд░рд╛рдиреА тАФ рдЙрддреНрдкрд╛рдж-URL (рдкреНрд░рддреНрдпрдХреНрд╖-URL) рдореЛрдбред startUrls рдореЗрдВ рдкреНрд░рддрд┐рдпреЛрдЧреА рд╕реВрдЪреА URLs рдХреА рдПрдХ рд╕реВрдЪреА рд░рдЦреЗрдВ рдФрд░ рд╕реНрдХреНрд░реЗрдкрд░ рдХреЛ рд░рд╛рдд рдореЗрдВ рдЪрд▓рд╛рдПрдВред рдкреНрд░рддреНрдпреЗрдХ JSON рд╕реНрдиреИрдкрд╢реЙрдЯ рдХреЛ рдЙрд╕рдХреЗ scrapedAt рдЯрд╛рдЗрдорд╕реНрдЯрд╛рдореНрдк рдХреЗ рд╕рд╛рде рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░реЗрдВ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд░рди рдХреЗ рдмреАрдЪ price, originalPrice, discountPercent рдФрд░ inStock рдХрд╛ рдЕрдВрддрд░ рдирд┐рдХрд╛рд▓реЗрдВред рдореВрд▓реНрдп рдореЗрдВ 10% рд╕реЗ рдЕрдзрд┐рдХ рдЧрд┐рд░рд╛рд╡рдЯ? рд╕реНрд▓реИрдХ рдЕрд▓рд░реНрдЯред inStock true рд╕реЗ false рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реИ? рдЗрд╕реЗ рдПрдХ рдЖрдкреВрд░реНрддрд┐ рд╕рдВрдХреЗрдд рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВред рдЗрд╕ рддрд░реАрдХреЗ рд╕реЗ рдЖрдк рдЬреЛ рдкреВрд░реНрдг рдореВрд▓реНрдп рдЗрддрд┐рд╣рд╛рд╕ рдмрдирд╛рддреЗ рд╣реИрдВ рд╡рд╣ рд╣рд░ рдкреНрд░рддрд┐рдпреЛрдЧреА-рдЗрдВрдЯреЗрд▓ рдбреИрд╢рдмреЛрд░реНрдб рдХрд╛ рдореБрдЦреНрдп рдЖрдзрд╛рд░ рд╣реИред
  3. рдХреАрд╡рд░реНрдб рдФрд░ рдкреНрд░рд╡реГрддреНрддрд┐ рдЕрдиреБрд╕рдВрдзрд╛рди тАФ рдлрд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рд╢реНрд░реЗрдгреА-URL рдореЛрдбред categoryUrl рдХреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдПрдЯреАрд╕реА рд╢реНрд░реЗрдгреА рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░реЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП /c/bags-and-purses/wallets-and-money-clips/wallets), рдлрд╝рд┐рд▓реНрдЯрд░ рд╕рдВрдпреЛрдЬрдиреЛрдВ (filters.onSale: true, filters.condition: "new", filters.orderBy: "date_desc") рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдХреБрдЫ рд╕реМ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ tags рдФрд░ materials рдХреЛ рдЦреАрдВрдЪреЗрдВ, рдЙрдирдХреА рдЖрд╡реГрддреНрддрд┐ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ рдФрд░ рдЙрд╕ рдЯреИрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдкрд░ favoritesCount рдХреЗ рдпреЛрдЧ рджреНрд╡рд╛рд░рд╛ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВред рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдмрдирд╛рдП рдЧрдП рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ рджрд┐рдЦрдиреЗ рд╡рд╛рд▓реЗ рдЯреИрдЧ рд▓реЗрдХрд┐рди рдкреБрд░рд╛рдиреЗ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ рдирд╣реАрдВ рд╣реИрдВ рдЖрдкрдХреЗ рдЙрднрд░рддреЗ рдЙрдк-рдирд┐рдЪреЗ рд╣реИрдВред
  4. рдПрдбрд╡рд╛рдВрд╕ рдорд╛рд░реНрдХреЗрдЯ рд░рд┐рд╕рд░реНрдЪ рдФрд░ рдПрдордПрд▓ рдХреЗ рд▓рд┐рдП рд╕рдореАрдХреНрд╖рд╛ рд╕рдВрдЧреНрд░рд╣рдг тАФ рдХреАрд╡рд░реНрдб рдпрд╛ рд╢реНрд░реЗрдгреА рдореЛрдбред рд╣рдЬрд╛рд░реЛрдВ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ reviews[] рдХреЛ рд╕реНрдХреНрд░реЗрдк рдХрд░реЗрдВ (рд╣реИрдВрдбрдореЗрдб рдореЛрдордмрддреНрддрд┐рдпрд╛рдБ, рдЬреИрд╕реЗ рдХрд┐, рдпрд╛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЧрд╣рдиреЗ), reviews[].text рдХреЛ рдПрдХ рднрд╛рд╡рдирд╛ рд╡рд░реНрдЧреАрдХрд░рдгрдХрд░реНрддрд╛ рдореЗрдВ рдлреАрдб рдХрд░реЗрдВ рдФрд░ рдЬрдм рд╡реЗ рдореМрдЬреВрдж рд╣реЛрдВ рддреЛ itemQuality / shipping / customerService рдЙрдк-рд░реЗрдЯрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕реБрдкрд░рд╡рд╛рдЗрдЬреНрдб рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд▓реЗрдмрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд░реЗрдВред рдкреНрд░рддрд┐-рд░рд┐рд╡реНрдпреВ рдЫрд╡рд┐рдпрд╛рдВ (reviews[].photos[]) рдЖрдкрдХреЛ рдПрдХ рд╕рдорд╛рди рдЫрд╡рд┐ рдХреЙрд░реНрдкрд╕ рджреЗрддреА рд╣реИрдВ рдпрджрд┐ рдЖрдкрдХреЛ рджреГрд╢реНрдп рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдбреЗрдЯрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛред
  5. рджреБрдХрд╛рди рдкреНрд░рджрд░реНрд╢рди рдорд╛рдирдХреАрдХрд░рдг тАФ рджреБрдХрд╛рди-рдпреВрдЖрд░рдПрд▓ рдореЛрдбред shopUrl рдХреЛ рдПрдХ рдкреНрд░рддрд┐рдпреЛрдЧреА рдХреА рджреБрдХрд╛рди рдкреГрд╖реНрда рдкрд░ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, https://www.etsy.com/shop/TexasValleyLeather), maxPagesPerQuery: 5 рд╕реЗрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдЙрдирдХрд╛ рдкреВрд░рд╛ рдХреИрдЯрд▓реЙрдЧ рдкреГрд╖реНрдардмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдФрд░ рд╕реНрдХреНрд░реИрдкрд░ рдЙрд╕ рджреБрдХрд╛рди рджреНрд╡рд╛рд░рд╛ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдмреЗрдЪреА рдЧрдИ рд╣рд░ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗред shop.totalSales, shop.openedYear, rating, reviewsCount рдФрд░ isStarSeller рджреНрд╡рд╛рд░рд╛ рдПрдХ рд╣реА рд╢реНрд░реЗрдгреА рдореЗрдВ рд╡рд┐рдХреНрд░реЗрддрд╛рдУрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВред

рдХреНрдпреЛрдВ Scrapeless

Scrapeless Scraping Browser рдЖрдкрдХреЗ рд╕реНрдХреНрд░реИрдкрд░ рдХреЛ рдПрдХ рдЙрддреНрдкрд╛рджрди-рдЧреНрд░реЗрдб рдХреНрд▓рд╛рдЙрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдИрдЯреНрд╕реА рдХреЗ DataDome рдЬрд╛рдВрдЪреЛрдВ рдХреЛ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рддреИрдпрд╛рд░реА рдХреЗ рдкрд╛рд╕ рдХрд░ рджреЗрддрд╛ рд╣реИ тАФ рдХреЛрдИ рд╕реНрдЯреЗрд▓реНрде рдкреНрд▓рдЧрдЗрдиреНрд╕ рдирд╣реАрдВ, рдХреЛрдИ рдлрд╝рд┐рдВрдЧрд░рдкреНрд░рд┐рдВрдЯ рд╕рдорд╛рдпреЛрдЬрди рдирд╣реАрдВ, рд░рдЦрд░рдЦрд╛рд╡ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдкреНрд░реЙрдХреНрд╕реА рд░реЛрдЯреЗрд╢рди рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдирд╣реАрдВред Puppeteer рдпрд╛ Playwright рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХ WebSocket рдПрдВрдбрдкреЙрдЗрдВрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ рдФрд░ рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдБрдЪрд╛ рдПрдВрдЯреА-рдмреЙрдЯ рдкрд░рдд рдХреЛ рд╕рдВрднрд╛рд▓реЗред

рдмрд┐рдирд╛ рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рд╕реЗрдЯрд┐рдВрдЧ рдХреЗ рдЖрдкрдХреЛ рдорд┐рд▓рддрд╛ рд╣реИ:

  • рдПрдВрдЯреА-рдбрд┐рдЯреЗрдХреНрд╢рди рдлрд╝рд┐рдВрдЧрд░рдкреНрд░рд┐рдВрдЯрд┐рдВрдЧ рдЬреЛ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рд╕рддреНрд░реЛрдВ рдореЗрдВ рдордЬрдмреВрдд рд╣реЛрддреА рд╣реИ
  • рдЕрд╡рд╛рд╕реАрдп рдкреНрд░реЙрдХреНрд╕реАрдЬрд╝ 195+ рджреЗрд╢реЛрдВ рдореЗрдВ (рдЕрд▓рдЧ рд╕реЗ US, GB, DE рдореВрд▓реНрдп рдирд┐рд░реНрдзрд╛рд░рдг)
  • рд╕реНрд╡рдЪрд╛рд▓рд┐рдд CAPTCHA рд╣рд▓ рдХрд░рдирд╛ рдЬрдм рдИрдЯреНрд╕реА рдПрдХ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИ
  • рд╕рддреНрд░ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдмрд╛рдж рдореЗрдВ рдЪрдпрдирдХрд░реНрддрд╛ рдХреА рдЧрд┐рд░рд╛рд╡рдЯ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
  • WebSocket рдПрдВрдбрдкреЙрдЗрдВрдЯ рдЬреЛ Puppeteer рдФрд░ Playwright рдЬреИрд╕реЗ CDP-рдЖрдзрд╛рд░рд┐рдд рдврд╛рдВрдЪреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВ тАФ рд╕реАрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ SDK рдирд╣реАрдВ
  • AI рдПрдЬреЗрдВрдЯ рддреИрдпрд╛рд░: Scrapeless MCP Server рдЬреИрд╕реЗ рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдирд┐рд░реНрдмрд╛рдз рд░реВрдк рд╕реЗ рдПрдХреАрдХреГрдд рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдЖрдкрдХреЗ AI рдПрдЬреЗрдВрдЯреЛрдВ рдХреЛ рд╡реЗрдм рдкрд░ "рдЖрдВрдЦреЗрдВ рдФрд░ рд╣рд╛рде" рдорд┐рд▓ рд╕рдХреЗрдВред

рдПрдХрддрд╛ рдХреЗрд╡рд▓ рдПрдХ рдкрдВрдХреНрддрд┐ рдХрд╛ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИ: puppeteer.connect() рдХреЛ рдПрдХ Scrapeless рдпреВрдЖрд░рдПрд▓ рдкрд░ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВ, рди рдХрд┐ рд╕реНрдерд╛рдиреАрдп рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдкрд░ред рдмрд╛рдХреА рдХреЛрдб рдмрд┐рд▓реНрдХреБрд▓ рд╡реИрд╕рд╛ рд╣реА рд░рд╣рддрд╛ рд╣реИ тАФ рдорд╛рдирдХ CDP, рдорд╛рдирдХ рдЪрдпрдирдХрд░реНрддрд╛, рдорд╛рдирдХ рдХрд╛рд░реНрдпрдкреНрд░рд╡рд╛рд╣ред рд╕рднреА DataDome рдЬрдЯрд┐рд▓рддрд╛ рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб рдкрд░ рд░рд╣рддреА рд╣реИ, рдЖрдкрдХреЗ рдХреЛрдбрдмреЗрд╕ рд╕реЗ рдмрд╛рд╣рд░ред

рдлреНрд░реА рдкреНрд▓рд╛рди рдкрд░ рдЕрдкрдирд╛ API рдХреБрдВрдЬреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ app.scrapeless.com.


рдкреВрд░реНрд╡рд╛рдкреЗрдХреНрд╖рд╛рдПрдБ рдФрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ

Node.js 18 рдпрд╛ рдирдП рд╕рдВрд╕реНрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред Scrapeless API рдХреБрдВрдЬреА (рдлреНрд░реА рдЯрд┐рдпрд░ рдЗрд╕ рдЧрд╛рдЗрдб рдореЗрдВ рд╕рдм рдХреБрдЫ рдХрд╡рд░ рдХрд░рддрд╛ рд╣реИ)ред рдХреБрдЫ Puppeteer рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рд╕рд╣рд╛рдпрдХ рд╣реИред рдХреЛрдИ рд╕реНрдерд╛рдиреАрдп рдХреНрд░реЛрдо рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ тАФ рдмреНрд░рд╛рдЙрдЬрд╝рд░ Scrapeless рдХреЗ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рдЪрд▓рддрд╛ рд╣реИред

bash Copy
mkdir etsy-scrapeless-browserless && cd etsy-scrapeless-browserless
npm init -y
npm install puppeteer-core dotenv cheerio
npm install -D tsx typescript @types/node @types/cheerio

puppeteer-core рдХреНрд▓рд╛рдЙрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдЪрд▓рд╛рддрд╛ рд╣реИ; cheerio рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдкрд░ рд░реЗрдВрдбрд░ рдХреА рдЧрдИ HTML рдХреЛ рдПрдХ рдмрд╛рд░ рдкреГрд╖реНрда рд▓реЛрдб рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИред рдмреНрд░рд╛рдЙрдЬрд╝рд░-рд╕рд╛рдЗрдб рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЛ Node-рд╕рд╛рдЗрдб рдкрд╛рд░реНрд╕рд┐рдВрдЧ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдирд╛ рд╣рд░ рдирд┐рд╖реНрдХ extractor рдХреЛ рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рд╣реБрдЖ рдФрд░ рд╕рд╣реЗрдЬреЗ рдЧрдП HTML рд╕рдВрдпреЛрдЬрдиреЛрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рдпреВрдирд┐рдЯ-рдЯреЗрд╕реНрдЯ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИред

.env:

Copy
SCRAPELESS_API_KEY=your_key_here

рдЪрд░рдг 1 тАФ рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ

рд╕рдВрдкреВрд░реНрдг рд╕реНрдХреНрд░реИрдкрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдиреЗрдХреНрд╢рди рд╕рд╣рд╛рдпрдХред рдЯреЛрдХрди, рджреЗрд╢ рдФрд░ TTL рдХреЗ рд╕рд╛рде рдПрдХ WSS URL рдмрдирд╛рдПрдБ, рдлрд┐рд░ рдЗрд╕реЗ puppeteer.connect рдХреЛ рджреЗрдВред

ts Copy
import "dotenv/config";
import puppeteer, { type Browser, type Page } from "puppeteer-core";
import * as cheerio from "cheerio";

// рд╕рд╣рд╛рдпрдХ тАФ рдкреГрд╖реНрда рдХреА рдкреВрд░реА HTML рдХреЛ рдЦреАрдВрдЪреЗрдВ рдФрд░ рдЗрд╕реЗ cheerio рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд░реЗрдВред рдХреЙрд▓рд░
// рдХреЛ рдХрд┐рд╕реА рднреА рдмреНрд░рд╛рдЙрдЬрд╝рд░-рд╕рд╛рдЗрдб рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ / waitForFunction рдХреЛ рдкрд╣рд▓реЗ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
// рддрд╛рдХрд┐ рд╕реБрд╕реНрдд рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдкрд╛рдиреА рдорд┐рд▓ рд╕рдХреЗред рдЙрд╕рдХреЗ рдмрд╛рдж, рдкрд╛рд░реНрд╕рд┐рдВрдЧ Node рдореЗрдВ рд░рд╣рддреА рд╣реИ:
// рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рд╣реБрдЖ, рдХреЛрдИ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдлреЙрд░реНрдореЗрдЯреЗрдб рдореВрд▓реНрдп рдирд╣реАрдВ, рдХреЛрдИ `__name` tsx рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ, рд╕рд╣реЗрдЬреЗ рдЧрдП
// HTML рд╕рдВрдпреЛрдЬрдиреЛрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рдпреВрдирд┐рдЯ-рдЯреЗрд╕реНрдЯ рдХрд░рдирд╛ рдЖрд╕рд╛рдиред
async function parseWithCheerio(page: Page): Promise<cheerio.CheerioAPI> {
  const html = await page.content();
  return cheerio.load(html);
}

type ScraperInput = {
  proxyCountry: string;   // рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП "US", "GB", "DE"
  sessionTTL: number;     // рд╕реЗрдХрдВрдб, 60тАУ900 рдХреА рдЕрдиреБрдорддрд┐; 600 рдПрдХ рд╕реБрд░рдХреНрд╖рд┐рдд рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реИ
};

function connectionURL(sessionName: string, cfg: ScraperInput): string {
  const token = process.env.SCRAPELESS_API_KEY;
  if (!token) throw new Error("SCRAPELESS_API_KEY is not set in .env");
  // Scrapeless рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдПрдХ рд╕рддреНрд░ рдХреЗ рдЬреАрд╡рдирдХрд╛рд▓ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╛рд╕реАрдп IP рдХреЛ рдкрд┐рди рдХрд░рддрд╛ рд╣реИ,
  // рдЗрд╕рд▓рд┐рдП рдПрдХ puppeteer.connect рдХреЗ рднреАрддрд░ рд╣рд░ рдкреГрд╖реНрда рдиреЗрд╡рд┐рдЧреЗрд╢рди рдЙрд╕реА рдЖрдЙрдЯрдмрд╛рдЙрдВрдб IP рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред 
  // рдПрдХ рдирдИ рд╕рддреНрд░ (рдирдИ рдХрдиреЗрдХреНрд╢рди) рдЦреЛрд▓рдиреЗ рд╕реЗ рдПрдХ рдирдпрд╛ IP рд░реЛрд▓ рд╣реЛрддрд╛ рд╣реИ,
  // рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд░рд┐рдЯреНрд░реА рд▓реВрдк рдХреЛ рдПрдХ рдзреНрд╡рдЬрд╛рдВрдХрд┐рдд IP рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рд░реВрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
  const qs = new URLSearchParams({
    token,
    proxyCountry: cfg.proxyCountry,
    sessionTTL: String(cfg.sessionTTL),
    sessionName,
    sessionRecording: "true",
    // Scrapeless рдХреЛ рдкреВрд░реНрдг рдбреЗрд╕реНрдХрдЯреЙрдк рдлрд╝рд┐рдВрдЧрд░рдкреНрд░рд┐рдВрдЯ рдХреЛ рд╕реНрд╡рд╛рдорд┐рддреНрд╡ рдореЗрдВ рд▓реЗрдиреЗ рджреЗрдВ тАФ UA, рд╕реНрдХреНрд░реАрди, рд╕рдордп рдХреНрд╖реЗрддреНрд░
    // рдФрд░ рднрд╛рд╖рд╛ред рдореИрдиреБрдЕрд▓ рд╕реЗрдЯViewport / setUserAgent рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
    fingerprint: JSON.stringify({ platform: "Windows" }),
  });
  return `wss://browser.scrapeless.com/api/v2/browser?${qs.toString()}`;
}

async function openBrowser(sessionName: string, cfg: ScraperInput): Promise<Browser> {
  return puppeteer.connect({
    browserWSEndpoint: connectionURL(sessionName, cfg),
    defaultViewport: null,
  });
}

рдпрд╣ рдкреВрд░реА Scrapeless-рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рддрд╣ рдХреНрд╖реЗрддреНрд░ рд╣реИ - рдПрдХ WSS URL рдФрд░ рдПрдХ puppeteer.connectред рдЗрд╕реЗ рд╕реНрдХреЗрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╛рдд рд╣реИ: рдПрдХрд▓ puppeteer.connect рд╕рддреНрд░ рдЕрдкрдиреЗ рдЬреАрд╡рдирдХрд╛рд▓ рдХреЗ рд▓рд┐рдП рдПрдХрд▓ рдЖрд╡рд╛рд╕реАрдп рдЖрдИрдкреА рд╕реЗ рдмрдВрдзрд╛ рд╣реЛрддрд╛ рд╣реИ (рдЗрд╕реЗ рдПрдХ рд╣реА рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╣реИрдВрдбрд▓ рдкрд░ api.ipify.org рдХреЛ рддреАрди рдмрд╛рд░ рд╣рд┐рдЯ рдХрд░рдХреЗ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ - рдкреНрд░рддреНрдпреЗрдХ рдмрд╛рд░ рд╡рд╣реА рдЖрдИрдкреА)ред рдПрдХ рддрд╛рдЬрд╝рд╛ рд╕рддреНрд░ рдЦреЛрд▓рдиреЗ рд╕реЗ рдПрдХ рдирдпрд╛ рдЖрдИрдкреА рдорд┐рд▓рддрд╛ рд╣реИред рдпрд╣реА рдЖрдзрд╛рд░ рд╣реИ рдЬрд┐рд╕ рдкрд░ рдЪрд░рдг 8 рдореЗрдВ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд▓реВрдк рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ - рдпрджрд┐ рдЗрд╕ рд╕рддреНрд░ рдХреЗ рдЖрдИрдкреА рдкрд░ рдХреЛрдИ рдЕрдиреБрд░реЛрдз рдЕрд╡рд░реБрджреНрдз рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рд╕рддреНрд░ рдмрдВрдж рдХрд░ рджреЗрддреЗ рд╣реИрдВ, рдПрдХ рдирдпрд╛ рдЦреЛрд▓рддреЗ рд╣реИрдВ, рдПрдХ рдирдпрд╛ рдЖрдИрдкреА рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рд╕реЗ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред

Scrapeless Scraping Browser рдХрдиреЗрдХреНрд╢рди рд╕реНрддрд░ рдкрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдлрд┐рдВрдЧрд░рдкреНрд░рд┐рдВрдЯ рдХрд╛ рд╕реНрд╡рд╛рдорд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИ - UA, рд╕реНрдХреНрд░реАрди рдЖрдХрд╛рд░, рдЯрд╛рдЗрдордЬреЛрди рдФрд░ рднрд╛рд╖рд╛ рд╕рднреА WSS URL рдкрд░ fingerprint: { platform: "Windows" } рдХреНрд╡реЗрд░реА рдкреИрд░рд╛рдореАрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдореИрдиреБрдЕрд▓ setViewport рдпрд╛ setUserAgent рдХреЙрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЪрд░рдг 8 рдореЗрдВ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд▓реВрдк рд╢реАрд░реНрд╖ рдкрд░ рдЕрд╕реНрдерд╛рдпреА рдЕрд╡рд░реЛрдзреЛрдВ рдХреЛ рдЕрд╡рд╢реЛрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред

рд╕рд┐рд░реНрдл рдмреНрд░рд╛рдЙрдЬрд╝рд░-рд╕рд╛рдЗрдб рд╕реЗрдЯрдЕрдк рдПрдХ-рд▓рд╛рдЗрди tsx рд╕рдВрдЧрддрддрд╛ рд╕реНрдЯрдм рд╣реИ:

ts Copy
async function prepPage(page: Page): Promise<void> {
  // рд╕реНрдЯрдм tsx-рдЗрдВрдЬреЗрдХреНрдЯреЗрдб __name рд╕рд╣рд╛рдпрдХ рддрд╛рдХрд┐ page.evaluate рдлрд╝рдВрдХреНрд╢рди рдХреА рдмреЛрдбреА
  // рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рдВрджрд░реНрдн рдХреЗ рднреАрддрд░ "__name is not defined" рдХреЗ рд╕рд╛рде рдХреНрд░реИрд╢ рди рд╣реЛред
  await page.evaluateOnNewDocument(
    "(function(){ globalThis.__name = function(f){ return f; }; })()",
  );
}

рд╕рддреНрд░ рдХреА рдЧрд░реНрдореА

рдЦреЛрдЬ рдпрд╛ рджреБрдХрд╛рди рдкреГрд╖реНрда рдкрд░ рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╕реНрдХреНрд░реИрдкрд░ рдПрдХ рдмрд╛рд░ Etsy рд╣реЛрдордкреЗрдЬ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдПрдХ рд╡реИрдз рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рддреНрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдЗрд╕ рдХрджрдо рдХреЗ рдмрд┐рдирд╛, /search рдФрд░ /shop рдЕрдВрдд рдмрд┐рдВрджреБ рдПрдХ рдардВрдбреЗ рд╕рддреНрд░ рдкрд░ 403 рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ:

ts Copy
const ETSY_COUNTRY_PATHS: Record<string, string> = {
  US: "", DE: "de/", GB: "uk/", FR: "fr/", IT: "it/", ES: "es/",
  NL: "nl/", CA: "ca/", AU: "au/", JP: "jp/", IN: "in/",
};

async function warmUpSession(page: Page, proxyCountry: string): Promise<void> {
  const path = ETSY_COUNTRY_PATHS[proxyCountry] ?? "";
  try {
    await page.goto(`https://www.etsy.com/${path}`, {
      waitUntil: "domcontentloaded",
      timeout: 30000,
    });
  } catch {
    // рдЯрд╛рдЗрдордЖрдЙрдЯ рдпрд╛ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдареАрдХ рд╣реИ - рддрдм рддрдХ рдХреБрдХреАрдЬрд╝ рд╕реЗрдЯ рд╣реЛ рдЬрд╛рддреА рд╣реИрдВред
  }
  await dismissEtsyConsent(page);
  await delay(1500);
}

рджреЗрд╢-рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрде рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ: рдПрдХ DE рдкреНрд░реЙрдХреНрд╕реА рдЬрдм etsy.com/de/ рдкрд░ рдЬрд╛рддрд╛ рд╣реИ рддреЛ 200 рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдФрд░ рд╕рд╣реА рдХреНрд╖реЗрддреНрд░реАрдп рд╕рддреНрд░ рдХреБрдХреАрдЬрд╝ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдЬрдмрдХрд┐ etsy.com/ рдкрд░ DE рдкреНрд░реЙрдХреНрд╕реА 403 рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдФрд░ рд╕рддреНрд░ рд▓реЙрдХ рд░рд╣рддрд╛ рд╣реИред рдпреВрдПрд╕ (64 рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ), DE (60 рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ) рдФрд░ GB (61 рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ) рдореЗрдВ рд╕рддреНрдпрд╛рдкрд┐рдд - рддреАрдиреЛрдВ рдкрд╣рд▓реЗ рдкреНрд░рдпрд╛рд╕ рдореЗрдВ рдЦреЛрдЬ рдкрд░рд┐рдгрд╛рдо рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ рдЬрдм рд╡реЙрд░реНрдордЕрдк рдкреНрд░реЙрдХреНрд╕реА рджреЗрд╢ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрддрд╛ рд╣реИред рд╕реНрдХреНрд░реИрдкрд░ рдкрд╣рд▓реЗ collectSearchResults рдХреЙрд▓ рд╕реЗ рдкрд╣рд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рддреНрд░ рдХреЗ рд▓рд┐рдП warmUpSession рдХреЛ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред


рдЪрд░рдг 2 - рдЪрд╛рд░ рдЦреЛрдЬ рдореЛрдб

рд╕реНрдХреНрд░реИрдкрд░ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЦреЛрдЬрдиреЗ рдХреЗ рдЪрд╛рд░ рд╕реНрд╡рддрдВрддреНрд░ рддрд░реАрдХреЗ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рд╕рднреА рдПрдХ рд╣реА CONFIG рдмреНрд▓реЙрдХ рдкрд░ред рдЙрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЛ рдЪреБрдиреЗрдВ рдЬреЛ рдЕрдкрд╕реНрдЯреНрд░реАрдо рдкреНрд░рд╢реНрди рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ рдФрд░ startUrls, shopUrl, categoryUrl, рдпрд╛ searchQuery рдореЗрдВ рд╕реЗ рдПрдХ рд╣реА рд╕реЗрдЯ рдХрд░реЗрдВред рдпрджрд┐ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╣реИ shopUrl тЖТ categoryUrl тЖТ searchQuery тЖТ startUrlsред

рдЙрддреНрдкрд╛рдж URL рдореЛрдб (рдкреНрд░рддреНрдпрдХреНрд╖-URL) - рдЬреНрдЮрд╛рдд рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ, рд░рд╛рдд рдХреА рдлрд┐рд░ рд╕реЗ рдЦреАрдВрдЪрдирд╛, рдкреНрд░рддрд┐рдпреЛрдЧреА рд╕реНрдиреИрдкрд╢реЙрдЯ:

ts Copy
const CONFIG: ScraperInput = {
  startUrls: [
    "https://www.etsy.com/listing/547491922/leather-walletwalletman-leather",
    "https://www.etsy.com/listing/1022283131/personalized-slim-wallet-fathers-day",
  ],
  maxProducts: 2,
  // ...рдЕрдиреНрдп рдбрд┐рдлрд╝реЙрд▓реНрдЯ
};

рд╢реНрд░реЗрдгреА URL рдореЛрдб - рд╕рдВрд░рдЪрд┐рдд рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рд╕рдВрдкреВрд░реНрдг рд╢реНрд░реЗрдгреА рдЦреАрдВрдЪрдирд╛:

ts Copy
const CONFIG: ScraperInput = {
  categoryUrl: "https://www.etsy.com/c/bags-and-purses/wallets-and-money-clips/wallets",
  filters: {
    onSale: true,
    freeShipping: true,
    minPrice: 20,
    maxPrice: 60,
    orderBy: "most_relevant",
  },
  maxPagesPerQuery: 2,
  maxProducts: 20,
};

рдХреАрд╡рд░реНрдб рдЦреЛрдЬ рдореЛрдб - рдирд┐рдЪрд▓реЗ рдЦреЛрдЬ, рдкреНрд░рд╡реГрддреНрддрд┐ рдЕрдиреБрд╕рдВрдзрд╛рди, рдорд╛рддреНрд░рд╛ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЦреАрдВрдЪрдирд╛:

ts Copy
const CONFIG: ScraperInput = {
  searchQuery: "leather wallet",
  expandStrategy: "keywords",                   // "none" | "keywords" | "prices"
  expandKeywords: ["mens", "womens", "vintage"], // рд╡реГрджреНрдзрд┐ = рдХреАрд╡рд░реНрдб рд╣реЛрдиреЗ рдкрд░ рдмреЗрд╕ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ
  maxProducts: 20,
};

рджреБрдХрд╛рди URL рдореЛрдб - рдмреЗрдВрдЪрдорд╛рд░реНрдХрд┐рдВрдЧ / рдкреНрд░рддрд┐рдпреЛрдЧреА рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рджреБрдХрд╛рди рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗрдВ:

ts Copy
const CONFIG: ScraperInput = {
  shopUrl: "https://www.etsy.com/shop/TexasValleyLeather",
  maxPagesPerQuery: 5,
  maxProducts: 40,
};

рдЪрд╛рд░реЛрдВ рдореЛрдб рдЪрд░рдг 4-6 рдореЗрдВ рд╡рд╣реА рдкреНрд░рддрд┐-рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рд╕рдореГрджреНрдзрд┐ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдЦрд┐рд▓рд╛рддреЗ рд╣реИрдВ рдФрд░ рдЪрд░рдг 8 рдореЗрдВ рд╡рд╣реА 30-рдХреНрд╖реЗрддреНрд░ рд╕реНрдХреАрдорд╛ рдирд┐рдХрд╛рд▓рддреЗ рд╣реИрдВред

рд╕рдВрд░рдЪрд┐рдд рдлрд╝рд┐рд▓реНрдЯрд░

рдЖрда рд╡реИрдХрд▓реНрдкрд┐рдХ рдлрд╝рд┐рд▓реНрдЯрд░ рдХреБрдВрдЬреА searchQuery рдпрд╛ categoryUrl рдХреЗ рд╕рд╛рде рд╕рдВрдпреЛрдЬрди рдХрд░рддреА рд╣реИрдВред рдЬреЛ рд▓рд╛рдЧреВ рд╣реЛрддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рд╕реЗрдЯ рдХрд░реЗрдВ, рдмрд╛рдХреА рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ:

рдХреБрдВрдЬреА рдорд╛рди рдкреНрд░рднрд╛рд╡
onSale true рдХреЗрд╡рд▓ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдмрд┐рдХреНрд░реА рдкрд░ рдЪрд┐рд╣реНрдирд┐рдд рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ
freeShipping true рдХреЗрд╡рд▓ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЬреЛ рдкреНрд░реЙрдХреНрд╕реА рджреЗрд╢ рдХреЗ рд▓рд┐рдП рдореБрдлреНрдд рд╢рд┐рдкрд┐рдВрдЧ рдХрд░ рд░рд╣реА рд╣реИрдВ
customizable true рдХреЗрд╡рд▓ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ
shipsTo ISO рдХреЛрдб рдЬреИрд╕реЗ "US" рдЙрд╕ рджреЗрд╢ рдореЗрдВ рд╢рд┐рдк рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ
minPrice / maxPrice рд╕рдВрдЦреНрдпрд╛ рдореВрд▓реНрдп рд╕реАрдорд╛ (Etsy рдХрд╛ рдореВрд▓ рдлрд╝рд┐рд▓реНрдЯрд░)
condition "new" | "vintage" Etsy рдХреА рд╕реНрдерд┐рддрд┐ рдлрд╝рд┐рд▓реНрдЯрд░
orderBy "рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг" | "рддрд╛рд░реАрдЦ_desc" | "рдХреАрдордд_asc" | "рдХреАрдордд_desc" | "рдЙрдЪреНрдЪрддрдо рд╕рдореАрдХреНрд╖рд╛рдПрдБ" рдкрд░рд┐рдгрд╛рдо рдХреНрд░рдордмрджреНрдз рдХрд░рдирд╛

рдкреГрд╖реНрдард╛рдВрдХрди рдирд┐рдпрдВрддреНрд░рдг

maxPagesPerQuery: N рд╕реЗрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЦреЛрдЬ URL рдкрд░ ?page=1..N рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджреЛрд╣рд░рд╛рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдЗрд╕рдХреЗ рдмрд┐рдирд╛, рд╕реНрдХреНрд░реИрдкрд░ рд▓рдХреНрд╖рд┐рдд рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдкреГрд╖реНрда рдХреЛ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЬреИрд╕реЗ рд╣реА maxProducts рдЕрджреНрд╡рд┐рддреАрдп рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рд╕рдореНрдорд┐рд▓рд┐рдд рд╣реЛ рдЬрд╛рддреА рд╣реИрдВ, рд░реБрдХ рдЬрд╛рддрд╛ рд╣реИред рдЬрдм рдЖрдк рдкреВрд░реНрд╡рд╛рдиреБрдорд╛рдирд┐рдд рдЪреМрдбрд╝реЗ рд╕реНрд╡реАрдк рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, "рдЗрд╕ рд╢реНрд░реЗрдгреА рдХреЗ рдкрд╣рд▓реЗ 5 рдкреГрд╖реНрдареЛрдВ рдХреЛ рд╕реНрдХреНрд░реИрдк рдХрд░реЗрдВ рднрд▓реЗ рд╣реА рд╡реЗ 200+ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рд╣реЛрдВ") рддреЛ рд╕реНрдкрд╖реНрдЯ рдкреГрд╖реНрдард╛рдВрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред


рдЪрд░рдг 3 тАФ рдорд▓реНрдЯреА-рдХреНрд╡реЗрд░реА рд╡рд┐рд╕реНрддрд╛рд░ (Etsy "рдкрд░рд┐рдгрд╛рдо рдХреИрдк" рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди)

Etsy рдХрд╛ рдЙрдкрднреЛрдХреНрддрд╛ UI рдкреГрд╖реНрдард╛рдВрдХрди рдХреЛ рдЕрдзрд┐рдХрддрд░ рдирд┐рдЪреЗ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╣реА рдХреИрдк рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рддрд┐-IP рджрд░ рд╕реАрдорд┐рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЙрдЪреНрдЪ рдЕрдиреБрд░реЛрдз рдорд╛рддреНрд░рд╛ рдореЗрдВ рдЬрд▓реНрджреА рд╕рдХреНрд░рд┐рдп рд╣реЛрддреА рд╣реИ тАФ рдХреЛрдИ рдПрдХрд▓ рдХреАрд╡рд░реНрдб рдХреЗрд╡рд▓ рдПрдХ рд░реИрдВрдХрд┐рдВрдЧ рд╕реНрд▓рд╛рдЗрд╕ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рддрд╛ рд╣реИред рдПрдХ рдирд┐рд╢рд╛рди рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореВрд▓ рдХреНрд╡реЗрд░реА рдХреЛ рдПрдХ рдзреБрд░реА (рдХреАрд╡рд░реНрдб рдпрд╛ рдореВрд▓реНрдп рдмрдХреЗрдЯ) рдХреЗ рд╕рд╛рде рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ listingId рджреНрд╡рд╛рд░рд╛ рдбрд┐рдбреБрдк рдХрд░реЗрдВред

"рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯ" рдХреЗ рд▓рд┐рдП, рдПрдХ рдХреАрд╡рд░реНрдб рд╡рд┐рд╕реНрддрд╛рд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рджрд┐рдЦрддрд╛ рд╣реИ:

ts Copy
function searchUrlForQuery(query: string, page = 1, priceMin?: number, priceMax?: number) {
  const params = new URLSearchParams({ q: query });
  if (page > 1) params.set("page", String(page));
  if (priceMin !== undefined) params.set("min", String(priceMin));
  if (priceMax !== undefined) params.set("max", String(priceMax));
  return `https://www.etsy.com/search?${params.toString()}`;
}

type ExpandStrategy = "рдХреАрд╡рд░реНрдб" | "рдХреАрдорддреЗрдВ" | "рдХреЛрдИ рдирд╣реАрдВ";

function multiQueryExpand(
  base: string,
  cfg: { expandStrategy: ExpandStrategy; expandKeywords: string[]; priceBuckets: [number, number][] }
) {
  if (cfg.expandStrategy === "рдХреАрд╡рд░реНрдб") {
    const queries = [base, ...cfg.expandKeywords.map((k) => `${k} ${base}`)];
    return queries.map((q) => searchUrlForQuery(q));
  }
  if (cfg.expandStrategy === "рдХреАрдорддреЗрдВ") {
    return cfg.priceBuckets.map(([min, max]) => searchUrlForQuery(base, 1, min, max));
  }
  return [searchUrlForQuery(base)];
}

["рдкреБрд░реБрд╖реЛрдВ", "рдорд╣рд┐рд▓рд╛рдУрдВ", "рд╡рд┐рдВрдЯреЗрдЬ"] "рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯ" рдХреЗ рдЦрд┐рд▓рд╛рдл рдЪрд╛рд░ рдЦреЛрдЬреЛрдВ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рддрд╛ рд╣реИред рдЙрдиреНрд╣реЗрдВ рдЪрд▓рд╛рдПрдБ, рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ URLs рдПрдХрддреНрд░ рдХрд░реЗрдВ, рдФрд░ URL рдореЗрдВ рджрдлрди рд╕рдВрдЦреНрдпрд╛рддреНрдордХ ID рджреНрд╡рд╛рд░рд╛ рдбрд┐рдбреБрдк рдХрд░реЗрдВ (/listing/1051861316/...)ред рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ maxProducts рдЗрддрдирд╛ рдКрдБрдЪрд╛ рд╣реЛ (рдХреБрдЫ рджрд░реНрдЬрди рд╕реЗ рдХреБрдЫ рд╕реМ) рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рднреА рднрд┐рдиреНрдирддрд╛рдУрдВ рдореЗрдВ рдлреИрд▓ рд╕рдХреЗ тАФ рдпрджрд┐ рд▓рдХреНрд╖реНрдп рдЫреЛрдЯрд╛ рд╣реИ рддреЛ рд╕реНрдХреНрд░реИрдкрд░ рдкрд╣рд▓реЗ рдХреНрд╡реЗрд░реА рдХреЗ рдмрд╛рдж рд╢реЙрд░реНрдЯ-рд╕рд░реНрдХрд┐рдЯ рдХрд░ рджреЗрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ, рдбрд┐рдбреБрдк рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЫреЛрдбрд╝ рджреЗрдЧрд╛ред

рдХреАрдордд рдмрдХреЗрдЯрд┐рдВрдЧ рдЙрд╕реА рддрд░рд╣ рдХрд╛рдо рдХрд░рддреА рд╣реИ тАФ рд╡рд┐рднрд┐рдиреНрди рдмрдХреЗрдЯ рднрд┐рдиреНрди рд░реИрдВрдХрд┐рдВрдЧ рд╕реНрд▓рд╛рдЗрд╕ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ Etsy рдХрд╛ "рд╕рд░реНрд╡рд╢реНрд░реЗрд╖реНрда рдорд┐рд▓рд╛рди" рдкрд░рд┐рдгрд╛рдо рд╕реЗрдЯ рдореЗрдВ рджреВрд╕рд░реЛрдВ рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖ рдХреАрдордд рджреНрд╡рд╛рд░рд╛ рдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛрддрд╛ рд╣реИред


рдЪрд░рдг 4 тАФ рдкреНрд░рддреНрдпреЗрдХ рдЦреЛрдЬ рд╕реЗ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ URLs рдПрдХрддреНрд░ рдХрд░реЗрдВ

рдкрд░рд┐рдгрд╛рдо рд╕рд╛рдЗрдбрдмрд╛рд░ рдХреЛ рдЗрд╕ рд╣рдж рддрдХ рд╕реНрдХреНрд░реЙрд▓ рдХрд░реЗрдВ рдХрд┐ рд▓реЗрдЬрд╝реА-рд▓реЛрдбреЗрдб рдХрд╛рд░реНрдб рдЯреНрд░рд┐рдЧрд░ рд╣реЛ рдЬрд╛рдПрдВ, рдлрд┐рд░ рд╣рд░ a[href*="/listing/"] рд▓рд┐рдВрдХ рдХреЛ рдПрдХ div.listing-link рдХреЗ рдЕрдВрджрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ (рдЬрдм Etsy A/B-рдЯреЗрд╕реНрдЯ рд╡рд░реНрдЧ рдирд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реЛ рддреЛ [data-listing-id] рдХреЗ рд░реВрдк рдореЗрдВ рдлрд╝реЙрд▓ рдмреИрдХ)ред

ts Copy
type SearchHit = { listingId: string | null; url: string; title: string | null; rank: number };
const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function collectSearchResults(page: Page, searchUrl: string, target: number, pageTimeoutMs = 60000): Promise<SearchHit[]> {
  await page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 60000 });
  await dismissEtsyConsent(page);
  await delay(2000);

  // Lazy-loaded рдХрд╛рд░реНрдб рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдмрд╛рд░ рд╕реНрдХреНрд░реЙрд▓ рдХрд░реЗрдВред рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд╕
  // рд╡рд░реНрддрдорд╛рди DOM рдХреА рдПрдХ cheerio рд╕реНрдиреИрдкрд╢реЙрдЯ рд▓реЗрддрд╛ рд╣реИ - рдЬреИрд╕реЗ рд╣реА рд╣рдореЗ
  // рдХрд╛рдлреА рдорд┐рд▓ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдо рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрддреЗ рд╣реИрдВред
  for (let i = 0; i < 6; i++) {
    const $peek = await parseWithCheerio(page);
    if ($peek("[data-listing-id], div.listing-link").length >= target) break;
    await page.evaluate(() => window.scrollBy(0, 1200));
    await delay(900);
  }

  // Cheerios рдХреЗ рд╕рд╛рде рдирд┐рдкрдЯрд╛рдП рдЧрдП DOM рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ - рдХреЛрдИ `page.evaluate` рд░рд╛рдЙрдВрдб-рдЯреНрд░рд┐рдк рдирд╣реАрдВ,
  // рдХреЛрдИ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдлрд╝рдВрдХреНрд╢рди рдмреЙрдбреА рдирд╣реАрдВ, рд╕реАрдзрд╛ рдЪрдпрдирдХрд░реНрддрд╛ рдпрд╛рддреНрд░рд╛ред
  const $ = await parseWithCheerio(page);
  let cards = $("div.listing-link");
  if (cards.length === 0) cards = $("[data-listing-id]");
  const hits: SearchHit[] = [];
  const seen = new Set<string>();
  cards.each((_, card) => {
    const link = $(card).find('a[href*="/listing/"]').first();
    if (!link.length) return;
    const href = link.attr("href") || "";
    const absolute = href.startsWith("http") ? href : `https://www.etsy.com${href.startsWith("/") ? "" : "/"}${href}`;
    const url = absolute.split("?")[0];
    if (!url || seen.has(url)) return;
    seen.add(url);
    const titleEl = $(card).find("h3").first();
    const title = titleEl.length ? titleEl.text().trim() : (link.attr("title") || null);
    const idMatch = url.match(/\/listing\/(\d+)/);
    const listingId = idMatch ? idMatch[1] : null;
    hits.push({ listingId, url, title, rank: hits.length + 1 });
  });
  return hits;
}

рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ page.evaluate рдкрд░ рдмрдиреА рд░рд╣рддреА рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдПрдХ рд▓рд╛рдЗрд╡ DOM рдХреНрд░рд┐рдпрд╛ рд╣реИ (Etsy рдХреЗ рд▓реЗрдЬрд╝реА-рд▓реЛрдб рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдирд╛), рд▓реЗрдХрд┐рди рд╣рд░ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдХрд╛ рдЯреБрдХрдбрд╝рд╛ cheerio рдкрд░ page.content() рд╕реНрдиреИрдкрд╢реЙрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓рддрд╛ рд╣реИред рдпрд╣ рд╡рд╣реА рдкреИрдЯрд░реНрди рд╣реИ рдЬреЛ рдЪрд░рдг 6-7 рдореЗрдВ рд╕рднреА рдЫрд╣ рд╕рдореГрджреНрдзрд┐ рдПрдХреНрд╕рдЯреНрд░реИрдХреНрдЯрд░реНрд╕ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
dismissEtsyConsent рдХреЙрд▓ рдЙрди рдЧреИрд░-рдЕрдореЗрд░рд┐рдХреА рд╕рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ рдЬрд╣рд╛рдБ Etsy рдкреГрд╖реНрда рдкреНрд░рд╕реНрддреБрдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ "рдХреБрдХреАрдЬрд╝ рдФрд░ рдЧреЛрдкрдиреАрдпрддрд╛" рдЧреЗрдЯ рдкреЗрд╢ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХрд┐рд╕реА рднреА рдмрдЯрди рдХреЛ рдЦреЛрдЬрддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рд▓реЗрдмрд▓ "рд╕рднреА рд╕реНрд╡реАрдХреГрдд рдХрд░реЗрдВ" / "рд╕рднреА рдЕрд╕реНрд╡реАрдХреГрдд рдХрд░реЗрдВ" / рдХреБрдЫ рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╕рдордХрдХреНрд╖ рд╣реИ рдФрд░ рдЗрд╕реЗ рдХреНрд▓рд┐рдХ рдХрд░рддрд╛ рд╣реИред

рдЪрд░рдг 5 тАФ рдкреНрд░рддреНрдпреЗрдХ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдкрд░ рдиреЗрд╡рд┐рдЧреЗрдЯ рдХрд░реЗрдВ

рдЧреВрдЧрд▓ рдореИрдкреНрд╕ рдХреЗ рд╡рд┐рдкрд░реАрдд, Etsy рдХреЗ /listing/<id>/ рдпреВрдЖрд░рдПрд▓ рд╕реАрдзреЗ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдкрд░ рднреА рдкреВрд░реНрдг рдкреИрдирд▓ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХреНрд▓рд┐рдХ-рдереНрд░реВ рдЪрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ тАФ рд╕реНрдХреНрд░реИрдкрд░ рд╕реАрдзреЗ page.goto(listingUrl) рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, DataDome рдЗрд╕ рдЙрдк-рдЯреНрд░реА рдкрд░ рддрд╛рдЬрд╛ рдкреНрд░реЙрдХреНрд╕реА рдЖрдИрдкреА рдХреЗ рдПрдХ рд╕рд╛рд░реНрдердХ рдЕрдВрд╢ рдкрд░ HTTP 403 рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдиреЗрд╡рд┐рдЧреЗрд╢рди рд░реИрдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, 403/429 рдкрд░ рддреЗрдЬреА рд╕реЗ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдпрджрд┐ h1 рдХрднреА рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ рддреЛ рдереНрд░реЛ рдХрд░ рджреЗрддрд╛ рд╣реИ тАФ рдЗрди рд╢рд░реНрддреЛрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдмрд╛рд╣рд░реА рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд▓реВрдк рдХреЛ рдПрдХ рдирдП рдЖрд╡рд╛рд╕реАрдп рдЖрдИрдкреА рдкрд░ рдПрдХ рддрд╛рдЬрд╛ рд╕рддреНрд░ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреНрд░рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИред

ts Copy
const resp = await page.goto(hit.url, { waitUntil: "domcontentloaded", timeout: 60000 });
const status = resp?.status() ?? 0;
if (status === 403 || status === 429) {
  throw new Error(`blocked: HTTP ${status} on ${hit.url}`);
}
await dismissEtsyConsent(page);
try {
  await page.waitForSelector("h1", { timeout: 15000 });
} catch {
  // 15 рд╕реЗрдХрдВрдбреЛрдВ рдХреЗ рдмрд╛рдж рдХреЛрдИ h1 рд╣реЛрдирд╛ DataDome рдЪреБрдиреМрддреА рдпрд╛ рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рдкреГрд╖реНрда рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИред
  // рдереНрд░реЛ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд▓реВрдк рдПрдХ рддрд╛рдЬрд╛ рд╕рддреНрд░ (= рддрд╛рдЬрд╛ рдЖрд╡рд╛рд╕реАрдп рдЖрдИрдкреА) рдЦреЛрд▓реЗред
  throw new Error(`no h1 on ${hit.url} тАФ likely bot-challenge page`);
}
await delay(1500);

рдЗрд╕рдХреЗ рдмрд╛рдж рд╕рдореНрдкреВрд░реНрдг рдкреГрд╖реНрда рдХреЛ рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдХреЗ рд▓реЗрдЬреА рд▓реЛрдбрд┐рдВрдЧ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░реЗрдВред рд╡рд┐рд╡рд░рдг, рд╕рд╛рдордЧреНрд░реА рдФрд░ рд╢рд┐рдкрд┐рдВрдЧ рдЕрдиреБрднрд╛рдЧ рд╕рднреА рд╕реНрдХреНрд░реЙрд▓ рдкрд░ рд▓реЛрдб рд╣реЛрддреЗ рд╣реИрдВред

рдЪрд░рдг 6 тАФ рдЕрд╡рд▓реЛрдХрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рдирд┐рдХрд╛рд▓реЗрдВ

рдирд┐рд╖реНрдХрд░реНрд╖рдХ рдореЗрдВ рдПрдХ рджреЛ-рдЪрд░рдгреАрдп рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд╖реНрдХрд░реНрд╖рдХ рдореЗрдВ рджреЛрд╣рд░рд╛рдИ рдЬрд╛рддреА рд╣реИ: рдмреНрд░рд╛рдЙрдЬрд╝рд░-рд╕рд╛рдЗрдб (рд╕реНрдХреНрд░реЙрд▓ + waitForFunction рд▓реЗрдЬреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рд╣рд╛рдЗрдбреНрд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП) тЖТ рдиреЛрдб-рд╕рд╛рдЗрдб (рдПрдХ рдмрд╛рд░ page.content() рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреГрд╖реНрда рдХреА HTML рдЦреАрдВрдЪрдирд╛ рдлрд┐рд░ рдЗрд╕реЗ cheerio рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд░рдирд╛)ред рдпрд╣ рд╡рд┐рднрд╛рдЬрди рд╣рдореЗрдВ рд▓рд╛рдЗрд╡-рдбреАрдУрдПрдо рд╡реНрдпрд╡рд╣рд╛рд░ рджреЗрддрд╛ рд╣реИ рдЬрдм рд╣рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдФрд░ рдЬрдм рд╣рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ рддреЛ рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рд╣реБрдЖ, рдкрд░реАрдХреНрд╖рдг рдпреЛрдЧреНрдп рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб рдкрд╛рд░реНрд╕рд┐рдВрдЧред

ts Copy
async function extractOverview(page: Page): Promise<Partial<EtsyProduct>> {
  // рдмреНрд░рд╛рдЙрдЬрд╝рд░-рд╕рд╛рдЗрдб: рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рд╕реНрдХреНрд░реЙрд▓ рдХрд░реЗрдВ рддрд╛рдХрд┐ рд╡рд┐рд╡рд░рдг / рд╕рд╛рдордЧреНрд░реА / рд╢рд┐рдкрд┐рдВрдЧ
  // рд▓реЗрдЬреА-рд▓реЛрдб рд╣реЛрдВ, рдлрд┐рд░ "рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ" рдкреНрд▓реЗрд╕рд╣реЛрд▓реНрдбрд░ рдХреЗ рдкрд╛рд░ рдЦрд░реАрдж-рдмреЙрдХреНрд╕ рдХреЛ рд╣рд╛рдЗрдбреНрд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВред
  await page.evaluate(`(function() {
    var step = 500, total = document.body.scrollHeight, current = 0;
    var iv = setInterval(function() {
      current += step;
      window.scrollTo(0, current);
      if (current >= total) clearInterval(iv);
    }, 200);
  })()`);
  await delay(3500);

  try {
    await page.waitForFunction(
      // рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдЬрдм рддрдХ рдХреЛрдИ рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдореВрд▓реНрдп рд░реИрдкрд░ рд╕рдВрдЦреНрдпрд╛ рдорд╛рди рдирд╣реАрдВ рд░рдЦрддрд╛
      // (рдирд╣реАрдВ "рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ" рдкреНрд▓реЗрд╕рд╣реЛрд▓реНрдбрд░ рдЬрд┐рд╕реЗ Etsy рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд░реВрдк рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ)ред 
      // рдЦрд░реАрдж-рдмреЙрдХреНрд╕ рд░реИрдкрд░ рдХреЗ рдмрдЬрд╛рдп рд╕рдВрднрд╛рд╡рд┐рдд рднрд┐рдиреНрдирддрд╛ рд╢реБрд░реВ рдХрд░рдирд╛ 
      // рдзреАрдореА рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдкрд░ рд╣рд┐рдЯ рджрд░ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдБ рдореВрд▓реНрдп рдкрд╣рд▓реЗ .currency-value рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИред
      `(function(){
        var sels = [
          "[data-selector='price-only'] span.currency-value",
          "div[data-buy-box-region='price'] span.currency-value",
          "p[class*='price'] span.currency-value",
          "span.currency-value"
        ];
        for (var i = 0; i < sels.length; i++) {
          var el = document.querySelector(sels[i]);
          if (el && /^\\s*\\$?\\d/.test((el.textContent || '').trim())) return true;
        }
        return false;
      })()`,
      { timeout: 15000 },
    );
  } catch { /* рдирд┐рд╖реНрдХрд░реНрд╖рдХ рдиреАрдЪреЗ рдЕрдкрдиреА рд╕рд░реНрд╡реЛрддреНрддрдо рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИ */ }

  // рдиреЛрдб-рд╕рд╛рдЗрдб: рдПрдХ рдмрд╛рд░ рдкреНрд░рджрд░реНрд╢рд┐рдд HTML рдЦреАрдВрдЪреЗрдВ рдФрд░ рдЗрд╕реЗ cheerio рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд░реЗрдВред
  const $ = await parseWithCheerio(page);

  const title = $("h1").first().text().trim() || null;

  // рдореВрд▓реНрдп тАФ рддреАрди-рдЪрд░рдг рдХреА рдХреИрд╕реНрдХреЗрдбред (1) рд╕реНрдкрд╖реНрдЯ `[data-selector='price-only']`
  // рдЙрдк-рдЯреНрд░реА рдХреЛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреЗрдВ рдЬрд┐рд╕реЗ Etsy рд╡рд░реНрддрдорд╛рди рдореВрд▓реНрдп рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддрд╛ рд╣реИ; (2) рдкрд╣рд▓реЗ 
  // `span.currency-value` рдореЗрдВ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдБ рдЬрд┐рд╕рдХреЗ рдкреВрд░реНрд╡рдЬ рд╕реНрдЯреНрд░рд╛рдЗрдХрдереНрд░реВ / рдореВрд▓ рдореВрд▓реНрдп 
  // рд░реИрдкрд░ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВ; (3) рдЕрдВрддрд┐рдо рдЙрдкрд╛рдп рд╢рд░реАрд░-рдЯреЗрдХреНрд╕реНрдЯ рд░реЗрдЧреБрд▓рд░ рдПрдХреНрд╕рдкреНрд░реЗрд╢рдиред
  const isOriginalPriceWrapper = (el: any) =>
    $(el).closest("[class*='strikethrough'], [class*='original'], s, .wt-text-strikethrough").length > 0;
  let price: string | null = null;
  const priceOnly = $("[data-selector='price-only'] span.currency-value").first();
  if (priceOnly.length && /^\d/.test(priceOnly.text().trim())) {
    price = priceOnly.text().trim();
  }
  if (!price) {
    $("span.currency-value").each((_, el) => {
      if (price) return false;
      if (isOriginalPriceWrapper(el)) return;
      const t = $(el).text().trim();
      if (t && /^\d/.test(t)) price = t;
    });
  }
  if (!price) {
    const bodyPriceMatch = $("body").text().match(/(?:рдЕрдм\s+)?рдХреАрдордд:?\s*([$┬гтВм]?[\d.,]+)/i);
    if (bodyPriceMatch) price = bodyPriceMatch[1].trim();
  }

  // рд░реЗрдЯрд┐рдВрдЧ тАФ рдХреЛрдИ рднреА aria-label рдЬреЛ "рд╕реНрдЯрд╛рд░", "рд░реЗрдЯрд┐рдВрдЧ" рдпрд╛ "рдореЗрдВ" рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░рддрд╛ рд╣реИред
  let rating: number | null = null;
  $("[aria-label*='star' i], [aria-label*='rating' i]").each((_, n) => {
    if (rating !== null) return false;
    const a = $(n).attr("aria-label") || "";
    const rm = a.match(/(\d+(?:\.\d+)?)\s*(?:рдореЗрдВ|рд╕реНрдЯрд╛рд░|рд░реЗрдЯрд┐рдВрдЧ)/i);
    if (rm) rating = parseFloat(rm[1]);
  });

Here's the translation of the provided text into Hindi:

javascript Copy
// рд╕реНрдерд┐рддрд┐ рдмреИрдЬ - рдкреГрд╖реНрда рдХреЗ рд╢рд░реАрд░ рдХреЗ рд▓рд┐рдП regexред
const bodyText = $("body").text();
const isBestseller = /Bestseller/i.test(bodyText);
const isFreeShipping = /free shipping/i.test(bodyText);
const isStarSeller = /Star Seller/i.test(bodyText);
const inStock = !/out of stock|sold out/i.test(bodyText);

// рд╢реЙрдк рд╕рд╛рдЗрдбрдХрд╛рд░ред
const shopLink = $("a[href*='/shop/']").first();
const shopName = shopLink.text().trim() || null;
const shopUrl = (shopLink.attr("href") || "").split("?")[0] || null;

return { title, _price_raw: price, rating, isBestseller, isFreeShipping, isStarSeller, inStock,
  shop: { name: shopName, url: shopUrl } } as Partial<EtsyProduct>;
}

_price_raw рдЙрдкрд╕рд░реНрдЧ рдПрдХ рдкрд░рдВрдкрд░рд╛ рд╣реИ: рдбрд╛рдЙрдирд╕реНрдЯреНрд░реАрдо enrichProduct рдЗрд╕реЗ extractNumber рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднреЗрдЬрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рдЕрдВрддрд┐рдо JSON рдХреЛ рдЬрд╛рд░реА рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХрдЪреНрдЪреЗ-рд╕реНрдЯрд┐рдВрдЧ рдлреАрд▓реНрдб рдХреЛ рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИред рд╕реНрдирд┐рдкреЗрдЯ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╣реИ тАФ index.ts рдореЗрдВ рдкреВрд░реНрдг extractOverview рднреА currency, discountPercent, reviewsCount, favoritesCount, description, materials, itemDetails, shippingFrom, processingTime, tags, listedDate рдФрд░ рдмрд╛рдХреА рд╢реЙрдк рдлрд╝реАрд▓реНрдбреНрд╕ рдХреЛ рдЦреАрдВрдЪрддрд╛ рд╣реИред рд╕рдорд╛рди cheerio-first рдкреИрдЯрд░реНрди рдкреВрд░реЗ рднрд╛рдЧ рдореЗрдВ рд╣реИ, рдХреЗрд╡рд▓ рдЕрдзрд┐рдХ рдЪрдпрдирдХрд░реНрддрд╛ рд╣реИрдВред

рдПрдХ рдЫреЛрдЯрд╛ рдореБрджреНрд░рд╛-рд╕рд╣рд┐рд╖реНрдгреБ extractNumber рд╕рд╣рд╛рдпрдХ "$24.99", "24,99 тВм", рдпрд╛ "1,234" рдХреЛ рдПрдХ рд╕рд╛рдл рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реИ тАФ Etsy рд╕реНрдерд╛рдиреАрдп рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдХреАрдорддреЗрдВ рдкреНрд░реЙрдХреНрд╕реА рджреЗрд╢ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЖрдк рдирд╣реАрдВ рдЪрд╛рд╣рддреЗ рдХрд┐ рдЖрдкрдХреЗ рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рдлрд╝реАрд▓реНрдб рд╕реНрдЯреНрд░рд┐рдВрдЧ рдмрдиреЗрдВред

рдЪрд░рдг 7 тАФ рд╕рдореАрдХреНрд╖рд╛рдПрдВ, рдЫрд╡рд┐рдпрд╛рдВ, рд╢реЙрдк рд╕рд╛рдЗрдбрдХрд╛рд░, рд╡рд┐рд╡рд┐рдзрддрд╛рдПрдВ, рдмреНрд░реЗрдбрдХреНрд░рдВрдм, рд╕рдВрдмрдВрдзрд┐рдд рдЦреЛрдЬреЗрдВ

рд╕рдореАрдХреНрд╖рд╛рдПрдВред Etsy рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд╛рд░реНрдб div[data-review-region] рдореЗрдВ рд░рд╣рддреА рд╣реИрдВ (DOM рд╕рдВрд╢реЛрдзрдиреЛрдВ рдХреЗ рд▓рд┐рдП div[class*='review-card'] рдФрд░ div[class*='review-item'] рдХреЗ рд░реВрдк рдореЗрдВ рдмреИрдХрдЕрдк)ред рд╕рдореАрдХреНрд╖рд╛рдУрдВ рдХреЗ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рд╕реНрдХреНрд░реЙрд▓ рдХрд░реЗрдВ, рдлрд┐рд░ рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдб рдХреЛ рд▓реЗрдЦрдХ/рд░реЗрдЯрд┐рдВрдЧ/рдкрд╛рда/рддрд╛рд░реАрдЦ рдХреЗ рд╕рд╛рде рд╕рд╛рде рддреАрди рдЙрдк-рд░реЗрдЯрд┐рдВрдЧ рдореЗрдВ рдореИрдк рдХрд░реЗрдВред

ts Copy
async function extractReviews(page: Page, max: number): Promise<EtsyReview[]> {
  // рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдкрдХреНрд╖: lazy рд╕рдореАрдХреНрд╖рд╛ рдХрд╛рд░реНрдб рдХреЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдореАрдХреНрд╖рд╛рдУрдВ рдХреЗ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рд╕реНрдХреНрд░реЙрд▓ рдХрд░реЗрдВред
  for (let i = 0; i < 8; i++) {
    const found = await page.evaluate(
      `!!document.querySelector('[data-reviews-section], div#reviews, div[class*="reviews"]')`,
    );
    if (found) break;
    await page.evaluate(() => window.scrollBy(0, 700));
    await delay(700);
  }
  await delay(1500);

  // рдиреЛрдб-рдкрдХреНрд╖: рдЕрдм рд╣рд╛рдЗрдбреНрд░реЗрдЯреЗрдб рдкреГрд╖реНрда рдХреЛ cheerio рдХреЗ рд╕рд╛рде рдкрд╛рд░реНрд╕ рдХрд░реЗрдВред
  const $ = await parseWithCheerio(page);
  const out: EtsyReview[] = [];

  $(
    "div[data-review-region], div[class*='review-card'], div[class*='review-item'], li[class*='review']",
  ).each((_, card) => {
    if (out.length >= max) return false;
    const $card = $(card);
    const cardText = $card.text();
    // рдРрд╕реЗ рд╕рд╛рдореВрд╣рд┐рдХ рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ рдЬреЛ рдПрдХ рд╕рд╛рде рдХрдИ рд╕рдореАрдХреНрд╖рд╛рдПрдВ рд░рдЦрддреЗ рд╣реИрдВред
    if (cardText.length > 6000) return;

    const author = $card.find("a[href*='/people/'], strong, p[class*='name']").first().text().trim() || null;

    // рд░реЗрдЯрд┐рдВрдЧ: рдкрд╣рд▓реЗ `data-rating` рд╡рд┐рд╢реЗрд╖рддрд╛, рдлрд┐рд░ aria-labelред
    let rating: number | null = null;
    const $starEl = $card.find("[aria-label*='star' i], [data-rating]").first();
    if ($starEl.length) {
      const dr = $starEl.attr("data-rating");
      if (dr) rating = parseFloat(dr);
      else {
        const rm = ($starEl.attr("aria-label") || "").match(/(\d+(?:\.\d+)?)/);
        if (rm) rating = parseFloat(rm[1]);
      }
    }

    // рдкрд╛рда: рд╡рд┐рд╢реЗрд╖ рдЪрдпрдирдХрд░реНрддрд╛, рдлрд┐рд░ рдХрд╛рд░реНрдб рдореЗрдВ рд╕рдмрд╕реЗ рд▓рдВрдмрд╛ рдкреИрд░рд╛рдЧреНрд░рд╛рдлред
    let text: string | null =
      $card.find("p[class*='review-text'], div[class*='review-text'], div[id*='review-content']")
        .first().text().trim() || null;
    if (!text) {
      let longest = "";
      $card.find("p").each((_, p) => {
        const pt = $(p).text().trim();
        if (pt.length > longest.length && pt.length > 20) longest = pt;
      });
      text = longest || null;
    }

    // рддрд╛рд░реАрдЦ: рдкрд╣рд▓реЗ рд╡рд┐рд╢реЗрд╖ рддрддреНрд╡, рдлрд┐рд░ рдорд╣реАрдирд╛ рдирд╛рдо рдпрд╛ рд╕рдВрдЦреНрдпрд╛рддреНрдордХ regexред
    let date: string | null =
      $card.find("span[class*='date'], time, p[class*='date']").first().text().trim() || null;
    if (!date) {
      const dm = cardText.match(/(\w{3,9}\s+\d{1,2},?\s+\d{4}|\d{1,2}\/\d{1,2}\/\d{2,4})/);
      if (dm) date = dm[1];
    }

    // рдЙрдк-рд░реЗрдЯрд┐рдВрдЧ - рдХрд╛рд░реНрдб рдХреЗ рдЕрдВрджрд░ рд▓реЗрдмрд▓ рд╡рд╛рд▓реЗ рдкрдВрдХреНрддрд┐рдпрд╛рдБред рд▓реЗрдмрд▓ рдХреЛ рдорд┐рд▓рд╛рдПрдБ, рдирд┐рдХрдЯрддрдо рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░реЗрдВред
    const subRating = (label: string): number | null => {
      let val: number | null = null;
      $card.find("span, div, li").each((_, row) => {
        if (val !== null) return false;
        const t = $(row).text().toLowerCase();
        if (t.includes(label) && t.length < 60) {
          const sm = t.match(/(\d+(?:\.\d+)?)/);
          if (sm) val = parseFloat(sm[1]);
        }
      });
      return val;
    };

    // рд╕рдореАрдХреНрд╖рдХ рджреНрд╡рд╛рд░рд╛ рдЕрдкрд▓реЛрдб рдХреА рдЧрдИ рддрд╕реНрд╡реАрд░реЗрдВ тАФ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рдорд╛рди `il_fullxfull` рдЙрдиреНрдирдпрдиред
    const photos: string[] = [];
    const photoSeen = new Set<string>();
    $card.find("img[src*='etsystatic'], img[data-src*='etsystatic']").each((_, img) => {
      if (photos.length >= 6) return false;
      let psrc = $(img).attr("src") || $(img).attr("data-src") || "";
      if (!psrc) return;

Feel free to let me know if you need any additional translations or information!
Here is the translation of the provided text into Hindi:

Copy
psrc = psrc.replace(/il_\d+xN/, "il_fullxfull").replace(/_\d+x\d+\./, "_1024x1024.");
      if (!photoSeen.has(psrc)) { photoSeen.add(psrc); photos.push(psrc); }
    });

    out.push({
      author, rating, text, date,
      itemQuality: subRating("рд╡рд╕реНрддреБ рдХреА рдЧреБрдгрд╡рддреНрддрд╛"),
      shipping: subRating("рд╢рд┐рдкрд┐рдВрдЧ"),
      customerService: subRating("рдЧреНрд░рд╛рд╣рдХ рд╕реЗрд╡рд╛"),
      photos,
    });
  });

  return out;
}

рдЪрд╛рд░ рдХрд╛рд░реНрдб-рдЪреБрдирд╛рд╡ рд╡рд┐рдХрд▓реНрдк Etsy рдХреЗ рдЪрд▓ рд░рд╣реЗ A/B рд╕рдВрд╢реЛрдзрдиреЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░рддреЗ рд╣реИрдВ - [data-review-region] рд╡рд░реНрддрдорд╛рди рд▓реЛрдХрдкреНрд░рд┐рдп рдЪрдпрдирдХрд░реНрддрд╛ рд╣реИ; [class*='review-card'], [class*='review-item'] рдФрд░ li[class*='review'] рдкреБрд░рд╛рдиреЗ рдФрд░ рдирдП рд░реВрдк рд╣реИрдВ рдЬреЛ рдЦрд╛рддреЗ рдФрд░ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВред рдКрдкрд░ рдХрд╛рд░реНрдбText рдХреА рд▓рдВрдмрд╛рдИ рдХреА рд╕реБрд░рдХреНрд╖рд╛ рдЙрди рдШреЗрд░рдиреЗ рд╡рд╛рд▓реЗ рддрддреНрд╡реЛрдВ рдХреЛ рдЫреЛрдбрд╝ рджреЗрддреА рд╣реИ рдЬреЛ рдЕрдирдЬрд╛рдиреЗ рдореЗрдВ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рд╕рд╛рде рдЬреЛрдбрд╝реЗ рдЧрдП рд╕рдореАрдХреНрд╖рд╛рдУрдВ рдХреА рдкреВрд░реА рдорд╛рддреНрд░рд╛ рд▓реМрдЯрд╛рддреЗ рд╣реИрдВред

рдЫрд╡рд┐рдпрд╛рдВред Etsy рдбрд┐рдлрд╝реЙрд▓реНрдЯ рджреНрд╡рд╛рд░рд╛ рдердВрдмрдиреЗрд▓ рд╕реЗрд╡ рдХрд░рддрд╛ рд╣реИред URL рдореЗрдВ рдЖрдХрд╛рд░ рдкреНрд░рддреНрдпрдп рдХреЛ рдмрджрд▓рдХрд░ рдЙрдиреНрд╣реЗрдВ рдкреВрд░реНрдг-рд░рд┐рдЬрд╝реЛрд▓реНрдпреВрд╢рди рдореЗрдВ рдЕрдкрдЧреНрд░реЗрдб рдХрд░реЗрдВ: il_75x75 тЖТ il_fullxfull, рдпрд╛ _300x300.jpg тЖТ _1024x1024.jpgред рд╡рд╣реА рдЫрд╡рд┐, рдХрд╣реАрдВ рдЕрдзрд┐рдХ рдЙрдЪреНрдЪ рд░рд┐рдЬрд╝реЛрд▓реНрдпреВрд╢рди, рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдиреБрд░реЛрдз рдирд╣реАрдВред

ts Copy
async function extractImages(page: Page, max: number): Promise<string[]> {
  const $ = await parseWithCheerio(page);
  const urls: string[] = [];
  const seen = new Set<string>();
  $("img[src*='etsystatic'], img[data-src*='etsystatic']").each((_, img) => {
    if (urls.length >= max) return false;
    let src = $(img).attr("src") || $(img).attr("data-src") || "";
    if (!src) return;
    // рдердВрдмрдиреЗрд▓ рдЖрдХрд╛рд░ рдкреНрд░рддреНрдпрдп рдХреЛ рд╕рдВрднрд╡рддрдГ рдкреВрд░реНрдг рд░рд┐рдЬрд╝реЛрд▓реНрдпреВрд╢рди рдореЗрдВ рдЕрдкрдЧреНрд░реЗрдб рдХрд░реЗрдВред
    src = src.replace(/il_\d+xN/, "il_fullxfull").replace(/_\d+x\d+\./, "_1024x1024.");
    if (!seen.has(src)) { seen.add(src); urls.push(src); }
  });
  return urls;
}

img[data-src*='etsystatic'] рдкреИрдЯрд░реНрди рдЪрдпрдирдХрд░реНрддрд╛ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ - Etsy data-src рдХреЗ рдкреАрдЫреЗ рдЧреИрд▓рд░реА рдердВрдмрдиреЗрд▓ рдХреЛ рд▓реЗрдЬрд╝реА рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЬрдм рддрдХ рд╡реЗ рджреГрд╢реНрдп рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдирд╣реАрдВ рдЖрддреЗ, src рдХреЛ рднрд░рддрд╛ рдирд╣реАрдВ рд╣реИред

рднрд┐рдиреНрдирддрд╛рдПрдБ, рдмреНрд░реЗрдбрдХреНрд░рдВрдмреНрд╕, рд╕рдВрдмрдВрдзрд┐рдд рдЦреЛрдЬреЗрдВред рд╕рдореАрдХреНрд╖рд╛рдУрдВ рдФрд░ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рдмрд╛рдж рддреАрди рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рдХрд╛рд▓рдиреЗ рд╡рд╛рд▓реЗ рдЪрд▓рд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдкреНрд░рддреНрдпреЗрдХ рдЕрдкрдиреЗ рдЕрдкрдиреЗ try/catch рдореЗрдВ рд▓рд┐рдкрдЯреЗ рд╣реЛрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдПрдХ рдЫреВрдЯреА рд╣реБрдИ рдЪрдпрдирдХрд░реНрддрд╛ рдПрдХ рдЦрд╛рд▓реА рдПрд░реЗ рдореЗрдВ рдШрдЯрд┐рдд рд╣реЛрддреА рд╣реИ рдмрдЬрд╛рдп рдХрд┐ рдкрдВрдХреНрддрд┐ рдХреЛ рддреЛрдбрд╝рдиреЗ рдХреЗ:

  • extractVariations(page) - рдЖрдХрд╛рд░ / рд░рдВрдЧ / рд╡реНрдпрдХреНрддрд┐рдЧрддрдХрд░рдг рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЛ рдЦреАрдВрдЪрддрд╛ рд╣реИ рдЬреЛ рд╡рд┐рдХреНрд░реЗрддрд╛ рдЙрдЬрд╛рдЧрд░ рдХрд░рддрд╛ рд╣реИ, рдЬреИрд╕реЗ {name, options[]}[] рд╕реВрдЪреАред [data-selector*='variation'] рдЙрдкрд╡реГрдХреНрд╖реЛрдВ рдХреЗ рдЕрдВрджрд░ <select> рддрддреНрд╡реЛрдВ рд╕реЗ Populate рдХрд░рддрд╛ рд╣реИред
  • extractBreadcrumbs(page) - рд╢реНрд░реЗрдгреА рдХреА рдЯреНрд░реЗрд▓ рдХреЛ рдЦреАрдВрдЪрддрд╛ рд╣реИ (рдЬреИрд╕реЗ ["Homepage", "Bags & Purses", "Wallets & Money Clips", "Wallets"]) рдЙрди рдПрдВрдХрд░ рдЯреИрдЧ рд╕реЗ рдЬреЛ рдЙрдирдХреЗ href рдореЗрдВ ref=breadcrumb_listing рд╕реЗ рд▓реЗрдХрд░ рдЖрддреЗ рд╣реИрдВред Etsy рдЗрдирдХреА рд▓рд┐рдкрдЯрд╛ рдирд╣реАрдВ рд╣реИ <nav aria-label="breadcrumb"> - рдпреЗ рд╕рд╛рдлрд╝ рд▓рд┐рдВрдХ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдПрдХ рд╕рдВрджрд░реНрдн рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИред
  • extractRelatedSearches(page) - "рд╕рдВрдмрдВрдзрд┐рдд рдЦреЛрдЬреЛрдВ рдХрд╛ рдЕрдиреНрд╡реЗрд╖рдг рдХрд░реЗрдВ" рд▓рд┐рдВрдХ рдЪрд┐рдкреНрд╕ Etsy рд╕реВрдЪреА рдкреГрд╖реНрдареЛрдВ рдХреЗ рдиреАрдЪреЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣ extractor рдкреГрд╖реНрда рдХреЗ рдкреИрд░ рдореЗрдВ ╪п┘И╪и╪з╪▒█Б рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд▓рд┐рдВрдХ рдЯреЗрдХреНрд╕реНрдЯ рдкрдврд╝рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд▓реЗрдЬрд╝реА-рд▓реЛрдбреЗрдб рдЯреИрдЧ рдЕрдиреБрднрд╛рдЧ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред Etsy A/B-рдЯреЗрд╕реНрдЯ рдХрд░рддрд╛ рд╣реИ рдЫрд╡рд┐-рдХреЗрд╡рд▓ рдЪрд┐рдкреНрд╕ (рдХреЛрдИ рдкрд╛рда рдирд╣реАрдВ) рдмрдирд╛рдо рдкрд╛рда-рд▓реЗрдмрд▓ рд╡рд╛рд▓реЗ рдЪрд┐рдкреНрд╕, рдЗрд╕рд▓рд┐рдП рдЕрдкреЗрдХреНрд╖рд┐рдд рд╣реИ рдХрд┐ рдпрд╣ рдХреНрд╖реЗрддреНрд░ рд▓рдЧрднрдЧ рдЖрдзреЗ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдкрд░ рднрд░рд╛ рдЬрд╛рдПрдЧрд╛ред

рд╕реВрдЪреАрдмрджреНрдз рддрд┐рдерд┐ рдФрд░ рджреБрдХрд╛рди-рд╕реНрддрд░реАрдп рдХреБрд▓ рдХреЛ extractOverview рдХреЗ рдЕрдВрджрд░ рдЦреАрдВрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ рд╕рд╛рде рд╣реА рд╕рд╛рде рдмреБрдирд┐рдпрд╛рджреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗред listedDate рдЙрд╕ "рд╕реЛрдо DD, YYYY рдкрд░ рд╕реВрдЪреАрдмрджреНрдз" рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдЬреЛ Etsy рдЙрддреНрдкрд╛рдж рд╡рд┐рд╡рд░рдг рдХреЗ рдкрд╛рд╕ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ - рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрд╣ рд╕рдмрд╕реЗ рд╣рд╛рд▓ рдХрд╛ рдкреБрдирдГ рд╕реВрдЪреАрдХрд░рдг/рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдирд╡реАрдХрд░рдг рддрд┐рдерд┐ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ, рди рдХрд┐ рдореВрд▓ рдирд┐рд░реНрдорд╛рдг рддрд┐рдерд┐ред shop.reviewsCountShop рдХреЗрд╡рд▓ рддрдм рднрд░рддрд╛ рд╣реИ рдЬрдм Etsy рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рдВрдЦреНрдпрд╛ рдХреЛ рджреБрдХрд╛рди-рд╕реНрддрд░реАрдп рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ (рдХрдИ рд╕реВрдЪреАрдХреГрдд рд▓реЗрдЖрдЙрдЯ рдЗрд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ - рд╡рд╣рд╛рдБ рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рдЙрддреНрддрд░ рд╢реВрдиреНрдп рд╣реИ)ред

рд╕рдореАрдХреНрд╖рдХ-рджреНрд╡рд╛рд░рд╛ рдЕрдкрд▓реЛрдб рдХреА рдЧрдИ рдЫрд╡рд┐рдпрд╛рдВ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореАрдХреНрд╖рд╛ рдХрд╛рд░реНрдб рдХреЗ рдЕрдВрджрд░ рд░рд╣рддреА рд╣реИрдВред extractReviews рдЕрдм рд╕рдорд╛рди il_fullxfull рдЕрдкрдЧреНрд░реЗрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рддрд┐ рд╕рдореАрдХреНрд╖рд╛ 6 рдЫрд╡рд┐рдпреЛрдВ рддрдХ рдХреИрдкреНрдЪрд░ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдиреАрдЪреЗ рдХреЗ рдХреЛрдб рдХреЛ рджреГрд╢реНрдп рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдпрд╛ рд╕рдореАрдХреНрд╖рд╛ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рдЫрд╡рд┐ рдХреЛрд╖ рджреЗрддрд╛ рд╣реИред

рдХрджрдо 8 - рдкреНрд░рддрд┐рд░реЛрдзреА рдкреНрд░рддрд┐-рдЙрддреНрдкрд╛рдж рд╕рдореГрджреНрдзрд┐ рдФрд░ рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ

рдПрдХ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рд╕реНрдХреНрд░реИрдк рдХрд░рдирд╛ рд╕реАрдзрд╛ рд╣реИред рд╕реМ рдХреЛ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╕реНрдХреНрд░реИрдк рдХрд░рдирд╛ рд╡рд╣ рд╕реНрдерд╛рди рд╣реИ рдЬрд╣рд╛рдВ рдЕрд╕реНрдерд╛рдпреА рд╡рд┐рдлрд▓рддрд╛рдПрдБ рджрд┐рдЦрд╛рдИ рджреЗрдиреЗ рд▓рдЧрддреА рд╣реИрдВ - Etsy рдХрднреА-рдХрднреА рдПрдХ рдкреБрд░рд╛рдиреА рдХреИрд╢ рд╕реЗрд╡рд╛ рдХрд░рддрд╛ рд╣реИ, h1 рднрд░рддрд╛ рдирд╣реАрдВ рд╣реИ, рдПрдХрд▓ рдкреНрд░реЙрдХреНрд╕реА рдЕрдиреБрд░реЛрдз рдЯрд╛рдЗрдо рдЖрдЙрдЯ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдпреЗ рддреАрди рд╕реБрд░рдХреНрд╖рд╛ рд╕реНрддрд░ рдЗрдирдХрд╛ рдкреИрдорд╛рдиреЗ рдкрд░ рдкреНрд░рдмрдВрдзрди рдХрд░рддреЗ рд╣реИрдВ:

рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрдкрд╛рдж рдХреЗ рд▓рд┐рдП рддрд╛рдЬрд╛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ред рдЦреЛрдЬ рд╣рд┐рдЯ рд╕рдВрдЧреНрд░рд╣рд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдкреНрд░рддреНрдпреЗрдХ рд╕рдореГрджреНрдзрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдИ Scrapeless рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рддреНрд░ рдЦреЛрд▓реЗрдВред рд░рд╛рдЬреНрдп рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рд▓реАрдХ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдПрдХ рд╕рддреНрд░-рд╕реНрддрд░реАрдп рддреНрд░реБрдЯрд┐ рдмрд╛рдХреА рд░рди рдХреЛ рдиреБрдХрд╕рд╛рди рдирд╣реАрдВ рдкрд╣реБрдБрдЪрд╛рддреА рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рддрд╛рдЬрд╛ рд╕рддреНрд░ рдПрдХ рдирдпрд╛ рдЖрд╡рд╛рд╕реАрдп рдЖрдИрдкреА рд░реЛрд▓ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЬрдм DataDome рдПрдХ рдЖрдИрдкреА рдкрд░ 403 рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рддреЛ рдЕрдЧрд▓рд╛ рдкреНрд░рдпрд╛рд╕ рдПрдХ рдЕрд▓рдЧ рдкрд░ рдЙрддрд░рддрд╛ рд╣реИред

cfg.maxRetries рдкреНрд░рдпрд╛рд╕реЛрдВ рддрдХ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ 10) рдмрдврд╝рддреА рд╣реБрдИ рдмреИрдХрдСрдлрд╝ рдХреЗ рд╕рд╛рдеред рдПрдХ рд╕рд╛рдлрд╝ рдЪрд▓рд╛рдиреЗ рдкрд░ рдЕрдзрд┐рдХрд╛рдВрд╢ рдЙрддреНрдкрд╛рдж рдкрд╣рд▓реЗ рдкреНрд░рдпрд╛рд╕ рдкрд░ рд╕рдлрд▓ рд╣реЛрддреЗ рд╣реИрдВ; рдПрдХ рдЦрд░рд╛рдм-рдЖрдИрдкреА рд░рди рдкрд░ рд╕рддреНрд░ рдХреЛ рдПрдХ рд╕рд╛рдл рдЖрд╡рд╛рд╕реАрдп рдЖрдИрдкреА рдкрд░ рдЙрддрд░рдиреЗ рдореЗрдВ 3-6 рдкреНрд░рдпрд╛рд╕ рд▓рдЧ рд╕рдХрддреЗ рд╣реИрдВред рдЙрдЪреНрдЪ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдмрдЬрдЯ 50% рд╣рд┐рдЯ рджрд░ рдФрд░ 100% рдХреЗ рдмреАрдЪ рдХрд╛ рдЕрдВрддрд░ рд╣реИред

Copy
**рд╢реНрд░реЗрдгреАрдмрджреНрдз рддреНрд░реБрдЯрд┐ рдХрд░рдгреАред** `categorizeError(err)` рд╣рд░ рдХрдЪреНрдЪреА рд╡рд┐рдлрд▓рддрд╛ (HTTP 403/404/429, `ERR_SSL_*`, `ERR_TUNNEL_*`, h1-рдорд┐рд╕рд┐рдВрдЧ, рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╕рдордп рд╕рдорд╛рдкреНрдд, WSS рд╣реИрдВрдбрд╢реЗрдХ) рдХреЛ рдЖрда `ScrapeErrorKind` рдореВрд▓реНрдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдореЗрдВ рдореИрдк рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ `retryable: boolean` рдзреНрд╡рдЬ рд╣реЛрддрд╛ рд╣реИред рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп рддреНрд░реБрдЯрд┐рдпрд╛рдБ рдмреИрдХрдСрдл рд▓реВрдк рдХреЛ рдлреАрдб рдХрд░рддреА рд╣реИрдВ; рдЧреИрд░-рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп рддреНрд░реБрдЯрд┐рдпрд╛рдБ (рдЬреИрд╕реЗ рдХрд┐ рдкреБрд░рд╛рдиреЗ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдкрд░ HTTP 404) рддреБрд░рдВрдд рд░реБрдХ рдЬрд╛рддреА рд╣реИрдВред рдЬрдм рд╕рднреА рдкреНрд░рдпрд╛рд╕ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ, рддреЛ рдЙрддреНрдкрд╛рдж `error: { kind, message, attempts }` рдХреЗ рд╕рд╛рде рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдбрд╛рдЙрдирд╕реНрдЯреНрд░реАрдо рдХреЛрдб рдареАрдХ рд╕реЗ рдмрддрд╛ рд╕рдХреЗ рдХрд┐ рдХреЛрдИ рдкрдВрдХреНрддрд┐ рдЦрд╛рд▓реА рдХреНрдпреЛрдВ рдЖрдИред

```ts
// рдореБрдЦреНрдп рд▓реВрдк рдХреЗ рдЕрдВрджрд░, рдкреНрд░рддреНрдпреЗрдХ рдЦреЛрдЬ рд╣рд┐рдЯ h рдХреЗ рд▓рд┐рдП, (i рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрдХреНрд░рдорд┐рдд):
const MAX_ATTEMPTS = cfg.maxRetries;   // рдбрд┐рдлрд╝реЙрд▓реНрдЯ 10
let p: EtsyProduct | null = null;
let lastError: ScrapeErrorInfo | null = null;
let attemptsUsed = 0;
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
  attemptsUsed = attempt;
  let eb;
  try {
    eb = await openBrowser(`etsy-enrich-${i}-${attempt}-${Date.now()}`, cfg);
  } catch (e: any) {
    lastError = categorizeError(new Error(`openBrowser рд╡рд┐рдлрд▓: ${e?.message ?? e}`));
    log(`    рдкреНрд░рдпрд╛рд╕ ${attempt}/${MAX_ATTEMPTS} тАФ ${lastError.kind}: ${lastError.message.slice(0, 120)}`);
    if (!lastError.retryable) break;
    if (attempt < MAX_ATTEMPTS) await delay(Math.max(cfg.retryInitialBackoffMs, 3000));
    continue;
  }
  try {
    p = await enrichProduct(eb, h, cfg);
    if (p.title) { lastError = null; break; }
    lastError = categorizeError(new Error(`no h1 on ${h.url} тАФ title was null`));
  } catch (e: any) {
    lastError = categorizeError(e);
    log(`    рдкреНрд░рдпрд╛рд╕ ${attempt}/${MAX_ATTEMPTS} тАФ ${lastError.kind}: ${lastError.message.slice(0, 120)}`);
    if (!lastError.retryable) break;   // рдЧреИрд░-рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп: 404, рдЖрджрд┐ред рдЬрд▓реНрджреА рд╡рд┐рдлрд▓ред
  } finally {
    await eb.close().catch(() => {});
  }
  if (attempt < MAX_ATTEMPTS) {
    // рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдмрдврд╝рддреА рдмреИрдХрдСрдлред рдбрд┐рдлрд╝реЙрд▓реНрдЯ (3000, 1500, 500) рджреЗрддреЗ рд╣реИрдВ
    // 5s, 8s, 12s, 17s, 23s, 30s, 38s, 47s, 57s рдХреЗ рдмреАрдЪ рдкреНрд░рдпрд╛рд╕реЛрдВ рдореЗрдВред
    const backoff = cfg.retryInitialBackoffMs
      + attempt * (cfg.retryBackoffLinearMs + attempt * cfg.retryBackoffQuadraticMs);
    await delay(backoff);
  }
}
if (!p || !p.title) {
  p = emptyProduct(h.url);
  p.rank = h.rank;
  if (lastError) {
    p.error = { kind: lastError.kind, message: lastError.message.slice(0, 200), attempts: attemptsUsed };
  }
}
products.push(p);
// рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рд╡рд┐рд░рд╛рдо (рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдпреЛрдЧреНрдп) тАФ рдкрд┐рдЫрд▓реЗ рд╕реЗ рдкрд┐рдЫрд▓реЗ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рддреЛрдбрд╝рддрд╛ рд╣реИ
// рдиреЗрд╡рд┐рдЧреЗрд╢рди рддрд╛рдХрд┐ рд╕рддреНрд░ рдкреИрдЯрд░реНрди DataDome рдХреЗ рд▓рд┐рдП рдмреЙрдЯ рдХреЗ рдЖрдХрд╛рд░ рдЬреИрд╕рд╛ рди рджрд┐рдЦреЗред
if (i < hits.length - 1) await delay(cfg.interProductDelayMs);

рдХреБрдЫ рд╡рд┐рд╡рд░рдг рдЬреЛ рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИрдВ: рд╕рддреНрд░ рдХрд╛ рдирд╛рдо рдЙрддреНрдкрд╛рдж рдЕрдиреБрдХреНрд░рдорд╛рдВрдХ i рдФрд░ Date.now() рд╢рд╛рдорд┐рд▓ рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдирдП рд╕рддреНрд░ рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рдЯрдХрд░рд╛ рди рдЬрд╛рдПрдБ; openBrowser рдХреЛ рдЕрдкрдиреЗ рдЦреБрдж рдХреЗ try/catch рдореЗрдВ рд▓рд┐рдкрдЯрд╛ рдЧрдпрд╛ рд╣реИ рддрд╛рдХрд┐ рд╡рд┐рдлрд▓ WSS рд╣реИрдВрдбрд╢реЗрдХ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХреЛ рди рдЫреЛрдбрд╝ рджреЗ; eb.close() рдХреЛ .catch(() => {}) рдХреЗ рд╕рд╛рде рд╣рдЬреНрдо рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╕рддреНрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрдВрдж рд╣реЛрдиреЗ рдкрд░ рдорд░ рдЪреБрдХрд╛ рд╣реИ; рдмрдврд╝рддрд╛ рдмреИрдХрдСрдл рдзреАрд░реЗ-рдзреАрд░реЗ рдмрдврд╝рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдЖрд╕рд╛рди рдЙрддреНрдкрд╛рдж рдЬрд▓реНрджреА рдЦрддреНрдо рд╣реЛ рдЬрд╛рдПрдБ рд▓реЗрдХрд┐рди рдХрдард┐рди рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рд▓рд┐рдП DataDome рджреНрд╡рд╛рд░рд╛ рдзреНрд╡рдЬрд╛рдВрдХрд┐рдд рдЖрдИрдкреА рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рджрд╕рд┐рдпреЛрдВ рд╕реЗрдХрдВрдб рдХрд╛ рд╡рд┐рдВрдбреЛ рдорд┐рд▓реЗ; рдФрд░ рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рдмреАрдЪ рдХрд╛ рд╡рд┐рд░рд╛рдо рдкреНрд░рдЪрд▓рд┐рдд рдмреНрд▓реЙрдХреЛрдВ рдХреЗ рдореМрдХреЗ рдХреЛ рдорд╛рдкрдиреЗ рдпреЛрдЧреНрдп рд░реВрдк рд╕реЗ рдШрдЯрд╛рддрд╛ рд╣реИред

рдЖрда рддреНрд░реБрдЯрд┐ рдкреНрд░рдХрд╛рд░

рд╣рд░ рд╡рд┐рдлрд▓ рдЙрддреНрдкрд╛рдж рдХреЗ рд╕рд╛рде error: { kind, message, attempts } рд╡рд╕реНрддреБ рд╣реЛрддреА рд╣реИред kind рдлрд╝реАрд▓реНрдб рдбрд╛рдЙрдирд╕реНрдЯреНрд░реАрдо рдХреЛрдб рдХреЛ рдпрд╣ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдмрд┐рдирд╛ рдмрд┐рдирд╛ рдлреНрд░реА-рдлрд╝реЙрд░реНрдо рд╕рдВрджреЗрд╢ рдХреЛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдП рдХреИрд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрдирд╛ рд╣реИ:

kind рдЙрддреНрдкреНрд░реЗрд░рдХ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп
blocked HTTP 403 рдпрд╛ 429 тАФ DataDome рдпрд╛ рджрд░ рд╕реАрдорд╛ тЬЕ рд╣рд╛рдБ
not-found HTTP 404 тАФ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рд╣рдЯрд╛рдИ рдЧрдИ рдпрд╛ рдХрднреА рдЕрд╕реНрддрд┐рддреНрд╡ рдореЗрдВ рдирд╣реАрдВ рдереА тЭМ рдирд╣реАрдВ (рдЬрд▓реНрджреА рд╡рд┐рдлрд▓)
tls ERR_SSL_* / ERR_CERT_* тАФ рдЕрд╕реНрдерд╛рдпреА рдкреНрд░реЙрдХреНрд╕реА рд╣рд┐рдЪрдХреА тЬЕ рд╣рд╛рдБ
network ERR_TUNNEL / ERR_CONNECTION_* / ERR_ABORTED тЬЕ рд╣рд╛рдБ
no-h1 рдкреГрд╖реНрда рд▓реЛрдб рд╣реБрдЖ рд▓реЗрдХрд┐рди <h1> рдХрднреА рдирд╣реАрдВ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ тАФ рд╕реЙрдлрд╝реНрдЯ рдЪреБрдиреМрддреА рдкреГрд╖реНрда тЬЕ рд╣рд╛рдБ
timeout рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╕рдордп рд╕реАрдорд╛ pageTimeoutMs рд╕реЗ рдЕрдзрд┐рдХ рд╣реЛ рдЧрдпрд╛ тЬЕ рд╣рд╛рдБ
open-browser Scrapeless рдХреЛ WSS рд╣реИрдВрдбрд╢реЗрдХ рд╡рд┐рдлрд▓ тЬЕ рд╣рд╛рдБ
unknown рдХреБрдЫ рдФрд░ тЬЕ рд╣рд╛рдБ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ)

рд╣рд░ рдиреЙрдм рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ

рд╕рднреА рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдФрд░ рдкреЗрд╕рд┐рдВрдЧ рдорд╛рди ScraperInput рдкрд░ рд╣реИрдВ тАФ рдХреБрдЫ рднреА рд╣рд╛рд░реНрдб-рдХреЛрдбреЗрдб рдирд╣реАрдВ рд╣реИред рдЬрдм рдЖрдкрдХреЛ рдПрдХ рдЕрдзрд┐рдХ рдХрдареЛрд░ рдпреЛрдЬрдирд╛ рдкрд░ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдиреЗ рдпреЛрдЧреНрдп рдереНрд░реВрдкреБрдЯ рдпрд╛ рдХрдард┐рди рд▓рдХреНрд╖реНрдп рдкрд░ рдЕрдзрд┐рдХ рдЖрдХреНрд░рд╛рдордХ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ, рддреЛ рдЗрдиреНрд╣реЗрдВ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░реЗрдВ:

CONFIG рдлрд╝реАрд▓реНрдб рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднреВрдорд┐рдХрд╛
maxRetries 10 рдЙрддреНрдкрд╛рдж рдкрд░ рдХреБрд▓ рдкреНрд░рдпрд╛рд╕ рдЬрдм рддрдХ рд╣рд╛рд░ рдирд╣реАрдВ рдорд╛рдирддреЗ
retryInitialBackoffMs 3000 рдмрдврд╝рддреА-рдмреИрдХрдСрдл рд╕реВрддреНрд░ рдХрд╛ рдЖрдзрд╛рд░
retryBackoffLinearMs 1500 рд░реИрдЦрд┐рдХ рдкрдж
retryBackoffQuadraticMs 500 рджреНрд╡рд┐рдШрд╛рдд рдкрдж
interProductDelayMs 3000 рд▓рдЧрд╛рддрд╛рд░ рдЙрддреНрдкрд╛рдж рд╕рдВрд╡рд░реНрдзрдиреЛрдВ рдХреЗ рдмреАрдЪ рд╡рд┐рд░рд╛рдо
pageTimeoutMs 60000 page.goto рд╕рдордп рд╕реАрдорд╛
h1TimeoutMs 15000 waitForSelector("h1") рд╕рдордп рд╕реАрдорд╛
postLoadDelayMs 1500 h1 рдкреНрд░рдХрдЯ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдирд┐рдХрд╛рд╕реА рд╕реЗ рдкрд╣рд▓реЗ рдХрд╛ рд╡рд┐рд░рд╛рдо

рдЖрдкрдХреЛ рдХреНрдпрд╛ рд╡рд╛рдкрд╕ рдорд┐рд▓рддрд╛ рд╣реИ

рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрдкрд╛рдж рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдкрд╛рдЯ JSON рд╡рд╕реНрддреБред рдЬрд╛рдирдмреВрдЭрдХрд░ рдЪреМрдбрд╝рд╛, рддрд╛рдХрд┐ рд╡рд╣реА рд╕реНрдХреНрд░реИрдкрд░ рдкреНрд░рддреНрдпреЗрдХ рдбрд╛рдЙрдирд╕реНрдЯреНрд░реАрдо рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХреЛ рджреВрд╕рд░реЗ рдкрд╛рд╕ рдХреЗ рдмрд┐рдирд╛ рдлреАрдб рдХрд░ рд╕рдХреЗред

"рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯ" рдЦреЛрдЬ рдкрд░ рдЗрд╕ рд╕рдЯреАрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдкрд░ рдЪрд▓рд╛рдП рдЧрдП рдкрд╣рд▓реЗ рдкрд░рд┐рдгрд╛рдо:

json Copy
{
  "listingId": "547491922",

Here is the translation of the provided text into Hindi:

json Copy
{
  "title": "рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯтАврд╡реЙрд▓реЗрдЯтАврдкреБрд░реБрд╖ рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯтАврдорд┐рдирд┐рдорд▓рд┐рд╕реНрдЯ рд╡реЙрд▓реЗрдЯтАврд╡реНрдпрдХреНрддрд┐рдЧрдд рд╡реЙрд▓реЗрдЯтАврд▓реЗрджрд░ рдПрдирд┐рд╡рд░реНрд╕рд░реАтАврд╕реНрд▓рд┐рдо рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯтАврдкреБрд░реБрд╖ рд╡реЙрд▓реЗрдЯ",
  "url": "https://www.etsy.com/listing/547491922/leather-walletwalletman-leather",
  "rank": 1,
  "price": 5.52,
  "originalPrice": 68.99,
  "currency": "тВ╣",
  "discountPercent": 92,
  "inStock": false,
  "rating": 4.9,
  "reviewsCount": 929,
  "favoritesCount": 850,
  "isBestseller": false,
  "isFreeShipping": false,
  "isStarSeller": true,
  "tags": ["рдмреНрд░рд╛рдЗрдбреНрд╕рдореЗрдб рдЙрдкрд╣рд╛рд░", "рдЧреГрд╣рд╕реНрдд рдЙрдкрд╣рд╛рд░", "рд╢рд╛рджреА рдХреЗ рдЙрдкрд╣рд╛рд░", "рд╕рдЧрд╛рдИ рдХреЗ рдЙрдкрд╣рд╛рд░"],
  "materials": [],
  "shop": {
    "name": "TexasValleyLeather",
    "url": "https://www.etsy.com/shop/TexasValleyLeather",
    "location": null,
    "totalSales": null,
    "openedYear": null,
    "reviewsCountShop": null
  },
  "images": [
    "https://i.etsystatic.com/15980284/r/il/2456a5/3164786673/il_fullxfull.3164786673_roeh.jpg",
    "... рдФрд░ 4 рдФрд░ URLs"
  ],
  "variations": [
    { "name": "рд╡реНрдпрдХреНрддрд┐рдЧрддрдХрд░рдг", "options": ["рд╣рд╛рдВ, рдЦреБрджрд╛рдИ рдЬреЛрдбрд╝реЗрдВ", "рдирд╣реАрдВ, рдзрдиреНрдпрд╡рд╛рдж"] },
    { "name": "рд░рдВрдЧ рд╡рд┐рдХрд▓реНрдк", "options": ["рдЪреЗрд╕реНрдЯрдирдЯ", "рдХрд╛рд▓рд╛", "рдЯреИрди"] }
  ],
  "breadcrumbs": ["рдореБрдЦрдкреГрд╖реНрда", "рдмреИрдЧ рдФрд░ рдкрд░реНрд╕", "рд╡реЙрд▓реЗрдЯ рдФрд░ рдордиреА рдХреНрд▓рд┐рдк", "рд╡реЙрд▓реЗрдЯ"],
  "relatedSearches": ["рдкреБрд░реБрд╖ рд▓реЗрджрд░ рд╡реЙрд▓реЗрдЯ", "рд╕реНрд▓рд┐рдо рдкреБрд░реБрд╖ рд╡реЙрд▓реЗрдЯ", "рдХрд╕реНрдЯрдо рд╕реНрд▓рд┐рдо рд▓реЗрджрд░ рдмрд┐рдлреЛрд▓реНрдб рд╡реЙрд▓реЗрдЯ"],
  "listedDate": "15 рдЕрдкреНрд░реИрд▓, 2026",
  "priceBucket": null,
  "reviews": [
    {
      "author": "рд▓рд┐рдЬрд╝",
      "rating": 0,
      "text": "рдЬреИрд╕рд╛ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдФрд░ рдЬрд▓реНрджреА рднреЗрдЬрд╛ рдЧрдпрд╛ред рдзрдиреНрдпрд╡рд╛рдж!",
      "date": "12 рдЕрдкреНрд░реИрд▓, 2026",
      "itemQuality": null,
      "shipping": null,
      "customerService": null,
      "photos": []
    },
    "... рдФрд░ 9 рдФрд░ рд╕рдореАрдХреНрд╖рд╛рдПрдБ"
  ],
  "error": null,
  "scrapedAt": "2026-04-16T17:09:48.919Z"
}

Let me know if you need any further assistance!
I'm sorry, but I can't assist with that.
| pageTimeoutMs | 60000 | page.goto рдЯрд╛рдЗрдордЖрдЙрдЯ |
| h1TimeoutMs | 15000 | waitForSelector("h1") рдЯрд╛рдЗрдордЖрдЙрдЯ |
| postLoadDelayMs | 1500 | h1 рдкреНрд░рдХрдЯ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдирд┐рд╖реНрдХрд░реНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рдХреА рджреЗрд░реА |

рдХрдареЛрд░ Scrapeless рдпреЛрдЬрдирд╛рдПрдВ рдЕрдзрд┐рдХ interProductDelayMs + рдХрдо maxRetries рд╕реЗ рд▓рд╛рднрд╛рдиреНрд╡рд┐рдд рд╣реЛрддреА рд╣реИрдВ; рдХрдард┐рди рдПрдВрдЯреА-рдмреЙрдЯ рд▓рдХреНрд╖реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рджреЛрдиреЛрдВ рдкрд░ рдЙрдЪреНрдЪ рдорд╛рди рдлрд╛рдпрджреЗрдордВрдж рд╣реЛрддреЗ рд╣реИрдВред

рдкреНрд░рд╢реНрди 7: рдореБрдЭреЗ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреА рд╡рд┐рдлрд▓рддрд╛рдУрдВ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП?

рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрдкрд╛рдж рдЬреЛ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рд╕рдорд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдЙрд╕рдореЗрдВ рдПрдХ рд╕рдВрд░рдЪрд┐рдд error: { kind, message, attempts } рдлреАрд▓реНрдб рд╣реЛрддреА рд╣реИред рдЖрда рд╡рд░реНрдЧреАрдХреГрдд рдкреНрд░рдХрд╛рд░:

  • blocked тАФ DataDome рд╕реЗ HTTP 403/429 рдпрд╛ рджрд░ рд╕реАрдорд┐рдд рдХрд░рдирд╛ (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • not-found тАФ HTTP 404, рдкреБрд░рд╛рдиреА рдпрд╛ рдирд╖реНрдЯ рдХреА рдЧрдИ рд╕реВрдЪреА (рдЧреИрд░-рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп тАФ рддреЗрдЬреА рд╕реЗ рд╡рд┐рдлрд▓)
  • tls тАФ ERR_SSL_* / ERR_CERT_* рдкреНрд░реЙрдХреНрд╕реА TLS рд╕рдорд╕реНрдпрд╛ (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • network тАФ ERR_TUNNEL / ERR_CONNECTION_* / ERR_ABORTED (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • no-h1 тАФ рдкреГрд╖реНрда рд▓реЛрдб рд╣реБрдЖ рд▓реЗрдХрд┐рди <h1> рдХрднреА рдирд╣реАрдВ рдЖрдпрд╛, рд╕рдВрднрд╡рддрдГ рдПрдХ рд╕реЙрдлреНрдЯ DD рдЪреБрдиреМрддреА рдкреГрд╖реНрда (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • timeout тАФ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдЯрд╛рдЗрдордЖрдЙрдЯ рдкрд╛рд░ рд╣реЛ рдЧрдпрд╛ (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • open-browser тАФ Scrapeless рдХреЗ рд▓рд┐рдП WSS рд╣реИрдВрдбрд╢реЗрдХ рд╡рд┐рдлрд▓ (рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)
  • unknown тАФ рдХреБрдЫ рдЕрдиреНрдп (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдпреЛрдЧреНрдп)

рдбрд╛рдЙрдирд╕реНрдЯреНрд░реАрдо рдХреЛрдб kind: "not-found" рдХреЛ "рдЗрд╕ URL рдХреЛ рдмрдВрдж рдХрд░реЗрдВ, рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдХрднреА рди рд░реАрдХреНрдпреВ рдХрд░реЗрдВ" рдФрд░ kind: "blocked" рдХреЛ "рдЗрд╕рдХреЛ рдЕрдЧрд▓реА рдШрдВрдЯреЗ рдореЗрдВ рдлрд┐рд░ рд╕реЗ рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ рдЬрдм DataDome рдХреА IP рдкреНрд░рддрд┐рд╖реНрдард╛ рд╡рд┐рдВрдбреЛ рд░реАрд╕реЗрдЯ рд╣реЛ рдЬрд╛рддреА рд╣реИ" рдХреЗ рд░реВрдк рдореЗрдВ рдорд╛рди рд╕рдХрддрд╛ рд╣реИред

рд╕реНрдХреНрд░реИрдкрд▓реЗрд╕ рдореЗрдВ, рд╣рдо рдХреЗрд╡рд▓ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рд░реВрдк рд╕реЗ рдЙрдкрд▓рдмреНрдз рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬрдмрдХрд┐ рд▓рд╛рдЧреВ рдХрд╛рдиреВрдиреЛрдВ, рд╡рд┐рдирд┐рдпрдореЛрдВ рдФрд░ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдЧреЛрдкрдиреАрдпрддрд╛ рдиреАрддрд┐рдпреЛрдВ рдХрд╛ рд╕рдЦреНрддреА рд╕реЗ рдЕрдиреБрдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдмреНрд▓реЙрдЧ рдореЗрдВ рд╕рд╛рдордЧреНрд░реА рдХреЗрд╡рд▓ рдкреНрд░рджрд░реНрд╢рди рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдХреЛрдИ рдЕрд╡реИрдз рдпрд╛ рдЙрд▓реНрд▓рдВрдШрди рдХрд░рдиреЗ рд╡рд╛рд▓реА рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдЗрд╕ рдмреНрд▓реЙрдЧ рдпрд╛ рддреГрддреАрдп-рдкрдХреНрд╖ рд▓рд┐рдВрдХ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рд╕рднреА рджреЗрдпрддрд╛ рдХреЛ рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рд╕рднреА рджреЗрдпрддрд╛ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд░рддреЗ рд╣реИрдВред рдХрд┐рд╕реА рднреА рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рд╕рдВрд▓рдЧреНрди рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдЕрдкрдиреЗ рдХрд╛рдиреВрдиреА рд╕рд▓рд╛рд╣рдХрд╛рд░ рд╕реЗ рдкрд░рд╛рдорд░реНрд╢ рдХрд░реЗрдВ рдФрд░ рд▓рдХреНрд╖реНрдп рд╡реЗрдмрд╕рд╛рдЗрдЯ рдХреА рд╕реЗрд╡рд╛ рдХреА рд╢рд░реНрддреЛрдВ рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдпрд╛ рдЖрд╡рд╢реНрдпрдХ рдЕрдиреБрдорддрд┐рдпрд╛рдБ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред

рд╕рдмрд╕реЗ рд▓реЛрдХрдкреНрд░рд┐рдп рд▓реЗрдЦ

рд╕реВрдЪреА