<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Http on ErrorZap</title><link>https://errorzap.com/tags/http/</link><description>Recent content in Http on ErrorZap</description><image><title>ErrorZap</title><url>https://errorzap.com/og.png</url><link>https://errorzap.com/og.png</link></image><generator>Hugo</generator><language>en-US</language><copyright>ErrorZap</copyright><lastBuildDate>Mon, 02 Nov 2026 17:15:00 -0700</lastBuildDate><atom:link href="https://errorzap.com/tags/http/index.xml" rel="self" type="application/rss+xml"/><item><title>The Public Website That Blocked the Polite Bot</title><link>https://errorzap.com/posts/the-public-website-that-blocked-the-polite-bot/</link><pubDate>Mon, 02 Nov 2026 17:15:00 -0700</pubDate><guid>https://errorzap.com/posts/the-public-website-that-blocked-the-polite-bot/</guid><description>A public data portal rejected an ordinary collector, and the right response was better failure handling—not a proxy-rotation arms race.</description><content:encoded><![CDATA[<p>The information was public. The website was reachable. The collector was slow, identified, and boring.</p>
<p>It still got blocked.</p>
<p>That moment divides scraping projects into two kinds. One kind asks, &ldquo;How do we get around this?&rdquo; The other asks, &ldquo;What is the responsible product behavior when the source says no?&rdquo;</p>
<p>I want to build the second kind.</p>
<h2 id="public-does-not-mean-permissionless">Public does not mean permissionless</h2>
<p>A page visible in a browser may sit behind rate controls, session logic, terms, copyright, privacy obligations, or infrastructure that was never designed for automated access. A government label does not automatically erase those constraints. Neither does civic usefulness.</p>
<p>Before collecting, identify:</p>
<ul>
<li>the official source and any documented API or export;</li>
<li>terms and licensing for reuse, not merely viewing;</li>
<li>robots.txt and any published crawl or rate guidance;</li>
<li>update cadence;</li>
<li>contact or data-request path;</li>
<li>personal information that should not be republished;</li>
<li>a reasonable request rate and cache policy.</li>
</ul>
<p>If a structured export exists, use it. If permission is required, ask. If the data can be linked without copying, consider whether that is enough.</p>
<h2 id="a-block-is-a-state-not-a-challenge">A block is a state, not a challenge</h2>
<p>When a collector receives a 403, a 429, a challenge page, or a suddenly empty response, it should classify the event and stop escalating.</p>
<p>The bad pattern rotates headers, IPs, accounts, and browser fingerprints until something slips through. That is expensive, fragile, and hostile. It also converts a data-quality problem into an adversarial-access problem.</p>
<p>The safer pattern is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>detect block
</span></span><span style="display:flex;"><span>  -&gt; stop the batch (and honor any Retry-After)
</span></span><span style="display:flex;"><span>  -&gt; preserve last-good data
</span></span><span style="display:flex;"><span>  -&gt; record bounded evidence
</span></span><span style="display:flex;"><span>  -&gt; alert once
</span></span><span style="display:flex;"><span>  -&gt; use official contact/export path
</span></span></code></pre></div><p>Do not let retries become a denial-of-service attack with good intentions.</p>
<h2 id="design-the-site-for-source-failure">Design the site for source failure</h2>
<p>If a public-facing service depends on someone else&rsquo;s portal, source unavailability is normal architecture.</p>
<p>The user experience should expose:</p>
<ul>
<li>last successful update time;</li>
<li>original source link;</li>
<li>current collection status;</li>
<li>whether displayed data is complete or partial;</li>
<li>what is being done to restore the feed;</li>
<li>correction path.</li>
</ul>
<p>That turns a mysterious stale page into an honest service.</p>
<h2 id="keep-the-collector-replaceable">Keep the collector replaceable</h2>
<p>Source HTML changes. Portals get replaced. APIs appear and disappear. A collector should separate retrieval, parsing, validation, storage, and presentation so a new lawful source path does not require rebuilding everything.</p>
<p>Store normalized records with provenance. Preserve the original source identifier. Keep transformations documented. Test parsers against saved, non-sensitive fixtures rather than hammering the live site during development.</p>
<p>The collector is not the public product. Trust is.</p>
<h2 id="politeness-includes-accepting-no">Politeness includes accepting no</h2>
<p>There is a technical culture that treats every block as a puzzle. Sometimes the clever solution is to back off, keep known-good information available, and make a formal request for a better feed.</p>
<p>The portal blocking the bot did not end the project. It clarified the contract the project needed: ethical retrieval, visible freshness, last-good preservation, and no secret war against the source.</p>
<p>A public-interest tool should not have to behave like malware to stay current.</p>
]]></content:encoded></item></channel></rss>