今日已更新 257 条资讯 | 累计 40702 条内容
关于我们

标签:#rap

找到 157 篇相关文章

AI 资讯

The 3 AM Dashboard: Why Most SaaS Analytics Pages Fail Their Users (And How to Fix Yours)

It's 3 AM. Your customer can't sleep. They open your SaaS product on their phone to check one number — whether their pipeline is healthy, whether something needs their attention before morning. What they see instead is a wall of 47 widgets, three unlabeled charts, and a date picker buried behind a gear icon. They close the tab. They don't come back. This isn't a hypothetical. In 2024, Userpilot benchmarked 62 B2B SaaS products and found that only 37.5% of new users ever reach activation — the point where they actually experience the value they signed up for ( Userpilot User Activation Benchmark Report, 2024 ). The rest poke around a dashboard, get overwhelmed, and leave. A Nielsen Norman Group study found that decision-makers spend roughly 2.3 seconds scanning a dashboard before deciding to engage or abandon it. Your analytics page is the screen where retention is won or lost. And most SaaS companies are losing. The Four Ways Dashboards Fail 1. The Data Dump The most common failure: treating a dashboard like a warehouse. Every stakeholder gets a tile. Three years in, the dashboard has 34 widgets and nobody can find anything. One UX audit of a banking analytics platform found that 11 of 23 displayed metrics were never clicked — four drove 80% of all sessions. After removing 17 widgets, adoption rose 41% in six weeks ( SaaS Dashboard Design: How to Build Dashboards Users Actually Love ). The team asked, "What data should we show?" The right question is: "What decision does this user need to make in the next 30 seconds?" 2. No Default Narrative A dashboard that shows "$42,000 MRR" with no trend arrow, no comparison, and no time period label forces the user to do mental math. A number without context is a snapshot; a number with a trend is a story. Research consistently suggests that 5–7 primary metrics is the maximum before cognitive load degrades comprehension — and for the headline view, 3–5 is ideal ( SaaS Dashboard Design Guidelines ). When different parts of a das

2026-07-30 原文 →
AI 资讯

The Founder-Led Sales Playbook: From $0 to $1M ARR Without Hiring a Single Salesperson

Every bootstrapped SaaS founder hits the same wall. You've built a product. You have organic signups. You're at $3-5K MRR growing 5% per month. At this rate, you'll hit $1M ARR in approximately... never. The conventional wisdom says: hire a salesperson. But you can't afford one. A decent SaaS AE costs $80-120K base plus commission, and the good ones want to sell for funded companies with brand recognition. Here's the good news: you don't need a sales team to reach $1M ARR. You need a system. And you — the founder — are the best salesperson your company will ever have, because you understand the customer's problem better than anyone you could hire. This playbook covers the tools, processes, and scripts to run founder-led sales from zero to a million ARR. Why Founder-Led Sales Wins At $10K MRR, your entire company revenue is $120K per year. Hiring a salesperson at $80-100K base means 70-80% of revenue goes to one person — before ramp time (3-6 months), tools, and leads burned while learning. Meanwhile, you already have the context. You built the product. You can answer any objection without checking with a product team. According to OpenView Partners' SaaS Benchmarks, companies in the $1-5M ARR range with founder-led sales close deals 40% faster than those with early sales hires, primarily because founders can make pricing and scope decisions on the spot. Companies like Bannerbear and many IndieHackers founders built to $1M+ ARR with the founder doing all the selling. It's often optimal. Phase 1: $0 to $10K MRR — Manual Everything Your job is to find the first 10-20 customers who will pay you, use your product, and give you feedback. The Tools ($0-50/month) CRM: A spreadsheet. Notion, Airtable, or Google Sheets. Don't buy a CRM until you have 50+ leads. Email: Your personal email via Google Workspace ($6/month). Meetings: Google Meet (free) or Calendly free tier. Enrichment: Apollo.io free tier or manual LinkedIn research. The Process Step 1: Build a target list of 10

2026-07-30 原文 →
AI 资讯

Handoffs can turn one task into a 15x token bill

Handoffs are useful when a specialist agent needs to take over a task. They also make cost easier to hide, because the bill is spread across graph nodes instead of one visible chat turn. Why can LangGraph handoffs multiply tokens? LangGraph handoffs can multiply tokens because each model-calling node may resend instructions, prior messages, retrieved material, tool returns, summaries, and artifacts, then loops or handoffs repeat that payload for the next agent. Token amplification is the total prompt-plus-completion tokens across a trace divided by a simpler baseline for the same task; Anthropic reported in June 2025 that multi-agent systems used about 15x more tokens than chats while improving an internal research evaluation by 90.2% . Quick Answer: Handoffs raise the token bill when each agent receives copied context instead of a narrow task packet. Anthropic’s June 2025 research system showed the tradeoff clearly: multi-agent runs used about 15x more tokens than chats while scoring 90.2% higher on its internal research evaluation . In LangGraph, the practical issue is observability and budgeting, not whether graphs are bad. The LangGraph project describes the runtime as a way to build stateful, long-running agents with persistence, human control, memory, and debugging support; those same traits make it possible to measure where context grows instead of guessing. "Multi-agent systems are often highly effective at open-ended research tasks, but token usage can be substantial," — Anthropic engineering team at Anthropic The small verified demo below shows the arithmetic behind a 15x bill: a 100-token task becomes 1,500 billed tokens when 5 agents each receive 3 copies of the relevant context . """ Tiny token-accounting demo: handoffs multiply the same task context. """ task_tokens = 100 agents = 5 context_copies_per_handoff = 3 # instructions + task + summary/history direct_bill = task_tokens handoff_bill = task_tokens * agents * context_copies_per_handoff print ( f

2026-07-30 原文 →
AI 资讯

Your Scraper Works Locally but Returns 403 on a Server. Here's Why.

Key takeaways A request is judged on many layers at once — IP reputation, TLS fingerprint, HTTP/2 shape, headers, and how the browser is driven — and failing any one is enough for a 403. Your laptop passes because every layer is consistent with a real home browser; a server changes one (usually the IP) and the inconsistency is the tell. A 403 with no challenge page almost always means you were blocked at the network layer (IP/ASN reputation or TLS/JA3 fingerprint) before any HTML was served — not a credentials or rate-limit bug, so 'add a User-Agent' or 'slow down' won't fix it. The fix order that actually works: get off datacenter IPs (residential/ISP proxies), match a real browser's TLS fingerprint, and spin up a real-browser stealth setup only for the pages that truly need JavaScript — escalate, don't lead with a browser. A proxy only changes your IP; a Linux VPS still leaks a Linux-shaped TLS/JS fingerprint, so 'residential IP + datacenter everything-else' is a contradiction a real home machine never makes — which is why a proxied server can get blocked harder than your laptop. Your scraper runs perfectly on your laptop. You deploy it to a VPS or a CI runner, change nothing in the code, and suddenly every request comes back 403 . It feels like a bug — the code is identical — but it usually isn't. Anti-bot systems judge a request on many signals at once, and moving from your home machine to a datacenter flips several of them at the same time. This post breaks down exactly which signals change, how to tell which one is blocking you, and how to fix it — for authorized access to public data (we'll keep that framing honest throughout; nothing here is about defeating a protection). A request is judged in two stages It helps to know that detection happens in two stages: Stage 1 — before any HTML is served. IP reputation, your TLS handshake, your HTTP/2 settings, and header order are all inspected on the connection itself, passively and cheaply, before your request is e

2026-07-30 原文 →
AI 资讯

The Great Ubuntu Blackout: My 3-Hour Journey to Fix the Darkness

Introduction It was a perfectly normal day. I opened my laptop, ready to get some work done, and then... BAM. A black screen. Not a gentle fade to black, but more like my computer shouting, "I’ve had enough of your crap!" The same operating system that had been working perfectly just five hours earlier had suddenly decided it had had enough of life. I wasn't too worried though. After all, I had ChatGPT on my side. Three hours later... Yeah... my confidence crumbled faster than my phone battery at 2%. What followed was a three-hour rabbit hole involving NVIDIA drivers, multiple Linux kernels, Secure Boot, DKMS, Xorg, GDM, journalctl , systemd , and more terminal commands than I'd like to admit. Somehow, against all odds (and probably a little divine intervention), we managed to fix it. And honestly? I enjoyed every minute of the chaos. It was like a wild adventure—except with more curse words and less danger. So I decided to document the entire debugging journey—not just because it might help someone who runs into the same issue, but also because I deserve a little sympathy after spending three hours arguing with my laptop. (And if the solution seems painfully obvious to you... please let me enjoy my victory. Don't take this away from me.😤 The Problem After rebooting my laptop, I was greeted with just a black screen. No login screen, no desktop… just nothing.** At first, I tried to enter TTY using Ctrl + Alt + F3, but that wasn’t working either. Since I wasn’t able to reach TTY directly, I had to take a different route. By editing the GRUB boot entry and booting into multi-user.target , I forced Linux to start in text-only mode, giving me access to a terminal.** For this, I edited the GRUB boot entry and appended systemd.unit=multi-user.target to the end of the kernel command line (after quiet splash ). That was the first breakthrough, though. The operating system wasn’t completely dead… only the graphical interface was failing to wake up. First Clues and Initial Ass

2026-07-30 原文 →
AI 资讯

From RAG to Agentic AI. How I Added LangGraph to My Local

In my previous article , I built a fully local RAG assistant Ollama, ChromaDB, LangChain, all running in Docker. It answered technical support questions by searching through documentation and citing sources. It worked. But after using it for a while, I noticed something uncomfortable: it treated every question the same way . Ask it "how to close monthly payroll?" it searches the docs. Fine. Ask it "the server crashes at startup" it also searches the docs. Less fine. Ask it something completely outside the documentation it searches the docs. Useless. A real support technician doesn't do that. They first assess the situation, then decide what to do: look it up, run a diagnosis, or escalate to a human. My RAG had no such judgment. That's what this article is about how I evolved the system into an Agentic AI architecture using LangGraph, where the assistant first decides which strategy to use , then acts accordingly. The Core Limitation of Classic RAG Classic RAG is a linear pipeline. Every query follows the exact same path: Question → Embed → Retrieve → Prompt → LLM → Answer No branching. No decision-making. No memory between steps. This works perfectly for procedural questions where the answer lives in the docs. But technical support involves at least three distinct scenarios: Scenario Example Best strategy Procedural question "How do I create an account?" Search documentation Known error code "ERR-COMP-001 appears" Lookup error database Unknown incident "Server crashes, no idea why" Diagnose + escalate if needed A single RAG pipeline handles the first case well and the other two poorly. The solution is to add a layer of reasoning before retrieval. What Agentic AI Adds The shift from RAG to Agentic AI comes down to one thing: the system plans before it acts . Instead of one fixed pipeline, you have: Question ↓ Classifier (what kind of question is this?) ↓ ├── Procedural → RAG Agent (search docs) ├── Error code → Diagnostic Agent (lookup + LLM analysis) └── Complex → D

2026-07-30 原文 →
AI 资讯

Scraping platform costs: measure successful rows, not browser minutes

A scraping job usually fails in boring ways: the browser hangs, a selector starts returning empty strings, a login expires, or the target site returns a captcha halfway through the run. The awkward part is that many platforms still bill you for the work done before the failure. If you run enough jobs, that difference shows up both in your invoice and in the amount of defensive code you need around the scraper. Billing by compute time changes how you build A lot of scraping platforms charge for runtime. Apify, for example, uses compute units: memory multiplied by time. A browser-heavy actor running for ten minutes with 2 GB of RAM consumes roughly a third of a compute unit before any actor-specific result fees. That model is reasonable from the provider side. Chromium processes are expensive. Proxies cost money. Retries use resources. But as the caller, you care about a different unit: did I get the rows I needed? The hard part is that runtime billing makes cost hard to know before execution. A job that normally takes 30 seconds might take 8 minutes when a site slows down. A job that returns malformed data can still count as successful from the platform's point of view. A job that fails after rendering 200 pages still consumed browser time. If your pipeline runs once a day, that may be fine. If it runs continuously, you probably want a local cost model that tracks outcomes, not just requests. type ScrapeRun = { jobId : string ; target : string ; startedAt : string ; finishedAt ?: string ; status : " queued " | " running " | " succeeded " | " failed " ; rowsExpected ?: number ; rowsReceived ?: number ; billedUnits ?: number ; }; function isUsefulResult ( run : ScrapeRun ) { if ( run . status !== " succeeded " ) return false ; if ( run . rowsExpected && ( run . rowsReceived ?? 0 ) < run . rowsExpected * 0.9 ) { return false ; } return ( run . rowsReceived ?? 0 ) > 0 ; } function costPerUsefulRow ( run : ScrapeRun ) { if ( ! isUsefulResult ( run )) return Infinity ; ret

2026-07-28 原文 →
AI 资讯

LangGraph isn't cheaper than LangChain — unless you opt out of its defaults

LangGraph isn't cheaper than LangChain — unless you opt out of its defaults Cost-audit series, episode 4. This series began with an AI agent that burned 136M tokens overnight → . When LangChain deprecated ConversationBufferMemory (the subject of episode 1 in this series), the official migration path was LangGraph. The pitch: explicit state management, you control exactly what flows where. More expressive, more controllable. It is — but only if you reach for the controls. The default state model in LangGraph has the same unbounded-growth problem as the memory it replaced. Teams migrating to escape ConversationBufferMemory's cost curve often land on an identical curve, with new graph complexity on top. This audit shows exactly where the default grows, what it costs, and what opt-outs exist. The default: MessagesState + add_messages The quickstart in LangGraph's own docs uses this pattern: from langgraph.graph import StateGraph , MessagesState def my_node ( state : MessagesState ): messages = state [ " messages " ] response = llm . invoke ( messages ) # sends ALL messages to the LLM return { " messages " : [ response ]} graph = StateGraph ( MessagesState ) graph . add_node ( " agent " , my_node ) MessagesState is a TypedDict with a single key, messages , backed by the add_messages reducer. Here's what that reducer does: # langgraph/graph/message.py — add_messages (def at line 18; merge loop below) def add_messages ( left : Messages , right : Messages ) -> Messages : # ... (coerces left/right to lists of BaseMessage) ... left_idx_by_id = { m . id : i for i , m in enumerate ( left )} merged = left . copy () ids_to_remove = set () for m in right : if ( existing_idx : = left_idx_by_id . get ( m . id )) is not None : if isinstance ( m , RemoveMessage ): ids_to_remove . add ( m . id ) else : merged [ existing_idx ] = m # same id → update in place else : merged . append ( m ) # new id → APPEND (the list grows) merged = [ m for m in merged if m . id not in ids_to_remove ] retu

2026-07-28 原文 →
AI 资讯

AI-Native Redesign: The Principles Don't Change — Only the Machinery Does

AI assistance disclosure: This article was drafted with the help of Claude. All technical content, design decisions, code references, and screenshots reflect production systems I designed and operate at airCloset; the prose was revised by me prior to publication. Hi, I'm Ryan , CTO at airCloset (a fashion-rental subscription service based in Japan). "Everything changes with AI" is the prevailing mood. My experience building and then running an internal AI platform (cortex) points the other way. The principles don't change at all. Only the machinery does. This post is about what I've come to treat as principle, what I've concluded should be broken, and the thinking behind that split. Disclaimer : "cortex" in this article is the internal codename for the AI platform built in-house at airCloset. It is unrelated to existing commercial services like Snowflake Cortex or Palo Alto Networks Cortex. I've written about the individual pieces before: code-graph , product-graph , db-graph , biz-graph , AI-Observability , the auto-review harness , and Self-Healing . This post isn't about any of them. It's about the design principle sitting behind all of them, one abstraction level up, more essay than build log. The principle, in one sentence: how do we make accurate information accessible? It's an old question. Libraries, legal case books, encyclopedias, search engines — every era has had its own answer using whatever tools that era gave it. Even the technology revolutions people call "paradigm shifts" mostly just changed the means . The underlying question didn't move. Now AI has arrived, and my read (probably not a controversial one) is that its shift is at least on the scale of the internet, possibly larger. As with every previous paradigm shift, the means of answering "how do we make accurate information accessible?" will get redesigned from the ground up. That's what this post is about: AI-Native Redesign — a view where you rebuild the whole design with AI treated as a given

2026-07-28 原文 →
AI 资讯

The Distributed Systems Challenge of Post-Quantum Cryptography

Encrypted data stored in cloud archives today will outlive the mathematical algorithms guarding it. In enterprise architectures that handle long-term records, like construction risk logs or employee compliance platforms, data retention schedules often span twenty to thirty years. When building cloud pipelines that move this information across services, we depend heavily on asymmetric encryption, which is a security method using one public key to lock data and a separate private key to unlock it. Standard public-key algorithms rely on mathematical problems that are nearly impossible for classical computers to solve within a reasonable human timeframe. Quantum computing changes this equation entirely. Quantum computers leverage quantum mechanics, the physical rules governing subatomic particles, to perform calculations at speeds fundamentally unimaginable with traditional silicon processors. While powerful quantum systems are still in development, the security threat to distributed systems exists today. Hostile actors do not need to crack modern security algorithms in real time. Through a pattern known as Harvest Now, Decrypt Later, adversaries can capture and store encrypted network traffic right now. They simply wait until future quantum hardware becomes capable of running the formulas required to decrypt that stolen history. For software architects, preparing for post-quantum cryptography, which refers to new mathematical encryption algorithms designed to withstand quantum attacks, is far more than a simple library swap. It is a deep distributed systems migration challenge. The primary operational hurdle is payload size and computational overhead. Quantum-resistant algorithms require significantly larger digital keys and payload headers than the standards we rely on today. When cryptographic payloads expand, every component of a distributed platform feels the ripple effect. Message queues experience higher bandwidth demands. Database indexes inflate. Memory consump

2026-07-27 原文 →
开发者

Rotating Residential Proxies in Python: requests, Scrapy & Sticky Sessions

When you scrape at any real volume, the bottleneck is rarely your code — it's the target site's rate limiting and IP bans. Rotating residential proxies solve this by routing each request through a different real-user IP. Here's how to wire them into requests and Scrapy in Python, including the sticky-session trick most tutorials skip. The proxy URL format A residential proxy is just an authenticated HTTP/SOCKS endpoint. With a pool gateway, you target a country and control session behavior through the username , not separate endpoints: http://USERNAME_country-us_session-a1b2c3_lifetime-30:PASSWORD@proxy.gproxy.net:1000 country-us — exit country (ISO code) session-a1b2c3 — a sticky-session id; reuse it to keep the same IP , change it to rotate lifetime-30 — how many minutes that session's IP stays fixed Basic request through a rotating proxy import requests USER = " USERNAME " PWD = " PASSWORD " def proxy ( country = " us " , session = None , lifetime = 30 ): tag = f " _country- { country } " if session : tag += f " _session- { session } _lifetime- { lifetime } " url = f " http:// { USER }{ tag } : { PWD } @proxy.gproxy.net:1000 " return { " http " : url , " https " : url } # New IP on every call (no session id): r = requests . get ( " https://api.ipify.org?format=json " , proxies = proxy (), timeout = 30 ) print ( r . json ()[ " ip " ]) Run it in a loop and you'll see a different IP each time — the gateway rotates automatically when no session id is present. Sticky sessions: keep one IP across requests Some flows (login, multi-step checkouts, paginated results behind a cookie) break if your IP changes mid-session. Pin the IP by passing a stable session id: import uuid sess = uuid . uuid4 (). hex [: 8 ] # one id for the whole flow p = proxy ( country = " de " , session = sess , lifetime = 30 ) s = requests . Session () s . proxies . update ( p ) s . get ( " https://example.com/login " ) s . post ( " https://example.com/login " , data = {...}) # same exit IP When you

2026-07-25 原文 →
AI 资讯

KRACK: How WPA2 Wi-Fi Encryption Was Broken by Reusing a Key

In October 2017, researcher Mathy Vanhoef published an attack that broke WPA2, the encryption that had protected almost every Wi-Fi network on the planet for over a decade. The surprise was how it worked. KRACK did not guess your Wi-Fi password or brute-force any key. It tricked your device into installing a key it had already used, and that single mistake unraveled the encryption. WPA2 replaced the badly broken WEP standard in 2004 and quickly became the baseline for wireless security. For thirteen years it held up well. The passphrase-based version most homes use (WPA2-Personal) was vulnerable to offline password guessing if you chose a weak passphrase, but the protocol itself was considered sound. KRACK, short for Key Reinstallation Attack, was different. It targeted a flaw in the WPA2 standard itself, which meant every correct implementation was affected. The four-way handshake, briefly When a device joins a WPA2 network, the client and the access point run a four-message exchange called the four-way handshake. Both sides already share a secret (derived from the passphrase or from an enterprise authentication server). The handshake uses that shared secret to agree on a fresh session key, the Pairwise Transient Key, that will actually encrypt the traffic for this session. The important part is message three. The access point sends message three to tell the client the key is ready, and the client responds with message four and installs the key. Once installed, that key encrypts frames using a counter, called a nonce or packet number, that increments with every frame. The security of the encryption depends on one rule: a given key must never encrypt two different frames with the same nonce. The reinstallation trick Wi-Fi is a lossy medium. Messages get dropped. So the standard says that if the access point does not receive message four, it retransmits message three. When the client receives a retransmitted message three, it reinstalls the same key and, critically,

2026-07-24 原文 →
AI 资讯

Why I Chose Slot Hashes Over VRF for Fair Random Selection on Solana

When I set out to build a provably-fair random selection system on Solana, the obvious choice for randomness was a VRF (Verifiable Random Function). Instead, I built the system around Solana's SlotHashes sysvar with a commit-reveal scheme. Here's why, and what I gave up to get there. The problem A fair-selection system needs a winner (or set of winners) chosen in a way that's fair, and just as important that participants can check for themselves without taking anyone's word for it. VRF services (Switchboard, ORAO, etc.) solve the fairness part well: they produce randomness that's unpredictable in advance and cryptographically provable after the fact. But they come with a dependency on an oracle, a fee per request, and a proof that most users will never actually verify they'll trust it because the crypto math says they can, not because they did. I wanted something a participant with no crypto background could check in a browser console. The approach: commit-reveal with slot hashes The core idea: commit to the participant list before you know the randomness, then derive the randomness from a slot hash you couldn't have predicted at commit time. rust fn derive_randomness(target_hash: &[u8; 32], participant_root: &[u8; 32]) -> [u8; 32] { let mut combined_seed = [0u8; 64]; combined_seed[..32].copy_from_slice(target_hash); // slot hash at reveal combined_seed[32..].copy_from_slice(participant_root); // Merkle root, locked at commit solana_keccak_hasher::hash(&combined_seed).to_bytes() } The flow: Commit: participant list is finalized and hashed into a Merkle root; this is written on-chain. Wait: a target slot in the future is chosen as the reveal point. Reveal: once that slot passes, its hash is pulled from SlotHashes and combined with the committed root to derive the randomness. Select: the randomness deterministically picks winners from the participant set; winners get their own Merkle root and proofs. Every draw ends up with an audit record like: rust pub struct AuditR

2026-07-24 原文 →
AI 资讯

HollowGraph Malware Uses Microsoft 365 Calendar Events as Dead-Drop C2 Channel

What Happened On July 20, 2026, cybersecurity firm Group-IB disclosed a new espionage implant dubbed HollowGraph that hijacks compromised Microsoft 365 mailboxes to run a command-and-control (C2) channel hidden inside calendar events. The malware attaches encrypted files to calendar entries dated May 13, 2050 — far enough in the future that a mailbox owner would never scroll to them — and retrieves operator instructions from the same dead drop. All traffic moves through the Microsoft Graph API, making the activity indistinguishable from legitimate M365 usage. At least 12 systems have been infected, with three actively communicating with the threat actor between June 3 and July 9, 2026. The indicators point to a targeted espionage campaign focused on Israeli organizations . Technical Analysis HollowGraph is a lightweight .NET DLL that supports only two commands: GET and SEND . To receive tasking, it queries the compromised mailbox's calendar for an event titled in the format "Event ID: <7-char-taskID>", downloads the attached file, and decrypts it using RSA and AES-256-GCM. To exfiltrate data, the implant creates a new calendar entry titled "Boss{..}ID{..}" and uploads stolen files encrypted with the attacker's public RSA key. The Group-IB research team described the mailbox calendar as a "covert dead-drop," with HollowGraph retrieving commands from events scheduled within a fixed one-hour window between 22:00 and 23:00 UTC on the far-future date. The hybrid encryption scheme uses separate RSA key pairs for inbound and outbound channels, keeping them cryptographically isolated. A second, unencrypted channel runs over DNS tunneling . HollowGraph refreshes its Microsoft Entra ID (Azure AD) credentials by querying IPv6 AAAA records from the attacker-controlled domain cloudlanecdn[.]com . Each returned IPv6 address yields 14 usable payload bytes, which the malware assembles and decodes as UTF-8 text to update its logAzure.txt configuration file — a file masquerading as a

2026-07-21 原文 →
AI 资讯

Stop writing a parser per site. Run five and let confidence decide.

For a long time I ran product extraction off a database of custom selector configs. Hundreds of retailers, each with its own set of CSS selectors mapped field by field: price here, title there, image over there. It worked. It was also a treadmill. Every retailer that redesigned its frontend silently broke its config, and the maintenance tax grew with every retailer I added. Hundreds of configs is hundreds of things that can rot without telling you, usually right before someone downstream asks why a brand's prices went null. At some point I stopped feeding it. The scraping platform I ran at my last engagement fed a 20M+ product catalogue at millions of pages a day, and the thing that made that survivable wasn't better per-site config. It was leaning on almost no per-site config at all. The pattern Instead of one careful parser per site, run several cheap generic extractors on every page, in parallel: JSON-LD. A huge share of e-commerce pages ship a schema.org/Product block because Google rewards it. It has name, price, currency, availability, images. It's the closest thing to a public API hiding in the HTML. OpenGraph tags. og:title , og:image , product:price:amount . Lower quality than JSON-LD, but present on sites too lazy for structured data, because everyone wants pretty link previews. Microdata / RDFa. Older sites, still surprisingly common outside the US. Embedded state. __NEXT_DATA__ , window.__INITIAL_STATE__ and friends. A JSON blob the site's own frontend hydrates from. Heuristics. A price-shaped string near a currency symbol inside the main content region. The largest above-the-fold image. The h1 . Dumb, and dumb works more often than you'd think. None of these is reliable alone. OG price tags go stale, JSON-LD sometimes describes the wrong variant, heuristics grab the crossed-out "was" price. The trick is you don't pick an extractor. You pick per field, and you let agreement between sources carry the decision. Confidence merge Each extractor emits candida

2026-07-20 原文 →
AI 资讯

Investor Database API: Filter 10,469 VC, Angel, and PE Firms as JSON in 2026

Every founder I know has burned a week building an investor list: digging through Crunchbase profiles tab by tab, copying partner names into a spreadsheet that is stale before the seed round closes. The data you want is simple, firms plus focus plus contacts, and it is weirdly hard to get in bulk. The shortcut I use now is the Startup Investors Data Scraper on Apify, a queryable investor database of 10,469 firms that returns filtered JSON in one call. Disclosure: the Apify links in this post are affiliate links. If you run the Actor, I may earn a referral commission at no extra cost to you. Is there a public API for investor data? Not really. The big commercial databases keep their APIs behind sales calls and paid plans sized for funds, not founders. Free sources are scattered lists and shared spreadsheets with no filters and no freshness guarantees. This Actor takes a different shape: a curated database of 10,469 investment firms (as of December 2025) that you query like an API, filtering by firm type, sector, stage, and country, and paying only for the records you pull. What the investor database API returns The investor database API returns one JSON record per firm: name, type, description, location, website, social links, assets under management, stages, and sector focus, with partner contacts when you ask for them. Field Example Notes firm_name Acme Ventures With firm_description alongside firm_type_name Venture Capital Investor One of 17 firm types firm_country Germany Plus firm_city and firm_state firm_website https://acme.vc Also firm_linkedin_url , crunchbase_url , twitter_url firm_aum $250M Assets under management when known investor_contacts [{ "job_title": "Partner", ... }] Names, titles, LinkedIn URLs, emails when available, and check sizes, with Include_Contacts on Who this is for Founders building a raise pipeline, sales teams selling into VC and PE back offices, and analysts mapping which firms fund a sector. If your CRM needs 200 seed funds with war

2026-07-19 原文 →
AI 资讯

How to Scrape Airbnb Listings and Prices in 2026 (No Code Required)

Heads-up: this post references a tool I built. It's a genuinely useful walkthrough either way — the technique applies to any Airbnb scraping project. If you've ever tried to scrape Airbnb, you already know the two walls you hit: the pages are rendered by JavaScript, and Airbnb aggressively blocks datacenter IPs. Below is the reliable way to get clean Airbnb data in 2026 — listing prices, ratings, coordinates, and discounts — without running a headless browser or babysitting proxies. The key insight: Airbnb ships its data in the HTML You don't need to render the page. Every Airbnb search response embeds the full result set as JSON inside a <script id="data-deferred-state-0"> tag. Parse that and you get structured data straight away — no DOM scraping, no selectors that break on the next redesign. The path to the results is: niobeClientData[*][1].data.presentation.staysSearch.results ├── searchResults[] // ~18 listings per page └── paginationInfo.pageCursors[] // all page cursors, upfront Each listing carries a base64-encoded ID in demandStayListing.id (decode it, take the segment after the last colon, and you have the numeric listing ID for airbnb.com/rooms/<id> ), a price line with discounts, avgRatingLocalized ("4.95 (123)"), and GPS coordinates. The two gotchas Datacenter IPs get blocked. You need residential proxies. If a response comes back without the data-deferred-state marker, you've been served a bot check — rotate to a fresh IP and retry. ~270 result cap per search. Airbnb won't paginate past ~15 pages. To cover a whole market, split into narrower searches (by price band or neighborhood) and dedupe by listing ID. The no-code way If you'd rather not maintain proxy pools and parsers, I published an Airbnb Scraper on Apify that does exactly the above. Paste a location or a full Airbnb search URL (every filter is honored), and get flat JSON/CSV back. curl -X POST "https://api.apify.com/v2/acts/ethanteague~airbnb-scraper/run-sync-get-dataset-items?token=YOUR_TOKE

2026-07-17 原文 →
AI 资讯

Details of Alan Turing’s Voice Encryption System

Really interesting piece of cryptographic history : In November 2023, a large cache of his wartime papers—nicknamed the “Bayley papers”—was auctioned in London for almost half a million U.S. dollars. The previously unknown cache contains many sheets in Turing’s own handwriting, telling of his top-secret “Delilah” engineering project from 1943 to 1945. Delilah was Turing’s portable voice-encryption system, named after the biblical deceiver of men. There is also material written by Bayley, often in the form of notes he took while Turing was speaking. It is thanks to Bayley that the papers survived: He kept them until he died in 2020, 66 years after Turing passed away...

2026-07-17 原文 →