рдИрдЯреАрд╕реА рд╕реНрдХреНрд░реИрдкрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░реИрдкрд▓реЗрд╕ рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: рд╡реНрдпрд╛рдкрдХ рдорд╛рд░реНрдЧрджрд░реНрд╢рд┐рдХрд╛ 2026 (рдиреЛрдб.рдЬреЗрдПрд╕)
Scraping and Proxy Management Expert
рдореБрдЦреНрдп рдирд┐рд╖реНрдХрд░реНрд╖:
- рд╕реНрдХреНрд░реЗрдкрд▓реЗрд╕ рд╕реНрдХреНрд░реЗрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдПрдЖрдИ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдПрдЯреАрд╕реА рдХреЗ 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 рд╡рд╛рдгрд┐рдЬреНрдпрд┐рдХ рдЙрдкрдпреЛрдЧ рджрд┐рдП рдЧрдП рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рд╕рдорд╛рди рдХреЛрдбрдмреЗрд╕ рд╕реЗ рдкреВрд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЕрдХреНрд╕рд░ рдХреЗрд╡рд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреЗ рд╕рд╛рде:
- рдбреНрд░реЙрдкрд╢рд┐рдкрд┐рдВрдЧ рдЕрдиреБрд╕рдВрдзрд╛рди рдФрд░ рдЙрддреНрдкрд╛рдж рдЦреЛрдЬрдирд╛ тАФ рдХреАрд╡рд░реНрдб-рдЦреЛрдЬ рдореЛрдбред рд╕реНрдХреНрд░реЗрдкрд░ рдХреЛ
"рдореИрдХреНрд░реЗрдореЗ рдкреНрд▓рд╛рдВрдЯ рд╣реИрдВрдЧрд░"рдкрд░ рдЪрд▓рд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВexpandStrategy: "keywords"рд╣реЛ["boho", "modern", "minimalist"]рдореЗрдВ,maxProducts: 200рд╕реЗрдЯ рдХрд░реЗрдВ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЛfavoritesCount ├Ч ratingрджреНрд╡рд╛рд░рд╛ рд░реИрдВрдХ рдХрд░реЗрдВред рдЙрди рджреБрдХрд╛рдиреЛрдВ рдХреЛ рдЫрд╛рдиреЗрдВ рдЬрд╣рд╛рдВisStarSeller: trueрд╣реИ рдФрд░ favoritesCount рдХрд╛рдлреА рдЕрдзрд┐рдХ рд╣реИ тАФ рд╡реЗ рдЖрдкрдХреЗ рдбреНрд░реЙрдкрд╢рд┐рдкрд┐рдВрдЧ рдЙрдореНрдореАрджрд╡рд╛рд░ рд╣реИрдВред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк CSV рдХреЛ рд╢реЙрдкрд┐рдлрд╛рдИ рдпрд╛ рдПрдХ рдирд┐рдЬреА рд╕рдкреНрд▓рд╛рдпрд░ рд╕реВрдЪреА рдореЗрдВ рдбрд╛рд▓реЗрдВред рдпрд╣ рдПрдЯреАрд╕реА рдХреЛ рд╕реНрдХреНрд░реЗрдк рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рдХрд╛рд░рдг рд╣реИ рдФрд░ рд░рд╛рдЬрд╕реНрд╡ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рддреЗрдЬрд╝ рд╣реИред - рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд┐рдпреЛрдВ рдХреА рдореВрд▓реНрдп рдирд┐рдЧрд░рд╛рдиреА тАФ рдЙрддреНрдкрд╛рдж-URL (рдкреНрд░рддреНрдпрдХреНрд╖-URL) рдореЛрдбред
startUrlsрдореЗрдВ рдкреНрд░рддрд┐рдпреЛрдЧреА рд╕реВрдЪреА URLs рдХреА рдПрдХ рд╕реВрдЪреА рд░рдЦреЗрдВ рдФрд░ рд╕реНрдХреНрд░реЗрдкрд░ рдХреЛ рд░рд╛рдд рдореЗрдВ рдЪрд▓рд╛рдПрдВред рдкреНрд░рддреНрдпреЗрдХ JSON рд╕реНрдиреИрдкрд╢реЙрдЯ рдХреЛ рдЙрд╕рдХреЗscrapedAtрдЯрд╛рдЗрдорд╕реНрдЯрд╛рдореНрдк рдХреЗ рд╕рд╛рде рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░реЗрдВ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд░рди рдХреЗ рдмреАрдЪprice,originalPrice,discountPercentрдФрд░inStockрдХрд╛ рдЕрдВрддрд░ рдирд┐рдХрд╛рд▓реЗрдВред рдореВрд▓реНрдп рдореЗрдВ 10% рд╕реЗ рдЕрдзрд┐рдХ рдЧрд┐рд░рд╛рд╡рдЯ? рд╕реНрд▓реИрдХ рдЕрд▓рд░реНрдЯредinStocktrueрд╕реЗfalseрдореЗрдВ рдмрджрд▓рддрд╛ рд╣реИ? рдЗрд╕реЗ рдПрдХ рдЖрдкреВрд░реНрддрд┐ рд╕рдВрдХреЗрдд рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВред рдЗрд╕ рддрд░реАрдХреЗ рд╕реЗ рдЖрдк рдЬреЛ рдкреВрд░реНрдг рдореВрд▓реНрдп рдЗрддрд┐рд╣рд╛рд╕ рдмрдирд╛рддреЗ рд╣реИрдВ рд╡рд╣ рд╣рд░ рдкреНрд░рддрд┐рдпреЛрдЧреА-рдЗрдВрдЯреЗрд▓ рдбреИрд╢рдмреЛрд░реНрдб рдХрд╛ рдореБрдЦреНрдп рдЖрдзрд╛рд░ рд╣реИред - рдХреАрд╡рд░реНрдб рдФрд░ рдкреНрд░рд╡реГрддреНрддрд┐ рдЕрдиреБрд╕рдВрдзрд╛рди тАФ рдлрд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рд╢реНрд░реЗрдгреА-URL рдореЛрдбред
categoryUrlрдХреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдПрдЯреАрд╕реА рд╢реНрд░реЗрдгреА рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░реЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП/c/bags-and-purses/wallets-and-money-clips/wallets), рдлрд╝рд┐рд▓реНрдЯрд░ рд╕рдВрдпреЛрдЬрдиреЛрдВ (filters.onSale: true,filters.condition: "new",filters.orderBy: "date_desc") рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдХреБрдЫ рд╕реМ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВtagsрдФрд░materialsрдХреЛ рдЦреАрдВрдЪреЗрдВ, рдЙрдирдХреА рдЖрд╡реГрддреНрддрд┐ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ рдФрд░ рдЙрд╕ рдЯреИрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдкрд░favoritesCountрдХреЗ рдпреЛрдЧ рджреНрд╡рд╛рд░рд╛ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВред рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдмрдирд╛рдП рдЧрдП рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ рджрд┐рдЦрдиреЗ рд╡рд╛рд▓реЗ рдЯреИрдЧ рд▓реЗрдХрд┐рди рдкреБрд░рд╛рдиреЗ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ рдирд╣реАрдВ рд╣реИрдВ рдЖрдкрдХреЗ рдЙрднрд░рддреЗ рдЙрдк-рдирд┐рдЪреЗ рд╣реИрдВред - рдПрдбрд╡рд╛рдВрд╕ рдорд╛рд░реНрдХреЗрдЯ рд░рд┐рд╕рд░реНрдЪ рдФрд░ рдПрдордПрд▓ рдХреЗ рд▓рд┐рдП рд╕рдореАрдХреНрд╖рд╛ рд╕рдВрдЧреНрд░рд╣рдг тАФ рдХреАрд╡рд░реНрдб рдпрд╛ рд╢реНрд░реЗрдгреА рдореЛрдбред рд╣рдЬрд╛рд░реЛрдВ рд╕реВрдЪреАрдХрд░рдгреЛрдВ рдореЗрдВ
reviews[]рдХреЛ рд╕реНрдХреНрд░реЗрдк рдХрд░реЗрдВ (рд╣реИрдВрдбрдореЗрдб рдореЛрдордмрддреНрддрд┐рдпрд╛рдБ, рдЬреИрд╕реЗ рдХрд┐, рдпрд╛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЧрд╣рдиреЗ),reviews[].textрдХреЛ рдПрдХ рднрд╛рд╡рдирд╛ рд╡рд░реНрдЧреАрдХрд░рдгрдХрд░реНрддрд╛ рдореЗрдВ рдлреАрдб рдХрд░реЗрдВ рдФрд░ рдЬрдм рд╡реЗ рдореМрдЬреВрдж рд╣реЛрдВ рддреЛitemQuality/shipping/customerServiceрдЙрдк-рд░реЗрдЯрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕реБрдкрд░рд╡рд╛рдЗрдЬреНрдб рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд▓реЗрдмрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд░реЗрдВред рдкреНрд░рддрд┐-рд░рд┐рд╡реНрдпреВ рдЫрд╡рд┐рдпрд╛рдВ (reviews[].photos[]) рдЖрдкрдХреЛ рдПрдХ рд╕рдорд╛рди рдЫрд╡рд┐ рдХреЙрд░реНрдкрд╕ рджреЗрддреА рд╣реИрдВ рдпрджрд┐ рдЖрдкрдХреЛ рджреГрд╢реНрдп рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдбреЗрдЯрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛред - рджреБрдХрд╛рди рдкреНрд░рджрд░реНрд╢рди рдорд╛рдирдХреАрдХрд░рдг тАФ рджреБрдХрд╛рди-рдпреВрдЖрд░рдПрд▓ рдореЛрдбред
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
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:
SCRAPELESS_API_KEY=your_key_here
рдЪрд░рдг 1 тАФ рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ
рд╕рдВрдкреВрд░реНрдг рд╕реНрдХреНрд░реИрдкрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдиреЗрдХреНрд╢рди рд╕рд╣рд╛рдпрдХред рдЯреЛрдХрди, рджреЗрд╢ рдФрд░ TTL рдХреЗ рд╕рд╛рде рдПрдХ WSS URL рдмрдирд╛рдПрдБ, рдлрд┐рд░ рдЗрд╕реЗ puppeteer.connect рдХреЛ рджреЗрдВред
ts
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
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
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
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
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
const CONFIG: ScraperInput = {
searchQuery: "leather wallet",
expandStrategy: "keywords", // "none" | "keywords" | "prices"
expandKeywords: ["mens", "womens", "vintage"], // рд╡реГрджреНрдзрд┐ = рдХреАрд╡рд░реНрдб рд╣реЛрдиреЗ рдкрд░ рдмреЗрд╕ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ
maxProducts: 20,
};
рджреБрдХрд╛рди URL рдореЛрдб - рдмреЗрдВрдЪрдорд╛рд░реНрдХрд┐рдВрдЧ / рдкреНрд░рддрд┐рдпреЛрдЧреА рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рджреБрдХрд╛рди рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗрдВ:
ts
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
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
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
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
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
// рд╕реНрдерд┐рддрд┐ рдмреИрдЬ - рдкреГрд╖реНрда рдХреЗ рд╢рд░реАрд░ рдХреЗ рд▓рд┐рдП 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
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:
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
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% рдХреЗ рдмреАрдЪ рдХрд╛ рдЕрдВрддрд░ рд╣реИред
**рд╢реНрд░реЗрдгреАрдмрджреНрдз рддреНрд░реБрдЯрд┐ рдХрд░рдгреАред** `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
{
"listingId": "547491922",
Here is the translation of the provided text into Hindi:
json
{
"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 рдкреНрд░рддрд┐рд╖реНрдард╛ рд╡рд┐рдВрдбреЛ рд░реАрд╕реЗрдЯ рд╣реЛ рдЬрд╛рддреА рд╣реИ" рдХреЗ рд░реВрдк рдореЗрдВ рдорд╛рди рд╕рдХрддрд╛ рд╣реИред
рд╕реНрдХреНрд░реИрдкрд▓реЗрд╕ рдореЗрдВ, рд╣рдо рдХреЗрд╡рд▓ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рд░реВрдк рд╕реЗ рдЙрдкрд▓рдмреНрдз рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬрдмрдХрд┐ рд▓рд╛рдЧреВ рдХрд╛рдиреВрдиреЛрдВ, рд╡рд┐рдирд┐рдпрдореЛрдВ рдФрд░ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдЧреЛрдкрдиреАрдпрддрд╛ рдиреАрддрд┐рдпреЛрдВ рдХрд╛ рд╕рдЦреНрддреА рд╕реЗ рдЕрдиреБрдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдмреНрд▓реЙрдЧ рдореЗрдВ рд╕рд╛рдордЧреНрд░реА рдХреЗрд╡рд▓ рдкреНрд░рджрд░реНрд╢рди рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдХреЛрдИ рдЕрд╡реИрдз рдпрд╛ рдЙрд▓реНрд▓рдВрдШрди рдХрд░рдиреЗ рд╡рд╛рд▓реА рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдЗрд╕ рдмреНрд▓реЙрдЧ рдпрд╛ рддреГрддреАрдп-рдкрдХреНрд╖ рд▓рд┐рдВрдХ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рд╕рднреА рджреЗрдпрддрд╛ рдХреЛ рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рд╕рднреА рджреЗрдпрддрд╛ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд░рддреЗ рд╣реИрдВред рдХрд┐рд╕реА рднреА рд╕реНрдХреНрд░реИрдкрд┐рдВрдЧ рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рд╕рдВрд▓рдЧреНрди рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдЕрдкрдиреЗ рдХрд╛рдиреВрдиреА рд╕рд▓рд╛рд╣рдХрд╛рд░ рд╕реЗ рдкрд░рд╛рдорд░реНрд╢ рдХрд░реЗрдВ рдФрд░ рд▓рдХреНрд╖реНрдп рд╡реЗрдмрд╕рд╛рдЗрдЯ рдХреА рд╕реЗрд╡рд╛ рдХреА рд╢рд░реНрддреЛрдВ рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдпрд╛ рдЖрд╡рд╢реНрдпрдХ рдЕрдиреБрдорддрд┐рдпрд╛рдБ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред



