Scrape Mercado Livre Search Results

Site lista.mercadolivre.com.brTask scrape-search-resultsVersion v12Updated Sep 9, 2026Category shopping

Navigate directly to Mercado Livre Brasil keyword-result URLs and extract deduplicated product cards, including prices, shipping, seller, ratings, and review counts, with optional filtering and sorting. This skill was captured from a live agent session on lista.mercadolivre.com.br and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Collect structured product listings from Mercado Livre Brasil search-result pages using the site's slug-based search URL and resilient selectors covering current Poly cards and legacy UI Search layouts. The extractor captures title, URL, image, current and original prices, installments, discount labels, seller, official-store status, shipping, badges, rating, review count, condition, and sold-count text. It deduplicates products and can optionally limit results, filter titles, restrict official stores, or sort by numeric current price.

Use Cases

Use for a keyword or phrase when the required output is the product cards displayed on the corresponding Mercado Livre Brasil results page. By default, return the first 20 deduplicated organic product cards; set maxResults to null when the caller needs every loaded result. For lowest-price requests, provide a model-specific titlePattern and set sortByPrice to true. Set officialStoreOnly to true when official-store listings alone are requested. The workflow is page-local and does not resolve product IDs or open individual product pages.

Automation Flow

  1. Build the direct URL as https://lista.mercadolivre.com.br/{normalized-query}: lowercase {query}, replace whitespace runs with hyphens, and URL-encode the path segment. Append ?sb=all_mercadolibre for the all-Mercado-Libre scope when requested.
  2. In one browser call, navigate with waitUntil: "domcontentloaded", wait about 2 seconds for cards, and execute the evaluator below. Set officialStoreOnly, titlePattern, sortByPrice, and maxResults according to the request. The default maxResults=20 returns the first 20 organic cards in page order.
(()=>{
const officialStoreOnly=false,titlePattern=null,sortByPrice=false,maxResults=20;
const clean=s=>(s||'').replace(/\s+/g,' ').trim();
const abs=u=>{try{return new URL(u,location.href).href}catch{return u||''}};
const text=(e,ss)=>{for(const s of ss){const v=clean(e.querySelector(s)?.textContent);if(v)return v}return ''};
const attr=(e,ss,as)=>{for(const s of ss){const n=e.querySelector(s);if(!n)continue;for(const a of as){let v=n.getAttribute(a);if(v)return a==='srcset'?abs(v.split(',')[0].trim().split(/\s+/)[0]):abs(v)}}return ''};
const money=(e,ss)=>{for(const s of ss){const n=e.querySelector(s);if(!n)continue;const f=clean(n.querySelector('.andes-money-amount__fraction')?.textContent),c=clean(n.querySelector('.andes-money-amount__cents')?.textContent||'00');if(f){const v=parseFloat(f.replace(/\./g,'').replace(',','.')+'.'+c.replace(/\D/g,''));if(Number.isFinite(v))return v}}return null};
const selectors=['li.ui-search-layout__item','.ui-search-result__wrapper','.poly-card','.andes-card'];
const cards=[...new Set(selectors.flatMap(s=>[...document.querySelectorAll(s)]))];
let re=null;try{re=titlePattern?new RegExp(titlePattern,'i'):null}catch{}
const products=cards.map(card=>{const te=card.querySelector('a.poly-component__title,h2.ui-search-item__title,.ui-search-item__title,[class*="title"] a,a[href*="/MLB-"]');const link=te?.closest('a')||card.querySelector('a[href*="mercadolivre.com.br/MLB"],a[href*="/MLB-"]');const title=clean(te?.textContent||card.querySelector('h2,h3')?.textContent);if(!title||!link||re&&!re.test(title))return null;const seller=text(card,['.poly-component__seller','.ui-search-item__group__element [class*="seller"]','[class*="seller"]']);const official=!!card.querySelector('.poly-component__seller svg[aria-label="Loja oficial"],[aria-label*="Loja oficial" i]')||/loja oficial/i.test(seller)||/loja oficial/i.test(clean(card.textContent));return{title,url:abs(link.href),image:attr(card,['.poly-component__picture','img','picture source'],['src','data-src','data-lazy-src','srcset']),priceCurrent:money(card,['.poly-price__current','.ui-search-price__part']),priceCurrentFull:text(card,['.poly-price__current','.ui-search-price__part']),priceOriginal:money(card,['.poly-price__previous','.poly-price__labels','.andes-money-amount--previous']),installments:text(card,['.poly-price__installments','.ui-search-installments']),discount:text(card,['.poly-price__discount-polylabel','.poly-price__label','.ui-search-price__second-line']),seller,isOfficialStore:official,shipping:text(card,['.poly-component__shipping-v2','.poly-component__shipping','.ui-search-item__shipping','[class*="shipping"]']),rating:text(card,['.poly-reviews__rating','.ui-search-reviews__rating','.poly-component__review-compacted','[class*="rating"]']),reviews:text(card,['.poly-reviews__total','.ui-search-reviews__amount','.poly-component__review-compacted','[class*="reviews"]']),badges:[...card.querySelectorAll('.polylabel-pill,.polylabel-label,.ui-search-item__highlight-label,[class*="badge"]')].map(x=>clean(x.textContent)).filter(Boolean),condition:text(card,['.poly-component__condition','[class*="condition"]']),sold:text(card,['.poly-component__sold-quantity','[class*="sold"]','[class*="quantity"]'])}}).filter(Boolean);
const seen=new Set(),unique=products.filter(p=>!seen.has(p.url)&&seen.add(p.url));let result=officialStoreOnly?unique.filter(p=>p.isOfficialStore):unique;if(sortByPrice)result.sort((a,b)=>(typeof a.priceCurrent==='number'?a.priceCurrent:Infinity)-(typeof b.priceCurrent==='number'?b.priceCurrent:Infinity));if(Number.isInteger(maxResults)&&maxResults>=0)result=result.slice(0,maxResults);return{url:location.href,title:document.title,bodyLength:document.body.innerHTML.length,cardCount:cards.length,officialStoreOnly,titlePattern,sortByPrice,maxResults,products:result,lowestPriceProduct:sortByPrice?result[0]||null:null};
})()

Possible Friction Points

  • The direct search endpoint is /{hyphenated-query}; do not visit the homepage or type into the search box first.
  • ?sb=all_mercadolibre selects the observed all-Mercado-Libre scope; it is not itself an official-store filter.
  • The default result limit is 20, preserving page order after URL deduplication. Set maxResults to null for all loaded cards.
  • For model-specific searches, supply a caller-generated regular expression matching the requested model; do not hard-code a particular product or title in the skill.
  • Official-store status is commonly marked by an SVG with aria-label="Loja oficial", but card/seller text fallbacks are also used and should be treated as page markers rather than definitive seller identity when markup is absent.
  • Preserve Poly and UI Search selectors because Mercado Livre may serve different card layouts. Deduplicate by canonical product URL.
  • Prices and other labels are localized text. Numeric prices are returned when the amount markup is parseable; displayed text remains available in the full-text fields.
  • The evaluator extracts only cards present in the loaded result page; it does not infer products hidden behind pagination or infinite scrolling.
  • If cards are absent, inspect the same session for an anti-bot or consent interstitial and wait/retry; no separate bypass endpoint is established.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=lista.mercadolivre.com.br&task=scrape-search-results