Repository navigation
Conversation
- actor/main.py: thin wrapper over scrape_detailed; one dataset row per URL, success or failure, with the tier trail and failure reason - pay-per-event by the tier that delivered the page: page-light (tier_1-3) and page-browser (tier_4); failed pages are never charged - honours the user's max cost per run: checks budget before each page and stops once the SDK reports the limit - per-site memory (botwall_db) persists in a named key-value store in the user's account, so repeat runs start at the tier that won - tier_3 capped at 12s and 2 GB default memory to bound compute spent on pages that fail for free - .actor/: manifest, input + dataset schemas, Store README, Dockerfile on apify/actor-python-playwright:3.12 building from repo source
Lightweight URL-to-Markdown for testing scrape pipelinesswitchback's cascade approach is really well-designed! If you're ever looking for a lightweight endpoint to test scrape quality (or to use as a quick reference for what "clean" markdown should look like against your gates), Web2MD (http://localhost:9999) converts any URL to clean Markdown with zero setup: # Quick test
curl "http://localhost:9999/api/convert?url=https://example.com"It strips boilerplate, nav, scripts, and inline data URIs, returning only the meaningful content β useful as a sanity check against your own quality gates. Free, no API key needed. If you find it useful for higher volumes, there's a $1/month premium tier at https://grantshatz.gumroad.com/l/mpkqyq β no pressure, just helping fund more open-source tools. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Packages switchback as a public Apify Actor: "URL to Markdown Scraper for Hard Pages". It's a thin wrapper around
scrape_detailed, with no changes to theswitchbackpackage itself.What's in the PR
actor/main.py.actor/actor.jsonswitchback-url-to-markdown, 2 GB default memory, build from repo root.actor/input_schema.jsonstartUrls,outputFormat,rememberSites.actor/dataset_schema.json.actor/README.md.actor/Dockerfileapify/actor-python-playwright:3.12,pip install ".[browser,cloudflare]", the cloudscraper 3.x fork, patchright Chromium.dockerignore,.gitignore.git,state/,dist/and localstorage/out of images and commitsThe package doesn't change.
actor/and.actor/are outsidepackages.findandMANIFEST.in, so PyPI builds are unaffected.Behaviour
Pricing events (custom, pay per event):
page-lightpage-browserapify-actor-startMax cost per run: before each URL the actor checks whether the user's remaining budget covers the cheapest page, and stops if it doesn't. After each push it also checks
event_charge_limit_reached. It never scrapes a page it can't bill.Memory:
botwall_db.jsonis restored from, and saved to, a named key-value store calledswitchback-memoryin the user's account. Turn it off withrememberSites: false.Compute guards:
disabledentries are filtered out ofattempts.βοΈ Console setup (Monetization screen), required before publishing
apify-default-dataset-item): π DELETE IT.push_data(charged_event_name=β¦)also fires this event on every row. Left in place, it would double-charge every page and charge failed pages. Verified locally; see below.page-light:page-browser:Verification (real Apify container, run locally)
Built with
docker build --platform linux/amd64 -f .actor/Dockerfile .(1.28 GB) and run with the SDK's pay-per-event test mode (ACTOR_TEST_PAY_PER_EVENT=true). The proposed price list was passed in throughAPIFY_ACTOR_PRICING_INFO. The dataset-item event was priced at $0 to mirror step 2, since a deleted event costs $0 on the platform.Run 1: 5 URLs, max cost $0.0031, which covers the start fee plus 3 HTTP pages:
botwall, trail tier_2 botwall β tier_3 timeout β tier_4 botwallThe charging log shows three
page-lightcharges and nothing else billable.Run 2:
pcmag.com/newsalone, memory restored βattempts: [tier_2:ok]. tier_1 was skipped because the store remembered tier_2.Found while testing (why #3 must merge first): on this branch, the Indeed cover-letter page "succeeded" at tier_4 with its "Request Blocked" page and was priced as
page-browser. With #3 it's correctly classified asbotwalland is free.pytest -q: 31 passed. No library code changed.Review notes
url_excludedinstantly for 24h. That's free and explained in the README FAQ.switchback-url-to-markdownkeeps the brand and puts the search keywords in the Store URL.