Серія випуску StyloBot: локальний режим відмітки (Українська (Ukrainian))

Серія випуску StyloBot: локальний режим відмітки

Wednesday, 24 June 2026

//

21 minute read

Cloudflare's "Markdown Mode" дає штучний крейлер чистий текст замість відтвореного HTMLM SK3 Оператори StyloBot отримують таку ж здатність за допомогою StyloExtractMSC4 запускаючи локально на вхідній шлюзі Stylo BotМSK5 достатньо швидко, щоб сидіти на гарячій доріжки, без жодних змін на дохідному сайті. Це те, що робить Styloextract\M SK8 як він підключається до Stylobot\Mska9 що собаки з 'їдаються за допомогою lucidVIEW спіймали\Mска10 і що\Mске11 все ще не працює\M Ska12


Що я хотів скопіювати

Cloudflare завантажує функцію, в якій:, якщо відомий штучний crawler просить сторінки , краєчок відповідає за Markdown репозицію тіла, а не повного HTML МSK2 Клівер отримує реальну zawartość без жодного хрома M SK3 без жодної Java-скрипта , без баннеров куки MSC5 Пользователь(а)

Архітектура очевидна ззовні.: classify the request as a crawler (Cloudflare already does this), pull the page through some contentM SK3extraction layerMSC4 project to Markdown, return that instead of the HTMLMSL6 Класифікатор - це цікава частина, якщо ви' Cloudflare and the extractor is the interesting part if you' anybody else(МSK9)

Те ж саме для оператора StyloBot є трьома обмеженнями

  1. Сайт розташований вздовж входу в StyloBot. Cloudflare може служити відміткою, тому що вони є краєм. Мережа входу StyloBot сидить перед витоками, які рухаються вгору, вона не контролюєM SK1 не контролюється, проксигування YARPMSC3 Контент має бути видобуваний на перехресті входу , не в самому витокі і не в якомусь раунді SaaS МSK5 траєкторія. Место, що рухається вгорі, залишається недоторканим
  2. Місцеві. Ні ПайтонM SK1 немає узла, немає окремого сервісу . Перехідник є єдиною AOT-опублікована бінарнаM SK1 Доdanie Python sidecar для HTML до Markdown подолає форму розгортання.
  3. Досить швидко, щоб сидіти на теплому шляху. Якщо "serve Markdown для штучного crawlers" додає 200ms на żądaнняM SK3 оператор вимикає цеMSC4 Бюджет - під МSK5ms pMST6 на кэші hitMSL7 що є тим, що живе всередині існуючого детектора

З боку StyloBot цього вже зроблено: ланцюг детектора класифікує алгоритми crawlers (BotType.AiBot) з такою ж швидкістю - затримкою маршруту, як і будь-який інший вирок DetectionPolicyMiddleware в 7.x надсилає policies дій, названі вироком ,, таким чином проводячи extract-markdown policy для "AiBot на /docsM SK2*" - це конфигурація ♫ ♫ МSK1 ♫ Поганий шматок був самим экстрактором ♫

Те, що's StyloExtract: HTMLM SK2toMSC3Markdown шар, який поєднується з схемою StyloBot 's detectionMST5 Інтеграційний корабель у вигляді маленького пакету адаптаторів МSK6Mostlylucid.BotDetection.StyloExtract) і правило, яке запускає це, це шість рядків JSON . Оператор відкидає пакет в МSK2 додає правило МSK3 і штучний crawler починає отримувати значок вниз за ті самі URL, які досі служать HTML для людей M SK4

Що насправді означає " вилучення знака "" Markdown "" "

Якщо ви читаєте спецификацію на лицевій основі, то це вирішена проблема. Є десятки бібліотек. МСК4. В дійсності, всі вони деградують на реальних сторінках, тому що вони сприймають документ як плоский контент і сторінку як масштабування.

Справжня-світові веб-сторінки - це M SK1 котлована płytа . Artykuł, який ви насправді хочете, живе в двох або трьох обгортаннях <div>s з двох або трьох сотень. Наївний HTMLМSK1на МSK2Biblioteka Маркдау перетворює всеМСК3 кожен наві-конектМ СК4 кожен баннер баннер cookieMСК5 кожен футрM СК6 кожен пов 'язанийМ סК7 пост-сайдбарМ SК8 кожен кнопок обмінуМ ็ СК9 кожен модул, щоM ็ SК10 прихований CSS, але присутній в DOMМ ШК11 Клокер попросив про статтюМ М СК12 ви передали йому цілий файл М ЦСК13 КБ Маркдау з статтю закопаною десь в мережі M ШК14

Отже, екстрактор повинен виконувати дві функції.

  1. Визначати тіло. Який піддерево розшифрованого DOM містить справжній зміст,, а які піддерева - хромM SK1
  2. Створити тіло. Після того, як ви - МСК0 - ізолюєте його, - МSK1 - проектуєте піддерево для позначки, яке зберігає структуру зворотнього читача. МСК2 - людина чи ЛЛМ, ) - піклується про це, - : - ієрархія заголовків, МSK5 - лінії зв 'язку, , - переліки, МСК7 - таблички, М СК8 - кодові блоки, M СК9 - зображення, MСК10

Це найважче визначити. МСК0. У МСК1 є ціла галузь наукової літератури виведення веб-контенту і встановлений Benchmark - WCXB. Коли я почав читати, то знаходився інструментом Python під назвою Trafilatura. Я переніс навантаженняM SK2на основі ідей до .NET та додав шар Trafiluca doesnMSC4t haveMska5 perMske6host навчання з шаблонами за допомогою структурних відбитків пальців.

Форма::

parse HTML → clean → fingerprint the structure → does this fingerprint
  match a template I've seen on this host before?
    yes → apply the cached extractor → render
    no  → run the heuristic classifier → induce a fresh extractor →
          cache it under this host's fingerprint → render

Першого разу, коли ворота бачать сторінку з домашнєї мережі, вони платять за повну эвристичністьM SK1 вартість класифікатора МSK2μs для середньої сторінки). Кожна наступна сторінка з того домашнего сервера, яка відповідає структурному відбитку пальців, отримує замість цього ввімкнений екстрактор , який є лише кількома CSS МSK5 пошуки виборця MSC6 μsMST7 Схожі МСК8host-сторінки з однаковим шаблоном МСК9 яка є більшою частиною веб-сайту M SK10 рухаються по швидкій дорозі . Страні з новими інтерфейсами викликають переробку MSC12

Опинка пальців - це малюнок MinHash над стандартизованим DOM-оточенням маршрутуM SK1 з LSH-бандером на вершині для суб--мільйсекундної зондуМSK3 Математика співпадіння неважлива МSK4 не має значення для цього artykułу ; важливим є те, що це робить навчання за один учасника МСК6 досить дешевим для запуску на кожному запиті М СК7

Похідник

На стороні рендеру є петля, яка дає мені змогу заробляти на цьому.

Перша версія StyloExtract випустила знак Марка-Даун , переміщуючи класифіковані блоки та проектуючи element.TextContent.Trim() в вихідні коди. Кожен блок став абзацомM SK1 Кожен заголовок став # text незважаючи на те, чи це H1 чи HМSK1 Анкори зруйновані до оголеного тексту МSK2 Листи втратили кулі . Блоки коду втратили паркани МСК4 Столи порівнювалися до коми М СК5 відокремлені запуски MСК6

Це технічно "Markdown." Це ' також непотрібно МSK3 crawler asks for Markdown to уникати аналізу хрома, і ми дамо йому стіну абзаців, де єдиний сигнал є інколи простим - текстові знаряддя фрази МSK2 Весь сенс служення Марка-Дауна полягає в тому, що структура несає інформацію

Отже, наступна версія StyloExtract рухається DOM кожного класифікованого блоку контенту і випускає реальні GFM:

  • <h1> через <h6> перетворюється на 1 через МSK1 # символи
  • <a href> стає [text](href)
  • <em> і <strong> підтримувати їх
  • <code> залишає зворотний знак, <pre> стає замкненим блоком з language-x carried across
  • <ul> і <ol> випускати справжні пулі та числові листи
  • <blockquote> примітки кожного рядка з > ( і багатозначнийM SK1запис отримує > body\n>\n> body конвенція)
  • <table> відтворюється за допомогою алгоритму шкали WHATWG- з відповідним розтягом рядків / розтргів рядків
  • Зображення відтворюють як ![alt](src) чи вони "'" вживають в просі, чи самотні <figure>

Глокер - це один StringBuilder на блок , внутрішній буфер скарбів, повторюваний через клітини / списку об 'єктів МSK2 і один перехід через DOM

Похідник - це також частина, яка зламалась першими.

Петячий цикл

lucidVIEW - це маркер-відрізок, який я створив разом з StyloExtract. Продукт - це веб-браузер - сторонній читач, який бере URL M SK2 завантажує його , запускає StyloEXtract над відповіддю MSC4 і показує отриманий маркерні відрізки МSK5 Застосований випадок: " Я хочу прочитати це блоговий пост на повільному підключенні без Java-скрипта Mska7 чи на телефоні без товарного запасу M Ska8 або просто тому, що оригінальна сторінка має око MSKA9 розмиканий CSS Мska10 Втілення - це Styloextract на сервері Mска11 маленький рендератор маркерних відрівок в браузері Мска12 і нічого іншого М Ska13

Те, що lucidVIEW дав мені - це петлю для собаки з зубами. МСК0. Другий випуск StyloBotу, МСК1, серія статей говорить про панель, як про поверхню для собак, МSK2, що МСК3 є правильним на рівні протоколу. МSK4. Але панель читає дані, які генерує детектор, і робить їх я. I'm в циклі МSK2 I\ ' я пробачу багато дивних можливих виходів, якщо підрахунки будуть правильними

lucidVIEW перетворює Маркдау на доштовховий читач (meM SK1 але читає зміст ). Це МSK3 має ту ж форму, як і пристрій для використання Шриверки штучного інтелекту МSK4 хтось споживає мій вихідний код речовина, не в якості інструментарію . Коли виход неправильний МSK2 ви бачите його відразу МСК3 Там М СК4 немає абстрактного шару між М СК5 экстрактор виробив X М ס К6 і М S К7 Я читаю X M С К8

Отож, я відкриваю lucidVIEW, дивлячись на мій власний блоговий індекс. Карти відтворюють . Потім я перегортаю МSK2 Кожен блог МСК3 карта з минулим першим відтворюється як [Post title](/blog/post) - літеральний скобковий текст - замість сліпої, натисливої посилання

unit-test suite є зеленим [Post title](/blog/post). Марка-даун неправильний в будь-якому разі

Клас багів не був би потрачений на тест

Індекс блогу збудований за допомогою Tailwind. вихід Tail wind встромлений для читабельностіM SK1 кожен обкладач div сидить на двох місцях далі, ніж його батьківський . Коли ви дістаєтеся до справжнього анкера для блогуMSC3 карта зв 'язок, джерело HTML виглядає такою ж як

<section class="...">
    <div class="container...">
        <div class="grid...">
            <div class="card...">
                <a href="/blog/post-a">Post title</a>
                ...

Рухник'с текстомМSK1помічник для obsługiM SK2 AppendEscapedInline, рухає runs білого простору в один простір . Всередині одного виклику він робить це правильно МSK2 функція зберігає prevWs прапорець, який пригнічує послідовне виділення білого простору, видає:. Між wywołaннями: , прапорець відпочиняється:

Чотири обкладинки індикації, чотири тексти - нот=- двоє літер з білим простором МSK3 чотири сплющені місця M SK4 Соціальний знак ' встромлений Mska6 код M Ska7 правило блокування реагує на чотири місця [Post title](/blog/post) lands on a line that starts with four spaces. Markdig parses the entire line as a code blockMSC1 The bracket text renders as literal text. The link is deadM SK3

Тест на одиниці проходить, тому що тест затверджує стрічку [Post title](/blog/post) з 'являється десь в вихідному коді.

Постановка - дві лінії: : на лінії, МSK1початкова, , просте число prevWs = true тож першим лідерський білий простір з кожного вузла стає пропущеним замість emitted. Лідерський білій простір всередині встромленої HTML ніколи не досягає вихідного коду

Цікаво те, що тест повинна стверджували. поверхняM SK1текст .Contains() перевіряє символи є присутнім. Вони булиM SK1 Вони просто були в неправильному CommonMark блоковому типу. Все, що мені потрібно було структурна ствердження: розшифровує ходунок ' його вихідний код за допомогою реального комп 'ютера CommonMark, іsert paragraphs are paragraphsM SK2 links are links, no spurious code blocksМSK4 MarkdigMSC5s AST gives you that for freeMska6 Таким чином, виправлення помилки приземлилося з тестом регресії Mska7 and the regression test landed with a lint harnessM Ska8 small helper that takes any walker outputM ska9 parses it with Markdig Mска10 and asserts Мska11

  • Нуль індикованих кодових блоків, якщо не був закритим блоком джерелом
  • Кожен зв 'язок у вихідному HTML виживає як справжній LinkInline в АСТ
  • Перерахунок блоків fenced- відповідає очікуванню

Щоб довести, що lint має зуби, Я повернув оригіналний ремонт і запустив комплект lint. Точнісінько один тест провалився - той, який використовує чотириM SK3 непотрібний МSK4 зразок ковпака . Знову підпорядкувати ремонтMSC6 всі пропущеніMスク7

Ця одна перевірка тепер проходить на кожному тесті на ходунки в наборі.. Дальне відхилення однієї категорії структурно фіксуються. , не через співпадіння стрічок. МSK2 Це означає, що я M SK3 знаходжу їх у CI, а не у lucidVIEW.

в основному зрозуміли.net відтворений у lucidVIEW після vM SK1 walker fix : кожен блог МSK3 посткарта вирішує як справжній клікаючий зв 'язок з його підсумком, як правильний абзац M SK4 замість скобки - текст всередині кодового блоку MSC6

Що насправді вимагає

У кожному продукті є етап, коли тести на одиниці є зеленими і демо працює, і оператор встановлює правильні флаги конфігурації, і ви відправляєте реліз, а через день пользователь відкриває проблему, говорячи: "" МСК1 "", це не працює. МСК2 "", не працює з реальним змістом. МSK3 "". Кожний продукт потрапляє на це. . "". Чесно кажучи, тестові пристрої та контент для демонстрації є стерильними, так само як і реальний контент.

. Фраза """, "" dogfooding "" і "" МSK2 "" вживаються повільно, а в цьому випадку це означає щось специфічне. окремий продукт, з окремими користувачами стається споживати Output StyloExtract' як поверхню продукту. Якщо lucidVIEW показує пошкоджений Маркдау , lucidVIEW МSK2 користувачі скаржаться на lucidVIEW

Ця відокремлення має значення. Якби lucidVIEW був пристроєм для тесту StyloExtract, я б написав його із стерильним вмістом, бо знаю, що подобається екстрактору . Тому що lucidVIEW існує в своєму світі МSK4 він вказує на мій справжній блог МСК5, який використовує Tailwind М СК6, що виробляє встромлений HTML-об 'єкт, що запускає клас багів M СК7 Баг з' явився за п 'ять хвилин використання продукту як користувача MСК8

Багато випущень v1.7.x повертаються до цієї ланцюги . СтруктурованийM SK2виход ходуча (v\1.7.0) відправлений через те, що перша версія lucidVIEWМSK5 була нерозбірливою, коли StyloExtract випустив плоскі абзаци МSK6 ГоловнийMSC7 whitespace fix МСК8v МСК9 відправлен через те що постMСК10version ходучка була помітно зламана на сайтах TailwindМ СК11 ВиходM СК12quality lint harness відправлений тому, що я хотів, щоб наступний клас बगу був CIMSSK13caughtMS.

Pattern' не новий споживацький продукт паралельно з вашим будівельний продукт, і споживайте свою власну інфраструктуру через споживача . Рівень błędów на шарі інфраструктури знизується в залежності від того, наскільки велика поверхня споживача клас Защитність на рівні інфраструктури зростає з кожним наступним моментом, коли споживач зауважує, що ви не думаєте написати тест для

Закритий цикл через стопку

StyloExtract / lucidVIEW - один із прикладів шаблону, який я запускаю на кожному проекті

flowchart LR
    PB[visible product<br/>behaviour] --> TR[test/review<br/>loop]
    TR --> AP[architectural<br/>primitive]
    AP --> RL[reusable<br/>library]
    RL --> WE[written<br/>explanation]
    WE --> LG[LLM-readable<br/>grammar]
    LG --> NP[next<br/>product]
    NP --> PB

База błędów у продукті. Поправка перетворюється на структурне твердження M SK1тест МSK2відкладання циклу МSK3 Затвердження перетворується на примітив, який інші речі можуть використовувати . Примітив перетвориться на бібліотеку \ . Бібліотека пише про . Письмо створює LLM \ МSK7 читабельну граматику довкола кодової бази | МSK8 граматика робить наступний продукт швидшим для побудови | . Наступний продукт накладається на нові баги в бібліотеках, які залежать від нього \

Граф залежності, який це створює – МСК0 – в усіх проектах, які я запускаю. МСК1 – схожий на МСК2

flowchart TB
    LV[lucidVIEW<br/>Avalonia markdown reader]
    SB[StyloBot<br/>detection gateway]
    SF[StyloFlow<br/>policy + flow runtime]
    SE[StyloExtract<br/>HTML → Markdown]
    NA[mostlylucid.Naiad<br/>Mermaid renderer fork]
    DA[mostlylucid.dagre<br/>graph layout]
    EP[mostlylucid.ephemeral<br/>signal + sketch primitives]
    UT[Mostlylucid.Avalonia.UITesting<br/>Avalonia UI test framework]

    SB --> SF
    SB --> SE
    LV --> SE
    LV --> NA
    NA --> DA
    SE --> EP
    SF --> EP
    LV -.tests via.-> UT

Mostlylucid.Avalonia.UITesting закриває еквівалентну петлю на боці робочого столу. StyloExtractM SK1Playwright закриває її на безголовній стороні-web sideMSC3 Те ж саме візерунок , різна поверхня МSK5 тестування M SK6 автоматизація дозволяє аутентичній петлі фактично перевірити поведінку продукту, яку вона повинна була полагодити

Торгівля реальна. Граф неоднозначнаM SK1 Ошибка в mostlylucid.ephemeral протікає через StyloExtract і StyloFlow в StyloBot та lucidVIEW. злегшення - це часMSC1boxed releases M SK2не викривлення funkcji, версії рухаються, коли сфера, яку вони revendicaють, рухаєтьсяМSK4 і кожен шар має свій власний тестовий наборMST5 перевагою є те, що я можу працювати над усіма ними за тиждень, а вартість контексту - перемикання між ними залишається низькоюMSL7 тому що кожна пластина має однакову формуMСК8 примітивну МСК9 бібліотекуMSК10 пояснениеM СК11 споживача М СК12

Це також означає, що написання цієї статті - не "'", а "" МSK1 "", як результат транспортування "" StyloExtract "". МSK2 "". Письмо є одним із етапів.

Це працює для мене, тому що закриваючи цикли - ось як я думаю.

Як lucidVIEW підключає його

flowchart LR
    URL[URL bar] --> Fetch[HttpClient GET<br/>Accept: text/markdown, text/html]
    Fetch --> Sniff{Content-Type}
    Sniff -->|text/markdown| Render[LiveMarkdown.Avalonia]
    Sniff -->|text/html| Convert[HtmlToMarkdownService]
    Convert --> Sparse{< 200 chars +<br/>SPA markers?}
    Sparse -->|yes| Stub[Stub: needs JS,<br/>open in browser?]
    Sparse -->|no| Render
    Stub --> Render

Чотири описи пакетів і одна служба:

public sealed class HtmlToMarkdownService
{
    private readonly IHtmlDomParser _parser = new AngleSharpHtmlDomParser();
    private readonly IDomCleaner _cleaner = new DomCleaner();
    private readonly IBlockSegmenter _segmenter = new BlockSegmenter();
    private readonly IBlockClassifier _classifier =
        HeuristicBlockClassifier.LoadFromEmbeddedResources();
    private readonly IMarkdownRenderer _renderer = new TypedMarkdownRenderer();

    public string Convert(string html, Uri? sourceUri = null)
    {
        var doc = _parser.Parse(html, sourceUri);
        _cleaner.Clean(doc);
        var blocks = _classifier.Classify(_segmenter.Segment(doc));
        return _renderer.Render(blocks, ExtractionProfile.RagFull);
    }
}

Те, що ' це те, що МSK1 Статус МSK2 іконка панелі показує, який шлях був запущений МSK3 прямий MD / конвертований एमСК5 SPAstub мСК6 так, що коли щось виглядає неправильно, пользователь може показати правильний шар МСК7

Вікіпедія's Марка-даун статті, представленої всередині lucidVIEW через StyloExtract : ієрархія заголовків непошкоджена

Трубопровод МСК0 по етапам

flowchart LR
    HTML[HTML] --> P[AngleSharpHtmlDomParser]
    P --> C[DomCleaner<br/>strip script/style]
    C --> S[BlockSegmenter<br/>candidate subtrees]
    S --> K[HeuristicBlockClassifier<br/>role + score]
    K --> W[DomMarkdownWalker<br/>GFM per block]
    W --> R[TypedMarkdownRenderer<br/>profile gate]
    R --> MD[Markdown]

Розшифровувач + чистіший - це упаковники AngleSharp . Цікавий код починається з сегментації МSK2

Сегментер. Пройдіть тіло, зануріть будь-яку семантичну позначку M SK1main/article/section/h1-h6/ul/pre/...) плюс будь-яка <div>/<section> що МСК0 текст МSK1 важкий або має багато дітей . Все інше надто маленьке, щоб бути задоволеним

public IReadOnlyList<IElement> Segment(IDocument document)
{
    if (document.Body is null) return Array.Empty<IElement>();
    var result = new List<IElement>();
    Walk(document.Body, result);
    return result;
}

private static void Walk(IElement element, List<IElement> sink)
{
    if (SemanticTags.Contains(element.TagName))   sink.Add(element);
    else if (IsBlockyDiv(element))                sink.Add(element);
    foreach (var child in element.Children) Walk(child, sink);
}

Классifier. Оцінка кожного кандидата: МСК0 , Не вибирайте "-". Перетинаються лауреати . BlockRole (Главний змістM SK1 ЗаголовокМSK2 Навігація, Котелляна плитаMSC4 Повторне об 'єктMska5 Мska6 Кожен вибраний блок отримує DOM, який переходить в структурований знакопадMска7

foreach (var element in selected)
{
    var role = ClassifyRole(element);
    yield return new ExtractedBlock
    {
        Role     = role,
        Text     = element.TextContent.Trim(),
        Markdown = ShouldRenderMarkdown(role) ? DomMarkdownWalker.Render(element) : "",
        Links    = ExtractLinks(element),
        XPath    = XPathBuilder.For(element),
        // ...
    };
}

Вокер. Один StringBuilder, один DOM pass. <a> це місце, де проживав баг v1.7.1

case "a":
    var href = el.GetAttribute("href") ?? "";
    if (href.Length == 0) { WriteInlineChildren(dest, el); return; }
    dest.Append('[');
    WriteInlineChildren(dest, el);
    dest.Append("](").Append(href).Append(')');
    return;

( Це був виправленням ' тут не було МSK2 Це було в AppendEscapedInline,, що fed провідного білого простору в dest до того, як цей випадок коли-небудь працював. Чотири місця попереду [ дозволяє CommonMark аналізувати строк як кодовий блок.)

Рендерер. Двері по профілі. RagFull зберігає статтю-контекст M SK1Breadcrumb, Спільні зв 'язкиMSC3 і викидає хром (FooterMST5 HeaderM ST6 CookieBannerM st7 NavMst8 MainContentOnly зберігає лише тіло. AgentNavigation зберігає тільки наві ( для плавання - відкриток зв 'язку M SK2

return p switch
{
    ExtractionProfile.RagFull => b.Role is not (BlockRole.Footer or BlockRole.Header
        or BlockRole.Advertisement or BlockRole.CookieBanner or BlockRole.Boilerplate
        or BlockRole.Unknown or BlockRole.PrimaryNavigation or BlockRole.SecondaryNavigation),
    ExtractionProfile.MainContentOnly => b.Role is BlockRole.MainContent or BlockRole.Article
        or BlockRole.Heading or BlockRole.Summary or BlockRole.Table or BlockRole.CodeBlock
        or BlockRole.RepeatedItem,
    ExtractionProfile.AgentNavigation => b.Role is BlockRole.PrimaryNavigation
        or BlockRole.SecondaryNavigation or BlockRole.Breadcrumb or BlockRole.Form,
    _ => true
};

Playwright для веб-сторінок JS-

StyloExtract'his heuristic operates on the static HTML the server returned . ThatMSC2s fine for SSR sites M SK3Wikipedia, GitHubMska5 most news article URLsMSKA6 It breaks on SPA shells where the visible content is hydrated client Mska7side from a JSON blobM Ska8 __NEXT_DATA__, __NUXT__, __APOLLO_STATE__. Статичний HTML має мета-теги + скелет МSK2 і немає тіла для класифікатора, щоб знайти

Mostlylucid.StyloExtract.Playwright підключення вздовж трубопроводу. Він реалізує IRenderedHtmlFetcher, підштовхує безголовний хром через Playwright , чекає на впиту МSK2 і повертає постM SK3 JS HTML до решти экстрактора :

public async Task<RenderedHtmlResult> FetchAsync(
    Uri uri, RenderOptions? options = null, CancellationToken cancellationToken = default)
{
    var page = await _context.NewPageAsync();
    await page.GotoAsync(uri.ToString(), new PageGotoOptions
    {
        WaitUntil = WaitUntilState.NetworkIdle,
        Timeout = options?.NavigationTimeoutMs ?? 15000,
    });
    var html = await page.ContentAsync();
    await page.CloseAsync();
    return new RenderedHtmlResult { Html = html, FinalUrl = page.Url };
}

Те ж саме Parser, ,, чистіший, МSK1, сегментатор, МСК2, класифікатор, MСК3, ходівник, M СК4, рендератор вниз по течії, М СК5. Єдина різниця в тому, що вхідний HTML зараз містить гидратований DOM, який створив ДС

flowchart LR
    URL[URL] --> Choice{Render mode}
    Choice -->|static| HTTP[HttpClient]
    Choice -->|js-required| PW[PlaywrightHtmlFetcher<br/>headless Chromium]
    HTTP --> Pipeline[parse → clean → segment<br/>→ classify → walk → render]
    PW --> Pipeline
    Pipeline --> MD[Markdown]

Це правильне рішення, коли оператор запускає сервер StyloExtract-замість безголовного браузера є розумною залежністюM SK1 CLI відправляє два бінарні для точного поділу: stylo-extract МSK0AOT, МSK2MBM SK3 статичний- тількиMSC5 і stylo-extract-playwright (~120MB один раз Playwright ' пакет браузера політає МSK2 JS

lucidVIEW не використовує його. lucidVIEW - маркер-відрізок; його ідентичність M SK1 без хрома , без браузерного двигуна МSK3 без МSK4 Мб залежності від однієї характеристики M SK5 Bundling Playwright помістить безголовний браузер всередині додатку, чия тональність - відсутність однієї. . Стап SPA, що описаний poniżej, є правильним відповіддю lucidVIEW М SK7 з точки зору МSK8 сказати користувачам, що сторінка потребує браузеру.

Інші речі, пов 'язані з їжею собак

Чотири не "-", що сформували lucidVIEW , МSK1 , невдачі ,

  • Спектр, який керував v1.7.0. Перші emitовані плоскі абзаци (element.TextContent.Trim() за блок. МСК0. Вікіпедія була нерозбірливою. МSK1. Карти блогу втратили кожну лінію. .. Натомість, я написав: docs/styloextract-markdown-spec.md вираховуючи, що бракувало: рівні заголовківM SK1 ланцюгові запуски , переліки МSK3 таблиці ГФМ МСК4 блокові зображення М СК5 з чотирма URL-адресами репродукторів M СК6 Структурований MСК7 пішохідна робота в vMСК8 реалізує це.

  • Страницы SPA. bbc.com/news Next.js: статичний HTML - це мета-теги + a __NEXT_DATA__ JS. StyloExtract правильно повертає M SK1 символ, тому що ' не має тіла МSK3 lucidVIEW тепер понюхає для відомих маркерів кар 'єри МSK4__NEXT_DATA__, __NUXT__, __APOLLO_STATE__, data-reactroot, ng-version=, __REMIX_DATA__) іM SK1 на вузькому выході + маркер МSK3 робить неправильний МSK4 "Ta сторінка використовує {フレーмワークM SK2 lucidVIEW не запускає JavaScript. Відкрий у браузеріMSC4 Article URLs (/news/articles/<id>) служи реальним <main> і перетворити чисто. Веб-сайт МSK1 асимметрія artykułуM SK2 не поганий конвертер.

    lucidVIEW завантажує bbc.comMSC1новостиM SK2 визначає наступнеMST3js, робить уривок, пояснюючи клієнтаMСК5боє відображання не піддеряєтьсяМСК6 не пропонує відкритийM СК7в МСК8заказ браузеруMSК9 Статус-бар показує попередженняMШК10источник трикутникаМШК11Symbol trybу плюс MСК12клиентM ШК13боці відображеніМ ШК14 неможлива конфігураціяМ СК15тегиМ SК16

  • Семантика-бесплатні сторінкиМSK1 example.com не має <main>, ні <article>. Хирологія правильно не повертає нічого . Такий же стрімкий потік запам 'ятовує це M SK2

  • Правильно-ноM SK1непотрібне випромінювання . Filtr категорії мого блогу' це <select><option>. Похідник не знаходить нічого <a href>, видає текст варіанту як один абзац "Це все МSK1NET МSK2 мSK3s M(1) АCP МСК5 штучний інтелект МК6 Правильно (можливими варіантами є МSK1 не пов 'язані с' язки МSK2 але візуально жахливі . майбутній прохідник може виявити <select> і видавати список визначення, або [42 categories] підсумок.

До того ж, одна галерея, що з 'явилася, опираючись на очевидний короткий шлях. . Коли видобуток є невеликим, спокушання наступне: " повертаєшся до Джина Reader МSK2 r МSK3 Джина мSK4 Ай एमSK5 Трафілатура \ ." \ lucidVIEW не робить \ МSK7 \ t \ . \ Перевод URL-адреса користувача через третю \ МSK9 \ сторонній читач робить читачем витіком конфіденциальності. | ; \ кожен URL, який відвідує користувача, проходить через якийсь інший оператор. ' \ журнали. ♪ МSK12 \ Лінія зворотнього зв' язку залишається локальною. ♫ : \ прямий відбиток \ мSK14 \ а потім HTML через StyloExtract | МSK15 \ і метаданніstub з <meta> / og: ярлики, потім M SK1открий у браузері ?" кожен крок StyloExtract інший вихід з одного і того ж джерела, або синтезує дані, які ми вже маємо

Невизначна різниця у поширенні сайтів

Що собакова ланцюжка добре знаходить, це поламаний результат на хорошому.

Я маю курити-бігача зараз, що бере дюжину реальнихМSK1світніх сайтів і відкидає экстрактораM SK2 виході. На структурно kooperatивній півкулі МSK4 новини ( BBCMSC6 ГуардіанMСК7 Вікіпедія МСК8 репозиція GitHub READMEsМСК9 Призрака М СК10 ҐорґМ СК11 журнал змін M СК12 хакерські новини | МССК13 герістичний класифікатор знаходить головний контент чисто, а ходівник виробляє читача | MСК14 рейтинги знизування маркеру | ССК15 десят до тридцяти кілобайт чистої прозі на сторінку | ВСК16

На іншій половині - Allbirds нічого. Нуль блоків контенту MainContent . Кожен кандидат отримує демоцію на boilerplate, тому що сторінка не використовує <main> або <article> і назви класів не співпадають з будь-якими шаблонами в рамках

Додавати більше записів до цього файлу JSON є очевидним кроком.. Це ' також ламати-aMSC3moleM SK4 Кожний тематичний магазин відправляє нові назви класів.МSK5 Кожна релізація Shopify змінює їх.

Справжньою справою є тренована модель. ПерМSK1дібні характеристики елементів M SK2 ідентифікація знаку МSK3 клас - назви хеш-букетів М SK5 текст M SK6 довжина , зв 'язок MSC8 щільність MSL9 фігура братів і сестер МСК10 присутність предків М СК11 до маленького відхилення М סК12 закріплений класифікатор М S К13 тренований на корпусі з маркуванням WCXB M С К 14 вивезений до ONNX М С К 15 викликаний з М С К 16 NET через Microsoft.ML.OnnxRuntime. Вektor властивості МSK1 на кожного кандидата МSK2 ~10μс висновків на один елемент \ , \ \ МSK5 \ MB модельного файлу , \ AOT \ мSK7 \ чистий \ . \ Модель збільшує геристичне число \ {\displaystyle {-} , воно не заміняє } МSK10 \ } не заміщає його \ '-\ , стимулюючи елементи герістичне число, що погіршується, коли рівень самодовіри є високим \

Дизайн для цього розроблений в repo StyloExtract (docs/ml-classifier-v2-design.md). Implementation is notM SK1t done. The thing it 's blocked on isnMSL4t engineering effortM SL5 itMsl6s the operator question of МSL7 ship a МSL8 MB ONNX Runtime native binary into the gatewayMKL9s deploymentMCL10 or keep ML as a separate optional pack the operator opts intoM CL11 The optional MKL12pack answer is the right one for a FOSS pack ecosystemM KL13 but it means the model is MSL14t on by defaultM LKL15 which means most operators won M CL16t get it М CL17 which mean the heuristic carries most of the production load anyway MCL18

В проміжній періоді - МСК0 - оператори отримують ручний escape hatch, :, оператор, МSK1, авторизовані шаблони YAML, МСК2, один файл на домашню установку, MСК3, розшифрований AOT, M СК4, чистий, М СК5, гарячий, М S К6, переважаючи провідник для цього домашнєї установки. weird-shopify-tenant.com виробляє пустий знак "" Markdown "", ",", пише файл YAML з п 'ятьма лініями "" МSK1 "", в якому написано: """ для цього хоста, "". .product-description-body", кидає його в config/templates/, і час запуску підбирає його через FileSystemWatcher за кілька секунд

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.