<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan</title>
    <description>The latest articles on DEV Community by Ivan (@ivanpilipnev).</description>
    <link>https://dev.to/ivanpilipnev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4230015%2F8279e61a-bfd3-48c2-917f-0c22878147e3.png</url>
      <title>DEV Community: Ivan</title>
      <link>https://dev.to/ivanpilipnev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivanpilipnev"/>
    <language>en</language>
    <item>
      <title>How to Scrape SHEIN Products with Python</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Fri, 06 Nov 2026 14:39:10 +0000</pubDate>
      <link>https://dev.to/ivanpilipnev/how-to-scrape-shein-products-with-python-26ii</link>
      <guid>https://dev.to/ivanpilipnev/how-to-scrape-shein-products-with-python-26ii</guid>
      <description>&lt;p&gt;A product's headline price is only part of the information needed for a useful shortlist. Currency, availability and the number of reviews can change which items are worth inspecting. This tutorial shows how to scrape SHEIN products into JSON or CSV, then turn the results into a small spreadsheet of in-stock products priced below $20 with a rating of at least 4.5.&lt;/p&gt;

&lt;p&gt;The tool is &lt;a href="https://github.com/2scraper/shein-scraper" rel="noopener noreferrer"&gt;2scraper/shein-scraper&lt;/a&gt;, an MIT-licensed Python project. The example below uses its bundled sample data so you can try the filtering step without making a live request. Those records are dated September 30, 2026; they are not current prices or results from a new test.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to scrape SHEIN products into a budget shortlist
&lt;/h2&gt;

&lt;p&gt;Use the Playwright engine to collect a small search result from &lt;code&gt;us.shein.com&lt;/code&gt;. Save the records as JSON, inspect the run's metadata, and filter products by currency, stock, price and rating. Export that selection to CSV. Treat it as a snapshot of the collected products, not a complete catalogue or variant inventory.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Python 3.9 or newer and clone the repository.&lt;/li&gt;
&lt;li&gt;Install the Playwright dependencies and Chromium.&lt;/li&gt;
&lt;li&gt;Configure any credentials in &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run one search with a small result limit.&lt;/li&gt;
&lt;li&gt;Check the exit code and the accompanying metadata file.&lt;/li&gt;
&lt;li&gt;Filter the JSON records and write a shortlist to CSV.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Install once, collect a small search
&lt;/h2&gt;

&lt;p&gt;The repository recommends Playwright. Use a separate virtual environment for it: the project's Playwright, Selenium and Puppeteer dependency sets should not be installed together.&lt;/p&gt;

&lt;p&gt;These setup commands are from the README and use a Bash-compatible shell, such as Linux, macOS or WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/2scraper/shein-scraper.git
&lt;span class="nb"&gt;cd &lt;/span&gt;shein-scraper
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements-playwright.txt
playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file contains &lt;code&gt;TWOCAPTCHA_KEY&lt;/code&gt; for CAPTCHA solving, &lt;code&gt;SHEIN_CDP_ENDPOINT&lt;/code&gt; for a remote browser profile, and &lt;code&gt;SHEIN_PROXY&lt;/code&gt; for an optional proxy. Add only the values you use. Keep credentials out of commands, screenshots and published files.&lt;/p&gt;

&lt;p&gt;A local browser can start without a CAPTCHA key, but that does not mean it will get product data: SHEIN may challenge or rate-limit it. For regular use, the README recommends a 2Captcha Scraping Browser API profile plus a solver key. Browser access and CAPTCHA solving are separate services.&lt;/p&gt;

&lt;p&gt;For a small search, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 playwright_scraper.py &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"linen shirt"&lt;/span&gt; &lt;span class="nt"&gt;--max-results&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query is an example input, not a claim that it was tested for this article. When rows are written, the default files are &lt;code&gt;shein_results.json&lt;/code&gt; and &lt;code&gt;shein_results.json.meta.json&lt;/code&gt;. The second file describes the run, including its status and why it stopped.&lt;/p&gt;

&lt;p&gt;To request CSV directly, use the documented output options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 playwright_scraper.py &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"linen shirt"&lt;/span&gt; &lt;span class="nt"&gt;--max-results&lt;/span&gt; 20 &lt;span class="nt"&gt;--format&lt;/span&gt; csv &lt;span class="nt"&gt;--out&lt;/span&gt; linen-shirts.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is another collection run, not a conversion of the previous JSON file. For an offline conversion and filter, use the Python example further down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each input actually returns
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Where the data comes from&lt;/th&gt;
&lt;th&gt;Useful output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--query "linen shirt"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Embedded data on a search listing&lt;/td&gt;
&lt;td&gt;Product IDs, titles, prices, discounts, ratings and stock flags when present&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--category "Women Jeans-c-1934.html"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Embedded data on a category listing&lt;/td&gt;
&lt;td&gt;The same product-level fields for that category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;--url&lt;/code&gt; with a product-page address&lt;/td&gt;
&lt;td&gt;The page's structured JSON-LD data&lt;/td&gt;
&lt;td&gt;Product identity and price; other fields can be missing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a search-to-product workflow, start with the listing and take a returned &lt;code&gt;product_url&lt;/code&gt;. Pass that address to &lt;code&gt;--url&lt;/code&gt; when you want to inspect that specific product page. A listing run does not automatically open every product card and build a complete variant inventory.&lt;/p&gt;

&lt;p&gt;Three field groups matter for the shortlist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;original_price&lt;/code&gt; and &lt;code&gt;discount_pct&lt;/code&gt; describe the price and displayed discount.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt; and &lt;code&gt;review_count&lt;/code&gt; describe the average rating and its review count. These are not individual review texts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;in_stock&lt;/code&gt; is a product-level flag. It does not prove that every size or colour is available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The README identifies &lt;code&gt;sku&lt;/code&gt; as SHEIN's &lt;code&gt;goods_id&lt;/code&gt;, shared across a product's colours and sizes. On a product page with differently priced variants, &lt;code&gt;price_source: "json_ld_min_variant"&lt;/code&gt; means the parser selected the lowest variant price. Do not present that number as the price of every variant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the market and price source visible
&lt;/h2&gt;

&lt;p&gt;This implementation targets &lt;code&gt;us.shein.com&lt;/code&gt;. Other regional sites have not been tested, so replacing the domain is not a documented way to switch markets. The sample records use USD; the filtering script below explicitly keeps that currency.&lt;/p&gt;

&lt;p&gt;Listings are read from &lt;code&gt;window.gbRawData&lt;/code&gt;, the product data embedded in the page. Product pages are read from schema.org JSON-LD. The &lt;code&gt;price_source&lt;/code&gt; field preserves that distinction. It is useful when a listing price and a product-page price do not appear to agree.&lt;/p&gt;

&lt;p&gt;Missing values also carry meaning. A missing rating is not a zero-star review, and an unknown stock flag is not confirmed availability. The shortlist leaves those records out rather than guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a browser can stop before returning products
&lt;/h2&gt;

&lt;p&gt;The project handles JavaScript-rendered product data, an infinitely scrolling listing and SHEIN's risk gateway. A basic HTML request does not cover that whole workflow.&lt;/p&gt;

&lt;p&gt;The README distinguishes two gateway responses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;th&gt;Documented behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/risk/challenge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The scraper attempts the checkbox, then can send an image grid or icon-sequence puzzle to 2Captcha when configured.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/risk/action/limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This is a rate limit with no puzzle to solve. A run with no rows exits with code &lt;code&gt;3&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Image grids use &lt;code&gt;GridTask&lt;/code&gt;; icon sequences use &lt;code&gt;CoordinatesTask&lt;/code&gt;. The default &lt;code&gt;--solve-captcha&lt;/code&gt; mode is &lt;code&gt;when-blocked&lt;/code&gt;. &lt;code&gt;--max-solves&lt;/code&gt; defaults to &lt;code&gt;8&lt;/code&gt; and limits paid solve attempts per run; &lt;code&gt;0&lt;/code&gt; prevents paid solves. That cap does not include remote-browser or proxy charges.&lt;/p&gt;

&lt;p&gt;Solving a challenge is not guaranteed to work. The README's September 30 test reported success for three of five fresh US browser profiles. That small historical test is not a reliability promise. The &lt;a href="https://2captcha.com/h/how-to-scrape-shein?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=shein-scraper" rel="noopener noreferrer"&gt;maintainers' full guide&lt;/a&gt; provides the broader setup and option reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect the run before trusting the file
&lt;/h2&gt;

&lt;p&gt;The repository's current documented release is &lt;code&gt;0.2.0&lt;/code&gt;, dated October 16, 2026. Its exit codes distinguish a completed run from incomplete data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Exit code&lt;/th&gt;
&lt;th&gt;Meaning for the collected data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The run completed. A requested result limit can still make it only a selection.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Some rows were written, but the run is partial. Check &lt;code&gt;stop_reason&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocked or rate-limited, with no rows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The page loaded but had no products.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Content was not obtained or a listing known to contain products could not be parsed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A zero-row run normally preserves previous output rather than overwriting it. That is helpful, but an existing file may therefore belong to an earlier run. Check the latest command's exit status and the records' &lt;code&gt;scraped_at&lt;/code&gt; values before using it as fresh data.&lt;/p&gt;

&lt;p&gt;The README also says collection beyond the first roughly 20 listing products has not been verified. Increasing &lt;code&gt;--max-results&lt;/code&gt; does not prove that you collected the whole category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a CSV shortlist from the bundled sample
&lt;/h2&gt;

&lt;p&gt;Here are selected fields from one record in &lt;code&gt;sample_output.json&lt;/code&gt;, unchanged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"499485260"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jotten"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price_source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"embedded_json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scraped_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-30T12:56:49Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"original_price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;13.79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"discount_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;38.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"review_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;143&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"in_stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bundled file contains three dress records. They demonstrate the processing step; they are not results for the &lt;code&gt;linen shirt&lt;/code&gt; query above.&lt;/p&gt;

&lt;p&gt;Save this code as &lt;code&gt;shortlist.py&lt;/code&gt; inside the repository. It uses only Python's standard library and fields present in the sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sample_output.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in_stock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;4.5&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;discount_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;csv_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"'"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;budget_shortlist.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeheader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerows&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;csv_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; products to budget_shortlist.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it on the repository sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 shortlist.py sample_output.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three bundled records meet these conditions. In ascending price order, the CSV contains SKUs &lt;code&gt;499485260&lt;/code&gt;, &lt;code&gt;458057728&lt;/code&gt; and &lt;code&gt;430743850&lt;/code&gt;, priced at $8.55, $13.03 and $17.51. These are reproducible calculations from the supplied sample, not live offers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6234rjubt5zcjtmqy61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6234rjubt5zcjtmqy61.png" alt="How to scrape SHEIN products: a budget shortlist calculated from the repository sample dated September 30, 2026" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Illustration of the bundled sample after filtering and sorting; not a screenshot of a live scraping run.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After checking a live run's status and freshness, process its JSON instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 shortlist.py shein_results.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script overwrites &lt;code&gt;budget_shortlist.csv&lt;/code&gt; each time. It retains the review count for context but does not impose a minimum count. A rating of 4.8 from a few reviews and the same rating from many reviews deserve different interpretations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions to resolve before extending the workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can this collect all SHEIN products?
&lt;/h3&gt;

&lt;p&gt;The repository does not establish complete catalogue coverage. Start with the small documented scope, inspect partial-run metadata and keep the unverified scrolling behaviour in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I export every size and colour?
&lt;/h3&gt;

&lt;p&gt;The output is one row per product, not one row per variant. A product-page minimum variant price is useful context, but it is insufficient for a size-by-size stock report.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I turn this into a SHEIN price tracker in Python?
&lt;/h3&gt;

&lt;p&gt;The repository includes &lt;code&gt;diff_runs.py&lt;/code&gt; for comparing compatible, complete runs. Keep the same search and market; a product missing from a capped selection is not evidence that SHEIN removed it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does this need an official SHEIN product API?
&lt;/h3&gt;

&lt;p&gt;The documented browser workflow reads data embedded in SHEIN pages. It does not require access to a separate official product API, and this article makes no claim about whether such APIs are available to particular partners.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does a collection run cost?
&lt;/h3&gt;

&lt;p&gt;There is no fixed per-run price established by this example. CAPTCHA solve counts, remote-browser usage and optional proxy usage are separate inputs; consult the services' current pricing before a paid run.&lt;/p&gt;

&lt;p&gt;Use this workflow only where you have permission and in line with applicable site terms, robots.txt and data-protection requirements. Keep request rates modest and stop when access is refused. This example concerns product information and does not require customer accounts or personal data.&lt;/p&gt;

&lt;p&gt;The useful output here is a small, traceable shortlist: every price has a currency, every record has a collection time, and missing fields remain visible. Start with the bundled sample, then decide whether the scraper's documented market and product-level scope fit your own task.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Creation note: this article was drafted with generative AI from the project's documentation and bundled sample data. The offline filtering example was checked against that sample. No live SHEIN scraping was performed for this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>tutorial</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
