惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
U
Unit 42
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
L
LangChain Blog
博客园_首页
博客园 - 【当耐特】
Vercel News
Vercel News
I
InfoQ
GbyAI
GbyAI
爱范儿
爱范儿
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Proofpoint News Feed
美团技术团队
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Help Net Security
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
小众软件
小众软件
J
Java Code Geeks
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
The Cloudflare Blog
Recorded Future
Recorded Future
阮一峰的网络日志
阮一峰的网络日志
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog
Microsoft Security Blog
Microsoft Security Blog

Pierce Freeman

A browser for agents | Pierce Freeman The grey market of podcast appearances The way I travel | Pierce Freeman Fixing slow AWS uploads | Pierce Freeman Local tools should still use vaults We solved scratch content first Starting a podcast in 2025 Being late but still being early Automating our home video imports Adding my parents to tailscale A deep dive on agent sandboxes Language servers for AI | Pierce Freeman My simple home podcast studio We need centralized infrastructure | Pierce Freeman Coercing agents to follow conventions using AST validation My unified theory of social selling My personal backup strategy | Pierce Freeman July updates to the homelab How the KV Cache works httpx is the right way to do web requests in Python Reputation is becoming everything | Pierce Freeman Building a (kind of) invisible mac app Updated knowledge in language models Making an ascii animation | Pierce Freeman How speculative decoding works | Pierce Freeman Under the hood of Claude Code Doing things because they're easy, not hard Speeding up sideeffects with JIT in mountaineer Firehot for hot reloading in Python Misadventures in Python hot reloading How text diffusion works | Pierce Freeman The tenacity of modern LLMs The ergonomics of rails | Pierce Freeman How language servers work | Pierce Freeman Just add eggs | Pierce Freeman Unfortunately SEO still matters | Pierce Freeman The futility of human-only web requirements Setting up Input Leap | Pierce Freeman Checking in on Waymo | Pierce Freeman The react revolution | Pierce Freeman Speeding up many small transfers to a unifi nas Quick notes on swift libraries AI engineering is a different animal San Francisco | Pierce Freeman Debugging a mountaineer rendering segfault Local network config on macOS Building our home network | Pierce Freeman Introducing Envelope.dev | Pierce Freeman Legacy code and AI copilots Typehinting from day-zero | Pierce Freeman Generating database migrations with acyclic graphs Lofoten | Pierce Freeman Mountaineer v0.1: Webapps in Python and React Constraining LLM Outputs | Pierce Freeman Passthrough above all | Pierce Freeman Accuracy in kudos | Pierce Freeman How quick we are to adapt The curious case of LM repetition Costa Rica | Pierce Freeman Debugging chrome extensions with system-level logging Speeding up runpod | Pierce Freeman Inline footnotes with html templates Parsing Common Crawl in a day for $60 An era of rich CLI All or nothing with remote work The Next 10 Years | Pierce Freeman Adding wheels to flash-attention | Pierce Freeman LLMs as interdisciplinary agents | Pierce Freeman New Zealand | Pierce Freeman Representations in autoregressive models | Pierce Freeman Let's talk about Siri | Pierce Freeman Minimum viable public infrastructure | Pierce Freeman Reasoning vs. Memorization in LLMs Automatically migrate enums in alembic Greater sequence lengths will set us free On learning to ski | Pierce Freeman Dolomites | Pierce Freeman Using grpc with node and typescript Opportunity years | Pierce Freeman Buzzword peaks and valleys | Pierce Freeman Buenos Aires | Pierce Freeman Network routing interaction on MacOS Independent work: November recap | Pierce Freeman Debugging slow pytorch training performance The provenance of copy and paste Debugging tips for neural network training Patagonia | Pierce Freeman Santiago | Pierce Freeman My 2022 digital travel kit AWS vs GCP - GPU Availability V2 Independent work: October recap | Pierce Freeman Planning Patagonia | Pierce Freeman Relationship modeling | Pierce Freeman The power of status updates A new chapter | Pierce Freeman Give my library a coffee shop AWS vs GCP - GPU Availability V1 Switzerland | Pierce Freeman Headfull browsers beat headless | Pierce Freeman Copenhagen | Pierce Freeman
Webcrawling tradeoffs | Pierce Freeman
2022-09-06 · via Pierce Freeman

A couple of years ago I built our internal crawling platform at Globality, which needed to be capable of scaling to two billion pages each crawl. We had to consider some early design tradeoffs that influenced the rest of the architecture. The most fundamental was which rendering engine we wanted to adopt - and like everything in systems design, they each had different trade offs.

The two main types of crawlers that are deployed in the wild are typically raw or headless:

Raw HTTP

Request raw html over the wire. Bind to the host's socket and issue a GET for the page of interest, then continue to discovered links in a BFS search.

  • Pros
    • Fast. Only downloads the html text payload (still measured in kb on the largest sites).
    • Trivially parallelizable through async processing or threading in your language of choice. An average server can usually accommodate tens of thousand requests in parallel.
  • Cons
    • SPAs are broken, often don't render or don't wrap their links with <a> tags.
    • Additional JS-populated data pages are often blank.

Headless Browsers

Using a runtime like Webkit or Google Chrome, execute the logic of the webpage like a user would see. Run javascript, background scripts, etc.

  • Pros
    • More comprehensive coverage of pages, guaranteed to render SPAs or conditional elements in javascript.
    • Can selectively download image content or reject these requests to save on download speeds.
  • Cons
    • Quite slow in comparison to raw http requests; has to download often unnecessary scripts (tracker scripts, ads, etc.) and execute javascript.
    • Scaling isn't as trivial. Chromium and webkit require sizable CPU and memory requirements to be able to launch and run quickly.

Both approaches operate on the extrema of webpage richness. One supports simple pages, the other the most complicated. If you have a particular set of target domains, you can make a decision that is best for your end use. Building a generic crawler that can deal with any domain you throw at it is a more difficult task. An increasing number of sites are built as SPAs or React applications even if they have static content; likely due to the increase of popularity of JS on the frontend and Node on the backend.

Still - most websites render fine with plaintext. Going with a headless browser is a waste of resources when dealing with the general case; you're burning CPU to render mostly raw html. But going with raw http then misses out on capturing a solid proportion of these new webpages. You seem stuck with the highest common denominator of rendering requirements. Are headless browsers the only answer?

Hybrid Crawlers

I'm surprised there isn't more discussion of crawlers that blend the two approaches. I call this approach hybrid crawling since it makes use of the strengths of both while trying to minimize their weaknesses. It relies on the notion that pages are plaintext until proven otherwise. If pages don't appear valid when retrieved plain, we can delegate the rendering to a headless browser to pull in additional dependencies.

I'd like to propose two main strategies to making this identification:

Page-Level Classification: Fetch the page of interest through a raw http request. Featurize the content and determine whether it contain meaningful data. Since this approach likely uses tag counts or page attribute thresholding, it can be very fast and therefore conducted on every page. Some featurization strategies include:

  • Determine a presence of a <noscript> tag, which usually indicates there's some content that can only be revealed when rendered with javascript.
  • Count the amount of embedded <script> tags that come from the same domain, which usually render some additional content.
  • Count the amount of <a> links that are identified within the body. If there are none or only a handful, it's likely that the page contents aren't fully captured via the raw payload and need to be re-crawled by a headless browser.

Domain-Level Classification: Assume that a domain either uses raw html or rich rendering. Fetch the raw http and full rendering concurrently. Since we are extrapolating for the whole domain, we only have to expend the headless resources a minimum of once per domain.

  • Compare the payload sizes of the body by bytes, by dom tag count, or by words. If the difference is greater than some percent threshold, tag the domain as requiring rich-text and delegate all subsequent pages to the headless browser cluster. Otherwise, continue to crawl as plain text.

To calibrate some of these hyperparameters, select an initial sample of 100-500 websites that you know are involved in your crawling seed set. Crawl these with both the http crawler and the headless browser. For each page, featurize the elements and compare them.

HTTPHeadlessRatio
<noscript> presentyesnoN/A
<a> counts2100.2
<script> counts10101
word counts2505600.44
bytes250060000.42

For page-level classification you'll have to rely on absolute quantities since they appear in a vaccum. For domain-quantities, you'll be better off relying on the ratios since these contain more signal. If you're lucky there will be a clear bimodal separation between the two ranges, which will let you choose clear hyperparameters by eyeballing it.

If you want to get even more precise, you can label the datasets by whether the raw html contain enough information for your crawler and train a simple model that weights the input criteria.

When you're done, you should have a hybrid browser that balances the best of both worlds.

  • Pros
    • Faster than headless browsers, by my measure an order of magnitude
    • Works for SPAs and javascript-heavy webpages
    • Saves on bandwidth
  • Cons
    • Some initial work and data preparation

Hybrid crawlers shift some of the implementation burden to R&D and some data analysis. But if that investment yields a crawler that performs at the sweet spot of time and coverage, it saves an integral of time each time it's used. For a crawler that runs perpetually that's typically worth the trade off.