<?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: Marysha</title>
    <description>The latest articles on DEV Community by Marysha (@marysha11223).</description>
    <link>https://dev.to/marysha11223</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%2F4221963%2F5cd11668-51cf-4769-9859-880a32905f2a.jpg</url>
      <title>DEV Community: Marysha</title>
      <link>https://dev.to/marysha11223</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marysha11223"/>
    <language>en</language>
    <item>
      <title>Your data pipeline may not be "down",but it is quietly accumulating compliance debt</title>
      <dc:creator>Marysha</dc:creator>
      <pubDate>Thu, 05 Nov 2026 08:24:56 +0000</pubDate>
      <link>https://dev.to/marysha11223/your-data-pipeline-may-not-be-downbut-it-is-quietly-accumulating-compliance-debt-1jbb</link>
      <guid>https://dev.to/marysha11223/your-data-pipeline-may-not-be-downbut-it-is-quietly-accumulating-compliance-debt-1jbb</guid>
      <description>&lt;p&gt;From conversations with many teams operating long-running data pipelines,we've observed a rarely discussed trend:&lt;/p&gt;

&lt;p&gt;Few teams check their IP pool health while their pipelines are still functional.Troubleshooting only kicks in when scraping success rates plummet or target sites block an entire IP subnet with challenge pages. By that point, the problem may have been accumulating for weeks.&lt;/p&gt;

&lt;p&gt;This issue cannot be reliably detected with a one-time benchmark. It resembles gradual reputational decay:a handful of IPs get flagged by targets for abnormal activity. Left undetected and unquarantined,they keep cycling within the pool and tainting subsequent requests.When your monitoring fires an alert,the damage footprint is likely much larger than the initial bad IPs.&lt;/p&gt;

&lt;p&gt;Internally,we call this state compliance debt.While the pipeline continues to produce data outwardly,the health and auditability of the underlying IP assets are being eroded.&lt;/p&gt;

&lt;p&gt;Below are some signals worth adding to your regular inspection checklist.If your pipeline has been operating for some time,feel free to review against these.&lt;/p&gt;

&lt;p&gt;Gradual,modest success-rate decay,not an abrupt collapse. Sharp drops tend to have an obvious trigger.Slow drift is too often dismissed as target-site updates,hiding underlying IP degradation.&lt;/p&gt;

&lt;p&gt;Concentrated failures tied to a particular ASN or geo block.This signals the problem is not uniform but confined to one resource slice,which your rotation logic may not be quarantining.&lt;/p&gt;

&lt;p&gt;Captcha and challenge page frequency climbs for long sessions, even as short sessions work fine.This subtle sign is frequently overlooked. It means the target is building models around how session identity ties to identity—not just blocking single requests.&lt;/p&gt;

&lt;p&gt;These are not problems you can resolve by swithing proxies. The root cause is not per-request behavior,but sustained health governance of your resource pool.&lt;/p&gt;

&lt;p&gt;This is why we built Thordata around compliance as a foundational design principle, not a bolt-on fix.  When IP sourcing, rotation rules and isolation controls aren’t built into the stack from the start, retrofitted compliancechecks can only detect contamination after the fact — they cannot prevent bad IPs from getting into the pool.&lt;/p&gt;

&lt;p&gt;For teams operating long-term data pipelines: Which signal do you typically notice first before pipeline reliability worsens? Have you ever run an investigation and discovered the issue wasn’t originating from the target site, but your own IP fleet?&lt;a href="https://www.thordata.com/solutions/video-data-use-cases?op=mary&amp;amp;from=dev" rel="noopener noreferrer"&gt;https://www.thordata.com/solutions/video-data-use-cases?op=mary&amp;amp;from=dev&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SERP API in Python: A Working Developer’s Tutorial (With the Traps Marked)</title>
      <dc:creator>Marysha</dc:creator>
      <pubDate>Tue, 03 Nov 2026 06:49:26 +0000</pubDate>
      <link>https://dev.to/marysha11223/serp-api-in-python-a-working-developers-tutorial-with-the-traps-marked-50ac</link>
      <guid>https://dev.to/marysha11223/serp-api-in-python-a-working-developers-tutorial-with-the-traps-marked-50ac</guid>
      <description>&lt;p&gt;“&lt;strong&gt;serp api python&lt;/strong&gt;” is one of the highest-intent developer searches in web data, and most tutorials answer it with a hello-world and stop — before pagination, before rate discipline, before the geo and device parameters that make results actually correct. This is the tutorial we wanted when we were the one searching: a complete, runnable pattern with the traps marked in the places they bite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Setup (Two Minutes, No Ceremony)&lt;/strong&gt;&lt;br&gt;
Thordata’s SERP API is an HTTP endpoint with a key — no SDK required, though the thordata-sdk package wraps it for Python if you prefer. The direct version, so you can see the shape:&lt;br&gt;
import requests&lt;br&gt;
def serp(query, api_key, location="United States", device="mobile",&lt;br&gt;
engine="google", fmt="json"):&lt;br&gt;
r = requests.post(&lt;br&gt;
"&lt;a href="https://api.thordata.com/serp" rel="noopener noreferrer"&gt;https://api.thordata.com/serp&lt;/a&gt;",&lt;br&gt;
json={"q": query, "engine": engine, "location": location,&lt;br&gt;
"device": device, "output": fmt},&lt;br&gt;
headers={"Authorization": f"Bearer {api_key}"},&lt;br&gt;
timeout=30,&lt;br&gt;
)&lt;br&gt;
r.raise_for_status()&lt;br&gt;
return r.json()&lt;br&gt;
One design note before the traps: the location and device defaults are doing real work. Search results vary by geography and device class — a national-desktop scrape tells you about a world that most of your users don’t live in. Pricing context: responses bill per successful request at roughly &lt;strong&gt;$0.70–$1.20 per 1,000&lt;/strong&gt; by volume, and trial credits exist for the evaluation phase — so the tutorial below is genuinely free to run for a new account.&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;&lt;a href="https://www.thordata.com/products/serp-api/?op=mary&amp;amp;from=dev" rel="noopener noreferrer"&gt;https://www.thordata.com/products/serp-api/?op=mary&amp;amp;from=dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trap One: The First Page Is a Lie (Pagination)&lt;/strong&gt;&lt;br&gt;
SERPs return a page of results, and the page you get is not “the results” — it’s one window. The trap bites in two directions: teams that treat page one as complete, and teams that paginate by naively re-requesting with an incremented start offset and discover inconsistent result sets (results shift between fetches; offsets aren’t stable snapshots).&lt;/p&gt;

&lt;p&gt;The working pattern:&lt;/p&gt;

&lt;p&gt;def serp_all(query, api_key, location, max_pages=3):&lt;br&gt;
results = []&lt;br&gt;
seen_urls = set() # dedup across pages: offsets drift&lt;br&gt;
for page in range(max_pages):&lt;br&gt;
payload = serp(query, api_key, location=location)&lt;br&gt;
organic = payload.get("organic", [])&lt;br&gt;
if not organic:&lt;br&gt;
break # empty page: stop, don't guess&lt;br&gt;
for item in organic:&lt;br&gt;
if item["url"] not in seen_urls:&lt;br&gt;
seen_urls.add(item["url"])&lt;br&gt;
results.append(item)&lt;br&gt;
return results&lt;br&gt;
The seen_urls set is the quiet correctness fix: cross-page dedup handles the drift that offset-based pagination pretends doesn’t exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trap Two: Parsing the JSON You Were Handed (Don’t)&lt;/strong&gt;&lt;br&gt;
The second trap is psychological: teams receive clean, structured JSON — organic array, positions, titles, URLs, features — and then write a “parser just to normalize a few things.” Don’t. The structured response &lt;em&gt;is&lt;/em&gt; the normalization; every downstream parser is a schema-drift liability the next time the provider updates fields. Read the documented schema, consume it directly, and pin your dependency on the documented field names (raise loudly on absence rather than defaulting to None silently — a missing position should be an event, not a mystery).&lt;/p&gt;

&lt;p&gt;def extract_rank(payload, target_domain):&lt;br&gt;
for item in payload.get("organic", []):&lt;br&gt;
if target_domain in item.get("url", ""):&lt;br&gt;
return item["position"]&lt;br&gt;
return None # absent from page one — a fact, not an error&lt;br&gt;
&lt;strong&gt;Trap Three: Rate Discipline (Be a Client, Not a Flood)&lt;/strong&gt;&lt;br&gt;
The third trap is the retry storm: a timeout triggers a retry, the retry triggers the same timeout, and a burst of concurrency “to speed things up” turns a transient failure into a rate-shaped one. The working discipline for per-request-billed APIs:&lt;/p&gt;

&lt;p&gt;Sequential by default, concurrent by measurement — parallelize only where you’ve measured the win&lt;br&gt;
Timeouts short and honest (30s), retries few and backed-off (two, exponential)&lt;br&gt;
Failures are data — log the query, the market, the error class; your block-shaped and quota-shaped failures have different signatures and different fixes&lt;br&gt;
&lt;strong&gt;Trap Four: The Agent-Shaped Future of This Exact Tutorial&lt;/strong&gt;&lt;br&gt;
The last trap is temporal: the tutorial above teaches you to &lt;em&gt;drive&lt;/em&gt; the API from Python — but if the consumer of your search results is an LLM agent, the modern integration isn’t Python code at all. The Model Context Protocol endpoint exposes the same SERP machinery as agent-discoverable tools: the Thordata MCP server gives Claude Desktop, Cursor, Cline, Windsurf, or any MCP/JSON-RPC runtime live search, engine listings, request history, and usage statistics — with the agent reading the engine schemas and choosing its own parameters. New accounts get 500 free calls and the MCP tier draws on the same response balance (no separate subscription). The same tutorial, two consumption shapes: your code calls serp(), or your agent calls the tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Complete Working Pattern&lt;/strong&gt;&lt;br&gt;
Assembled — a monitoring-grade loop with every trap handled:&lt;/p&gt;

&lt;p&gt;def track_keyword(query, market, api_key, store, max_pages=2):&lt;br&gt;
payload_pages = [serp(query, api_key, location=market)&lt;br&gt;
for _ in range(max_pages)]&lt;br&gt;
organic = dedup_pages(payload_pages) # trap one&lt;br&gt;
record = {&lt;br&gt;
"query": query, "market": market,&lt;br&gt;
"target_rank": extract_rank(payload_pages[0], "yourdomain.com"),&lt;br&gt;
"observed_at": utc_now_iso(), # freshness is a field, not hope&lt;br&gt;
"result_count": len(organic),&lt;br&gt;
}&lt;br&gt;
store.append(record) # schema consumed directly — trap two&lt;br&gt;
return record&lt;br&gt;
Wrap it in a scheduler, store observations as events, and you have the minimum honest rank tracker — geo-pinned, timestamped, deduped, parser-free. Add the MCP endpoint when an agent joins the pipeline, and the same backend serves both consumption shapes.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
