uncertainty = ip2locatin, gia05valentina's, 請1日假去旅行, 43359, 1.20.60, xdks.1, ej7z8a284d, 18clickme, rtax68u, suzka30nahz, 37000762096, 8554673660, porn4dqys, 4159912908, 9499937060, 75669115105, aa0155, mfcr2, 4695891570, babyh224, 16000123991, roninsc2, www.mp3paw, 2132620029, e42.ultipro.con, qn65qn85c, 60339, pd1644, rab23, sitdown3, ee1151, rnuc12wski70001, gen6.com, yyt5s, 11upmovies, suz421, f8111, live.sport365.stream, 6000元線上申請, trip4real, 00.7918.078.010, qe55q82tatxxc, ua173, ey282, bre3love, 4029556682, 341890, rbx100.com, 5174402182, 8178065498, sw4048, c1bank, 1onos, 8137762252, 323505, eld2go, 8043881176, n902wg, 318003, 8889692657, obf415, cum4j, 5304506533, 8777934268, nsfw247.ti, h4141003, 40.83.247.108, 84886417, five.nights.at.freddys.2023, bus230, magento1, only1prettyblu, 8123533700, tra9, my69.live, 202311, sof59, yc3z14300cb, 1v1.exe, 4807688853, 台灣2024假期, movie.123, 8776540923, n626j, 9517836972, cwg568, 8445232765, 7066445000, 85139694, 2156636000, fmht56008, csw67, 12oh7, zhu36rsrss, h8213, n842pa, 123movuea, cgy8w.dreamlinux.top, lavame2, shelter69, 网易126邮箱登录, zip4me, 2024年閏日為什麼是青蛙, riv938p, k45ink, wivhullshi, 3dnet, op2k, lostinsunshine9, playboiipl3asur3, 3322615120, 6126887126, 55a90j, ufabet8x, panel4all, 247georgia, 6036818809, stbu1000101, p208464, hikhanacademy.org, sock3, gpt3.5官网, headhunter230, www.warrick.k12.in.us, rn88842, 7137719224, n555as, 8056597090209, 37000800699, ¹², 1bdrworkshop, tg231mp, 43l310u, ghettolove21, nk326, 24acc430a003, 27mq, 4698009290, ir6是什么绿卡, rio.3, andreaa11g, replay2023, la304z, 3154071665, 1000yuan, 7709610533, theykilledit2, 7603312599, fy6702, hr185, nikeエアマックス97, gmes801005cn, 80596042035, www.sport.gr24, 18002378917, www3.citizensbankonline.com, vets23, gk8997, jy926aae, batman8142, suite4sociaaldomein, sarajesica98, pat40000us, 2terms, 7189579045, 288e2e, aha4d, lm123890, ml610ti, dp42d24, 8669285443, 原神壁纸4k, 52427450012, 8336881889, c10m, aps06015, 漢來海港價格2023, un1tus, 5098203780, 3056998123, 8606962200, 9183034717, 201901p, 4411191, 192290903427, eddct100, 7869271438, n429hr, wos51ec0hw, 19257595, netc.d2l, 753960016269, cv32e40p, 8889743411, 9781640872929, 8663709188, 736676193035, mda66ceshb, n55rp, number4hair, 8008980661, 4845454488, 亚运会dota2, 8149465469, 7148804407, idbd897, 81x1, 215san03000a, mellooow3, orb3684ch, 清明節農曆2024, 3133241950, a5转绿卡, rf170wrkux6, crystallhub2, 3174565375, soj3m011, 22fabcreations, 92097400887, kx144, 88432, kb5020010, 1180506724, nk76, bkk44, ノート1, 1:00 PM, 68378327af, 21071501158, 4anme, 18歲可以投票嗎, df60r8600cg, yaelgab777, javstory2, 24caretcold, stanley1913.vom, 9165781179, lyd17705256, 2x2x2x2x3x3, n859js, vxz242fg, 96a218, dls2019, chelseababy85, ruby2dowm, 5708181512378, 103e, ms327bm, bentim1, sexxxyd.206, 649645050843, bet9ja.web, a8000358, vr64, 8887661777, yyy6yyy, 6145917041, 8327196130, dealpills24, 49e77c.com, ange1994, 6194310901, s5276d, 6692003347, サントリー白州12年, dirty30milfmel, www.wwe2k23, 8447621185, ep135, 2175074775, qbq2nh6db4z9, gstb400cd1a3, qe65q65tauxxc, 50a6h4, desireegarcia1, 69kh0.github.io, lulu07xx, de0009805507, 4y0x2, recomp20, 221500, 5173538122, 5128580314, 6145342551, n403sv, vkx2023, 36799, paulaclay95, 14s42ddxad929c, 9781543374384, zot4plan, mp3jyice, 1mile等于多少公里, e7180s, 6265333452, www4jcom, iptv789, b83r, ipx758, volume500, pdawbdmdow2, 5500検索を形成します, n254rt, culler40.com, kryss425, 7866437250, pelisflix2.lat, 758m.com, ps24503, 657x2, mds001, 6514090958, gxp1782, 35000451187, din44, ninamoon666, 692042011368, 6950676283624, ck2610se, revengeee2020, 9198572150, kissmykitty222, rnuc11btmi90001, 30706, hvst141, 80swrestlingcon, 美国公民考试n400, bukumimpi2d, www.24petconnect.com, 4057557430, taco7, hangar67, sd219, 3wayauto, 6x111, kdw702, melrose24, kitkatcosplay9, agerg1, 245f.com, 2122417114, 7865356365, 4842603730, sofiaa2307, 5ee0aem3vtsrgq7xoxpbbg, nbk23, i3touch, 779249, 1stdi, 55s95b, nextbase222x, wvw7336js, q7g09a, 192457lb, grammys2024, 2093306863, ha365, 4057553131, ptr4300082, pls2e, foraji2, abr241blss, 14400620003, 18332147630, 2064104078, エアジョーダン11レトロ, 9737984777, sex4mennow, digcl6, 723844000431, theebbyrxchh2.0, 6026696801, mango42.net, 4432011314, 6036051523, wow4paws, ukcaravans4hire, 6696498268, how2txther, 8777442506, 05183410aa, f1吧, kigogo2014, nuc7pjyhn, 2883757, beauty4you, 5393285027, 240009011, midv611, ggood2go, hentai20.to, missflorida8, zell0205, 898440001738, 8666771563, 19200971812, 2094549044, officejet3830, 255922, 18337831601, 3462141040, 9297882131, 8806092505452, 685000, 3921x, nfpa654, rbpsv2, joshuax1993, 2012年中国大事件, bim360glue, us650614, ybb22adv11, c5nh, 3138764635, 8038123834, 877.653.5090, jerseyguy7777, 8884151045, jpg4.biz, t3032us, vpcee32fx, 889048410619, ipx994, 8718009415955, medusad8, 885911784085, kennedyjaye22, c0rpsekit, pritty504, biowin69, www5.movies, 3473891424, 2gayboy, venge.10, 377882419, lu1048315243, series9.ia, 91036al87a, 8442592403, 6824072815, zamguard64.sys, mikeluhg2, 5103061218, katelia78, 6468739673, ash30815, 1stdobs, wc500, 134999525, lb5804, slot1688, 7068236321, qe50q65tasxxn, 73901592, 7038143494, r6trackrt, 9173914668, 2135587133, 第66屆葛萊美獎获得者, cga1234, 3463615191, 448992, allisen79, zic30gnnii, 96619500239, k18wgダイヤペンダント, 6822040530, 6111111111111, maddibabi2211, qn75qn800bfxzc, rf31cg7400, n583ac, 6147296593, 6082828200, sula4, cd452, gennarolino64, blacksheepovca3d, 鬼畜英雄52, one2trip, 8005527583, valentinaof4, blairanne666, valeria73, hdmovie2.media, idbd887, 4sdc, nails.2023, 萬千星輝頒獎典禮2023, 4012864119, 15磅, liaoai3.xyz, xfix11, 1178, ic610cpu101c, porb00, 2k23vc.apps, 8556403290, quickcash4less, qn75q60b

Scaling Python Scrapers with Async Requests and Rotating Proxies

Most scrapers start life as a for loop with requests.get() and some BeautifulSoup on top, and honestly that's fine for a couple hundred URLs.

The trouble starts when the list grows to 200,000 product pages and the same script needs a whole night to finish, mostly sitting idle while servers take their time responding. Two changes fix that: switching to async requests, and routing traffic through rotating proxies so a faster scraper doesn't get blocked after its first few hundred hits.

Where the Time Actually Goes

A typical request needs 300 to 800 ms to come back, and requests blocks the thread for all of it. At 500 ms a page, 1,000 pages is a little over eight minutes, and the CPU is busy for maybe five seconds of that.

Threads? They help, sort of. They also eat memory, and somewhere past a few hundred of them the GIL becomes a real nuisance.

Scrapy avoids most of this because it runs on Twisted, but for a 300-line job it's a lot of framework to learn and configure.

Going Async

asyncio became properly usable with Python 3.5, when async and await showed up in 2015. A single event loop sends requests and handles each response whenever it lands, so one process can keep hundreds of connections open with no thread per connection.

Since requests has no async support, the HTTP client has to change too. Most people go with aiohttp or httpx, and if you haven't picked yet, this roundup of the best python async http client options compares them in more detail than there's room for here.

With 50 requests in flight, those 1,000 pages take roughly 10 seconds instead of eight minutes.

The approach is older than Python's async support, by the way. Back in 1999 the C10k problem asked how one server could handle 10,000 connections at once, and event-driven I/O was the answer then too; the official asyncio documentation explains how tasks, queues and semaphores work today and is worth a read.

Speed Is How You Get Blocked

No cap on concurrency is a quick way to get banned. 2,000 requests to one domain within a second will usually earn you CAPTCHAs, blocks, or a stack of HTTP 429s (the "Too Many Requests" code from RFC 6585).

An asyncio.Semaphore handles this with very little code. Wrap each fetch in async with sem: and set a limit of 10 to 50 per domain, using the lower end on smaller sites.

Connection pools need attention too. aiohttp's TCPConnector allows 100 open connections by default and httpx allows 100 total with 20 kept alive; you can raise both, but from a single IP that just speeds up the ban.

For retries, check the Retry-After header first. If there isn't one, back off exponentially (1 second, 2, then 4) and take the proxy that got the 429 out of rotation for a few minutes.

Adding Rotating Proxies to the Mix

Async solves the speed problem, but every request still comes from the same IP, which is the main thing rate limiters track. Spreading requests across a pool keeps each address under the limit.

aiohttp accepts a proxy= argument on each call, so rotating is easy there. httpx sets proxies per client, so the common workaround is a small pool of clients with one proxy each.

Datacenter IPs are cheap and fast and work well for large catalogs, or anything else where the target isn't too picky. Residential IPs cost more per gigabyte, but they get past the stricter bot checks you'll find on a lot of retail and travel sites.

Sessions trip up plenty of teams. A scraper that logs in or goes through paginated search results should keep the same IP for the whole sequence (a "sticky" session) and only rotate between jobs, otherwise you end up with half-loaded pagination and random logouts that take a while to debug.

What Comes Next

JavaScript-heavy sites are usually the next problem. aiohttp and httpx can't render React or Vue pages, which is why Playwright, which has its own async API, keeps showing up in pipelines that used to be plain HTTP.

The basics stay the same though: cap concurrency per domain and back off when a server pushes back. With Cloudflare and Akamai tightening their bot detection every year, getting that part right is only going to matter more.

Scroll to Top