@nitpicker/crawler 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/archive/archive-accessor.d.ts +56 -0
- package/lib/archive/archive-accessor.js +72 -0
- package/lib/archive/archive.d.ts +108 -9
- package/lib/archive/archive.js +109 -7
- package/lib/archive/body-hash/compute-body-hash.d.ts +22 -0
- package/lib/archive/body-hash/compute-body-hash.js +31 -0
- package/lib/archive/body-hash/extract-body.d.ts +18 -0
- package/lib/archive/body-hash/extract-body.js +29 -0
- package/lib/archive/body-hash/mask-dynamic-ids.d.ts +33 -0
- package/lib/archive/body-hash/mask-dynamic-ids.js +44 -0
- package/lib/archive/body-hash/normalize-url-like-strings.d.ts +16 -0
- package/lib/archive/body-hash/normalize-url-like-strings.js +19 -0
- package/lib/archive/cache/clear-archive-cache-entry.d.ts +19 -0
- package/lib/archive/cache/clear-archive-cache-entry.js +25 -0
- package/lib/archive/cache/clear-archive-cache-root.d.ts +26 -0
- package/lib/archive/cache/clear-archive-cache-root.js +32 -0
- package/lib/archive/cache/list-archive-cache-entries.d.ts +23 -0
- package/lib/archive/cache/list-archive-cache-entries.js +125 -0
- package/lib/archive/cache/path-exists.d.ts +9 -0
- package/lib/archive/cache/path-exists.js +18 -0
- package/lib/archive/cache/types.d.ts +33 -0
- package/lib/archive/cache/types.js +1 -0
- package/lib/archive/create-adjunct-tables.d.ts +18 -0
- package/lib/archive/create-adjunct-tables.js +277 -0
- package/lib/archive/create-entity-tables.d.ts +14 -0
- package/lib/archive/create-entity-tables.js +52 -1
- package/lib/archive/database.d.ts +91 -2
- package/lib/archive/database.js +128 -0
- package/lib/archive/db-ops/_shared/clear-write-ref-caches.js +1 -0
- package/lib/archive/db-ops/_shared/compress-payload.d.ts +26 -0
- package/lib/archive/db-ops/_shared/compress-payload.js +30 -0
- package/lib/archive/db-ops/_shared/create-write-ref-caches.js +1 -0
- package/lib/archive/db-ops/_shared/types.d.ts +2 -0
- package/lib/archive/db-ops/_shared/upsert-json-ref.js +3 -3
- package/lib/archive/db-ops/analysis/replace-page-templates.d.ts +29 -0
- package/lib/archive/db-ops/analysis/replace-page-templates.js +84 -0
- package/lib/archive/db-ops/analysis/types.d.ts +61 -0
- package/lib/archive/db-ops/analysis/types.js +1 -0
- package/lib/archive/db-ops/config/info-column-allowlist.js +1 -0
- package/lib/archive/db-ops/console-logs/compute-console-log-hash.d.ts +19 -0
- package/lib/archive/db-ops/console-logs/compute-console-log-hash.js +30 -0
- package/lib/archive/db-ops/console-logs/replace-console-logs.d.ts +34 -0
- package/lib/archive/db-ops/console-logs/replace-console-logs.js +123 -0
- package/lib/archive/db-ops/console-logs/stringify-console-log-args.d.ts +16 -0
- package/lib/archive/db-ops/console-logs/stringify-console-log-args.js +26 -0
- package/lib/archive/db-ops/console-logs/types.d.ts +38 -0
- package/lib/archive/db-ops/console-logs/types.js +1 -0
- package/lib/archive/db-ops/console-logs/upsert-console-log-item.d.ts +29 -0
- package/lib/archive/db-ops/console-logs/upsert-console-log-item.js +52 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.d.ts +11 -0
- package/lib/archive/db-ops/errors/list-dns-burned-host-candidates.js +21 -4
- package/lib/archive/db-ops/inventory/record-inventory-run.js +1 -0
- package/lib/archive/db-ops/lifecycle/init.d.ts +25 -10
- package/lib/archive/db-ops/lifecycle/init.js +39 -10
- package/lib/archive/db-ops/meta/get-audios-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-audios-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-buttons-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-buttons-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-canvases-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-canvases-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-headings-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-headings-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-iframes-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-iframes-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-main-content-images-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-main-content-images-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-main-content-tables-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-main-content-tables-of-page.js +15 -0
- package/lib/archive/db-ops/meta/get-videos-of-page.d.ts +11 -0
- package/lib/archive/db-ops/meta/get-videos-of-page.js +15 -0
- package/lib/archive/db-ops/outages/close-network-outage.d.ts +12 -0
- package/lib/archive/db-ops/outages/close-network-outage.js +15 -0
- package/lib/archive/db-ops/outages/close-stale-open-network-outages.d.ts +26 -0
- package/lib/archive/db-ops/outages/close-stale-open-network-outages.js +42 -0
- package/lib/archive/db-ops/outages/compute-outage-clamp-timestamp.d.ts +26 -0
- package/lib/archive/db-ops/outages/compute-outage-clamp-timestamp.js +31 -0
- package/lib/archive/db-ops/outages/insert-network-outage.d.ts +14 -0
- package/lib/archive/db-ops/outages/insert-network-outage.js +29 -0
- package/lib/archive/db-ops/outages/list-network-outages.d.ts +28 -0
- package/lib/archive/db-ops/outages/list-network-outages.js +42 -0
- package/lib/archive/db-ops/pages/read/build-page-query.js +1 -1
- package/lib/archive/db-ops/pages/reset/repromote-external-pages.js +19 -10
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.d.ts +18 -3
- package/lib/archive/db-ops/pages/reset/reset-failed-pages.js +48 -10
- package/lib/archive/db-ops/pages/write/insert-audios.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-audios.js +25 -0
- package/lib/archive/db-ops/pages/write/insert-buttons.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-buttons.js +29 -0
- package/lib/archive/db-ops/pages/write/insert-canvases.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-canvases.js +26 -0
- package/lib/archive/db-ops/pages/write/insert-headings.d.ts +15 -0
- package/lib/archive/db-ops/pages/write/insert-headings.js +27 -0
- package/lib/archive/db-ops/pages/write/insert-iframes.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-iframes.js +28 -0
- package/lib/archive/db-ops/pages/write/insert-main-content-images.d.ts +20 -0
- package/lib/archive/db-ops/pages/write/insert-main-content-images.js +32 -0
- package/lib/archive/db-ops/pages/write/insert-main-content-tables.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-main-content-tables.js +29 -0
- package/lib/archive/db-ops/pages/write/insert-page.js +15 -2
- package/lib/archive/db-ops/pages/write/insert-videos.d.ts +14 -0
- package/lib/archive/db-ops/pages/write/insert-videos.js +28 -0
- package/lib/archive/db-ops/pages/write/update-page.js +33 -0
- package/lib/archive/db-ops/pages/write/write-page-html-blob.js +6 -6
- package/lib/archive/filesystem/output-binary.d.ts +12 -0
- package/lib/archive/filesystem/output-binary.js +17 -0
- package/lib/archive/get-failed-page-messages.d.ts +20 -8
- package/lib/archive/get-failed-page-messages.js +29 -15
- package/lib/archive/init-schema.js +2 -1
- package/lib/archive/meta/compute-main-contents-denormalized.d.ts +22 -0
- package/lib/archive/meta/compute-main-contents-denormalized.js +63 -0
- package/lib/archive/meta/types.d.ts +263 -0
- package/lib/archive/migrate-content-items-alias-of-id.d.ts +47 -0
- package/lib/archive/migrate-content-items-alias-of-id.js +58 -0
- package/lib/archive/migrate-info-main-content-selector.d.ts +11 -0
- package/lib/archive/migrate-info-main-content-selector.js +24 -0
- package/lib/archive/migrate-inventory-runs-invalid-skipped.d.ts +11 -0
- package/lib/archive/migrate-inventory-runs-invalid-skipped.js +24 -0
- package/lib/archive/migrate-main-contents-columns.d.ts +21 -0
- package/lib/archive/migrate-main-contents-columns.js +50 -0
- package/lib/archive/migrate-page-meta-body-hash.d.ts +39 -0
- package/lib/archive/migrate-page-meta-body-hash.js +52 -0
- package/lib/archive/migrate-page-meta-console-error-count.d.ts +22 -0
- package/lib/archive/migrate-page-meta-console-error-count.js +34 -0
- package/lib/archive/page.d.ts +145 -3
- package/lib/archive/page.js +195 -0
- package/lib/archive/types.d.ts +86 -2
- package/lib/archive/url-alias/compute-tier-a-alias-key.d.ts +31 -0
- package/lib/archive/url-alias/compute-tier-a-alias-key.js +36 -0
- package/lib/archive/url-alias/compute-tier-b-alias-key.d.ts +19 -0
- package/lib/archive/url-alias/compute-tier-b-alias-key.js +30 -0
- package/lib/archive/url-alias/format-alias-key.d.ts +13 -0
- package/lib/archive/url-alias/format-alias-key.js +14 -0
- package/lib/archive/url-alias/parse-alias-key-parts.d.ts +15 -0
- package/lib/archive/url-alias/parse-alias-key-parts.js +40 -0
- package/lib/archive/url-alias/types.d.ts +7 -0
- package/lib/archive/url-alias/types.js +1 -0
- package/lib/crawler/choose-probe-host.d.ts +24 -0
- package/lib/crawler/choose-probe-host.js +38 -0
- package/lib/crawler/clear-dns-burned-host-cache.js +2 -0
- package/lib/crawler/crawler.js +261 -2
- package/lib/crawler/dns-burned-host-burn-timestamps.d.ts +17 -0
- package/lib/crawler/dns-burned-host-burn-timestamps.js +17 -0
- package/lib/crawler/evict-network-classified-destination-cache-entries.d.ts +26 -0
- package/lib/crawler/evict-network-classified-destination-cache-entries.js +34 -0
- package/lib/crawler/evict-outage-tainted-dns-burns.d.ts +23 -0
- package/lib/crawler/evict-outage-tainted-dns-burns.js +26 -0
- package/lib/crawler/fetch-destination.js +2 -0
- package/lib/crawler/link-to-page-data.js +2 -0
- package/lib/crawler/network-gate.d.ts +49 -0
- package/lib/crawler/network-gate.js +78 -0
- package/lib/crawler/network-outage-detector.d.ts +51 -0
- package/lib/crawler/network-outage-detector.js +81 -0
- package/lib/crawler/network-outage-summary-counter.d.ts +21 -0
- package/lib/crawler/network-outage-summary-counter.js +18 -0
- package/lib/crawler/probe-network.d.ts +26 -0
- package/lib/crawler/probe-network.js +21 -0
- package/lib/crawler/resource-to-page-data.js +2 -0
- package/lib/crawler/types.d.ts +152 -1
- package/lib/crawler-orchestrator.d.ts +62 -18
- package/lib/crawler-orchestrator.js +163 -26
- package/lib/crawler.d.ts +21 -0
- package/lib/crawler.js +17 -0
- package/lib/is-within-outage-window.d.ts +49 -0
- package/lib/is-within-outage-window.js +33 -0
- package/lib/network-related-error-kinds.d.ts +23 -0
- package/lib/network-related-error-kinds.js +28 -0
- package/lib/types.d.ts +9 -1
- package/lib/utils/array/each-splitted.d.ts +1 -1
- package/lib/utils/compute-file-sha256.d.ts +17 -17
- package/lib/utils/compute-file-sha256.js +18 -47
- package/package.json +3 -3
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds the `page_meta.body_hash` column to archives created before this
|
|
3
|
+
* feature, then ensures its index exists.
|
|
4
|
+
*
|
|
5
|
+
* `page_meta` is provisioned via a bare `CREATE TABLE IF NOT EXISTS` in
|
|
6
|
+
* {@link import('./create-entity-tables.js').createEntityTables}, which
|
|
7
|
+
* self-heals a *missing table* on every `initSchema` call but is a no-op
|
|
8
|
+
* against an *existing* table — adding a column to the DDL string never
|
|
9
|
+
* reaches an archive whose `page_meta` predates this change. This mirrors
|
|
10
|
+
* {@link import('./migrate-main-contents-columns.js').migrateMainContentsColumns}'s
|
|
11
|
+
* catch-up: a `hasColumn`-guarded `ALTER TABLE` for the one column
|
|
12
|
+
* `CREATE TABLE IF NOT EXISTS` cannot retrofit.
|
|
13
|
+
*
|
|
14
|
+
* The index is created here — unconditionally, after the column-add guard,
|
|
15
|
+
* not inside `createEntityTables`'s DDL — for both a fresh archive (where
|
|
16
|
+
* `body_hash` already exists from the DDL, so only the index still needs
|
|
17
|
+
* creating) and a legacy archive (where the column is added just above,
|
|
18
|
+
* then the index follows in the same call). `createEntityTables` runs
|
|
19
|
+
* unconditionally on every archive open, including legacy archives that
|
|
20
|
+
* still lack `body_hash` at that point; an unconditional
|
|
21
|
+
* `CREATE INDEX ... body_hash` there would fail with `no such column` before
|
|
22
|
+
* this migration ever runs. This function is the one place guaranteed to
|
|
23
|
+
* run only after the column is confirmed present, for both archive kinds.
|
|
24
|
+
*
|
|
25
|
+
* Only adds the column and its index — it does not backfill values for
|
|
26
|
+
* existing rows (they stay `NULL`). That backfill runs separately, from
|
|
27
|
+
* `backfillBodyHashFromHtmlBlobs` during a viewer-read-model build, since it
|
|
28
|
+
* requires decompressing every page's stored HTML and is too heavy to run on
|
|
29
|
+
* every archive open.
|
|
30
|
+
*
|
|
31
|
+
* Idempotent: adding the column is a no-op once it exists (the index
|
|
32
|
+
* creation always runs, but `IF NOT EXISTS` makes repeat runs a no-op too).
|
|
33
|
+
* Guards on `page_meta`'s existence defensively, though by the time this
|
|
34
|
+
* runs (after `initSchema`, itself after `assertCompatibleVersion` rejects
|
|
35
|
+
* pre-0.13 archives) the table is always present.
|
|
36
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
37
|
+
*/
|
|
38
|
+
export async function migratePageMetaBodyHash(instance) {
|
|
39
|
+
const hasPageMeta = await instance.schema.hasTable('page_meta');
|
|
40
|
+
if (!hasPageMeta) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const hasColumn = await instance.schema.hasColumn('page_meta', 'body_hash');
|
|
44
|
+
if (!hasColumn) {
|
|
45
|
+
await instance.schema.table('page_meta', (t) => {
|
|
46
|
+
t.binary('body_hash');
|
|
47
|
+
});
|
|
48
|
+
// eslint-disable-next-line no-console
|
|
49
|
+
console.error('[migrate] page_meta.body_hash column added');
|
|
50
|
+
}
|
|
51
|
+
await instance.raw('CREATE INDEX IF NOT EXISTS idx_page_meta_body_hash ON page_meta(body_hash)');
|
|
52
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
/**
|
|
3
|
+
* Adds the `page_meta.console_error_count` column to archives created
|
|
4
|
+
* before this feature (issue #228).
|
|
5
|
+
*
|
|
6
|
+
* `page_meta` is provisioned via a bare `CREATE TABLE IF NOT EXISTS` in
|
|
7
|
+
* {@link import('./create-entity-tables.js').createEntityTables}, which
|
|
8
|
+
* self-heals a *missing table* on every `initSchema` call but is a no-op
|
|
9
|
+
* against an *existing* table — adding a column to the DDL string never
|
|
10
|
+
* reaches an archive whose `page_meta` predates this change. Same
|
|
11
|
+
* catch-up shape as {@link import('./migrate-page-meta-body-hash.js').migratePageMetaBodyHash}.
|
|
12
|
+
*
|
|
13
|
+
* Unlike `body_hash`, there is no separate backfill step: a page that has
|
|
14
|
+
* never been re-scraped since this feature shipped has no
|
|
15
|
+
* `page_console_logs` rows either, so `0` (the value `replaceConsoleLogs`
|
|
16
|
+
* writes for a page with no error/pageerror entries) is already the
|
|
17
|
+
* correct value, not a placeholder pending backfill.
|
|
18
|
+
*
|
|
19
|
+
* Idempotent: adding the column is a no-op once it exists.
|
|
20
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
21
|
+
*/
|
|
22
|
+
export declare function migratePageMetaConsoleErrorCount(instance: Knex): Promise<void>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds the `page_meta.console_error_count` column to archives created
|
|
3
|
+
* before this feature (issue #228).
|
|
4
|
+
*
|
|
5
|
+
* `page_meta` is provisioned via a bare `CREATE TABLE IF NOT EXISTS` in
|
|
6
|
+
* {@link import('./create-entity-tables.js').createEntityTables}, which
|
|
7
|
+
* self-heals a *missing table* on every `initSchema` call but is a no-op
|
|
8
|
+
* against an *existing* table — adding a column to the DDL string never
|
|
9
|
+
* reaches an archive whose `page_meta` predates this change. Same
|
|
10
|
+
* catch-up shape as {@link import('./migrate-page-meta-body-hash.js').migratePageMetaBodyHash}.
|
|
11
|
+
*
|
|
12
|
+
* Unlike `body_hash`, there is no separate backfill step: a page that has
|
|
13
|
+
* never been re-scraped since this feature shipped has no
|
|
14
|
+
* `page_console_logs` rows either, so `0` (the value `replaceConsoleLogs`
|
|
15
|
+
* writes for a page with no error/pageerror entries) is already the
|
|
16
|
+
* correct value, not a placeholder pending backfill.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: adding the column is a no-op once it exists.
|
|
19
|
+
* @param instance - The Knex query builder instance connected to the database.
|
|
20
|
+
*/
|
|
21
|
+
export async function migratePageMetaConsoleErrorCount(instance) {
|
|
22
|
+
const hasPageMeta = await instance.schema.hasTable('page_meta');
|
|
23
|
+
if (!hasPageMeta) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const hasColumn = await instance.schema.hasColumn('page_meta', 'console_error_count');
|
|
27
|
+
if (!hasColumn) {
|
|
28
|
+
await instance.schema.table('page_meta', (t) => {
|
|
29
|
+
t.integer('console_error_count');
|
|
30
|
+
});
|
|
31
|
+
// eslint-disable-next-line no-console
|
|
32
|
+
console.error('[migrate] page_meta.console_error_count column added');
|
|
33
|
+
}
|
|
34
|
+
}
|
package/lib/archive/page.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Anchor, Redirect, Referrer, DB_Anchor, DB_Page, DB_Redirect, DB_Re
|
|
|
9
9
|
* Keep in sync with {@link import('./meta/types.js').FlatPageMetaColumns} —
|
|
10
10
|
* one row of `pages` has the same shape.
|
|
11
11
|
*/
|
|
12
|
-
declare const FLAT_META_COLUMNS: readonly ["lang", "dir", "charset", "baseHref", "viewport_raw", "themeColor", "applicationName", "author", "generator", "publisher", "title", "description", "keywords", "robots_raw", "robots_noindex", "robots_nofollow", "robots_noarchive", "robots_noimageindex", "googlebot", "canonical", "amphtml", "manifest", "icon_href", "appleTouchIcon_href", "og_type", "og_title", "og_url", "og_site_name", "og_description", "og_image", "og_image_alt", "og_image_width", "og_image_height", "og_locale", "og_article_published_time", "og_article_modified_time", "twitter_card", "twitter_site", "twitter_creator", "twitter_title", "twitter_description", "twitter_image", "fb_app_id", "verification_google", "formatDetection_telephone", "tag_count", "jsonld_count", "tags_providers_csv"];
|
|
12
|
+
declare const FLAT_META_COLUMNS: readonly ["lang", "dir", "charset", "baseHref", "viewport_raw", "themeColor", "applicationName", "author", "generator", "publisher", "title", "description", "keywords", "robots_raw", "robots_noindex", "robots_nofollow", "robots_noarchive", "robots_noimageindex", "googlebot", "canonical", "amphtml", "manifest", "icon_href", "appleTouchIcon_href", "og_type", "og_title", "og_url", "og_site_name", "og_description", "og_image", "og_image_alt", "og_image_width", "og_image_height", "og_locale", "og_article_published_time", "og_article_modified_time", "twitter_card", "twitter_site", "twitter_creator", "twitter_title", "twitter_description", "twitter_image", "fb_app_id", "verification_google", "formatDetection_telephone", "tag_count", "jsonld_count", "tags_providers_csv", "main_content_node_name", "main_content_id", "main_content_role", "main_content_selector", "main_content_class_list", "main_content_word_count", "main_content_body_word_count", "main_content_heading_count", "main_content_image_count", "main_content_table_count", "main_content_button_count", "main_content_iframe_count", "main_content_video_count", "main_content_audio_count", "main_content_canvas_count", "scroll_height_desktop", "scroll_height_mobile"];
|
|
13
13
|
/**
|
|
14
14
|
* Represents a crawled page stored in the archive.
|
|
15
15
|
*
|
|
@@ -90,6 +90,71 @@ export default class Page {
|
|
|
90
90
|
* or null for legacy rows / never-scraped pages.
|
|
91
91
|
*/
|
|
92
92
|
get lastCrawledAt(): number | null;
|
|
93
|
+
/**
|
|
94
|
+
* Detected main-content element's `nodeName` (e.g. `'MAIN'`), or null when
|
|
95
|
+
* no main region was found or the page was not fully rendered.
|
|
96
|
+
*/
|
|
97
|
+
get mainContentNodeName(): string | null;
|
|
98
|
+
/**
|
|
99
|
+
* Detected main-content element's `id`, or null.
|
|
100
|
+
*/
|
|
101
|
+
get mainContentId(): string | null;
|
|
102
|
+
/**
|
|
103
|
+
* Detected main-content element's `role` attribute, or null.
|
|
104
|
+
*/
|
|
105
|
+
get mainContentRole(): string | null;
|
|
106
|
+
/**
|
|
107
|
+
* Diagnostic tag+id+class selector for the detected main-content element, or null.
|
|
108
|
+
*/
|
|
109
|
+
get mainContentSelector(): string | null;
|
|
110
|
+
/**
|
|
111
|
+
* Detected main-content element's CSS classes, or null when no main region
|
|
112
|
+
* was found. Parsed from the JSON-encoded `main_content_class_list` column.
|
|
113
|
+
*/
|
|
114
|
+
get mainContentClassList(): string[] | null;
|
|
115
|
+
/**
|
|
116
|
+
* Character count of the main region's text content (denormalised
|
|
117
|
+
* aggregate written at scrape time), or null.
|
|
118
|
+
*/
|
|
119
|
+
get mainContentWordCount(): number | null;
|
|
120
|
+
/**
|
|
121
|
+
* Character count of `document.body`'s text content (denormalised
|
|
122
|
+
* aggregate written at scrape time), or null.
|
|
123
|
+
*/
|
|
124
|
+
get mainContentBodyWordCount(): number | null;
|
|
125
|
+
/**
|
|
126
|
+
* Number of headings within the main region (denormalised aggregate), or null.
|
|
127
|
+
*/
|
|
128
|
+
get mainContentHeadingCount(): number | null;
|
|
129
|
+
/**
|
|
130
|
+
* Number of images within the main region (denormalised aggregate), or null.
|
|
131
|
+
*/
|
|
132
|
+
get mainContentImageCount(): number | null;
|
|
133
|
+
/**
|
|
134
|
+
* Number of tables within the main region (denormalised aggregate), or null.
|
|
135
|
+
*/
|
|
136
|
+
get mainContentTableCount(): number | null;
|
|
137
|
+
/**
|
|
138
|
+
* Number of button-like elements within the main region (denormalised
|
|
139
|
+
* aggregate), or null.
|
|
140
|
+
*/
|
|
141
|
+
get mainContentButtonCount(): number | null;
|
|
142
|
+
/**
|
|
143
|
+
* Number of iframes within the main region (denormalised aggregate), or null.
|
|
144
|
+
*/
|
|
145
|
+
get mainContentIframeCount(): number | null;
|
|
146
|
+
/**
|
|
147
|
+
* Number of videos within the main region (denormalised aggregate), or null.
|
|
148
|
+
*/
|
|
149
|
+
get mainContentVideoCount(): number | null;
|
|
150
|
+
/**
|
|
151
|
+
* Number of audios within the main region (denormalised aggregate), or null.
|
|
152
|
+
*/
|
|
153
|
+
get mainContentAudioCount(): number | null;
|
|
154
|
+
/**
|
|
155
|
+
* Number of canvases within the main region (denormalised aggregate), or null.
|
|
156
|
+
*/
|
|
157
|
+
get mainContentCanvasCount(): number | null;
|
|
93
158
|
/**
|
|
94
159
|
* Iterable view over every flat meta column (~47 fields). Returns a frozen
|
|
95
160
|
* record so consumers can pick fields by name without re-enumerating
|
|
@@ -157,6 +222,16 @@ export default class Page {
|
|
|
157
222
|
* Use for diagnostics; specific directive flags live on `robots_*` getters.
|
|
158
223
|
*/
|
|
159
224
|
get robots_raw(): string | null;
|
|
225
|
+
/**
|
|
226
|
+
* `document.body.scrollHeight` at the desktop-compact preset (denormalised
|
|
227
|
+
* aggregate written at scrape time), or null.
|
|
228
|
+
*/
|
|
229
|
+
get scrollHeightDesktop(): number | null;
|
|
230
|
+
/**
|
|
231
|
+
* `document.body.scrollHeight` at the mobile-small preset (denormalised
|
|
232
|
+
* aggregate written at scrape time), or null.
|
|
233
|
+
*/
|
|
234
|
+
get scrollHeightMobile(): number | null;
|
|
160
235
|
/**
|
|
161
236
|
* The reason this page was skipped during crawling, or null if it was not skipped.
|
|
162
237
|
*/
|
|
@@ -210,6 +285,31 @@ export default class Page {
|
|
|
210
285
|
* @returns An array of {@link Anchor} objects representing the links on this page.
|
|
211
286
|
*/
|
|
212
287
|
getAnchors(): Promise<Anchor[]>;
|
|
288
|
+
/**
|
|
289
|
+
* Retrieves the audios within this page's detected main content region
|
|
290
|
+
* from `page_main_content_audios`. Lazy — runs a single SELECT per call.
|
|
291
|
+
* @returns Ordered audio rows.
|
|
292
|
+
*/
|
|
293
|
+
getAudios(): Promise<import("./meta/types.js").MainContentAudioRow[]>;
|
|
294
|
+
/**
|
|
295
|
+
* Retrieves the button-like elements within this page's detected main
|
|
296
|
+
* content region from `page_main_content_buttons`. Lazy — runs a single
|
|
297
|
+
* SELECT per call.
|
|
298
|
+
* @returns Ordered button rows.
|
|
299
|
+
*/
|
|
300
|
+
getButtons(): Promise<import("./meta/types.js").MainContentButtonRow[]>;
|
|
301
|
+
/**
|
|
302
|
+
* Retrieves the canvases within this page's detected main content region
|
|
303
|
+
* from `page_main_content_canvases`. Lazy — runs a single SELECT per call.
|
|
304
|
+
* @returns Ordered canvas rows.
|
|
305
|
+
*/
|
|
306
|
+
getCanvases(): Promise<import("./meta/types.js").MainContentCanvasRow[]>;
|
|
307
|
+
/**
|
|
308
|
+
* Retrieves the headings within this page's detected main content region
|
|
309
|
+
* from `page_main_content_headings`. Lazy — runs a single SELECT per call.
|
|
310
|
+
* @returns Ordered heading rows.
|
|
311
|
+
*/
|
|
312
|
+
getHeadings(): Promise<import("./meta/types.js").MainContentHeadingRow[]>;
|
|
213
313
|
/**
|
|
214
314
|
* Thin wrapper that forwards this page's id to the accessor's
|
|
215
315
|
* BLOB-read path. Lets callers hold a `Page` reference and ask for its
|
|
@@ -223,6 +323,12 @@ export default class Page {
|
|
|
223
323
|
* }
|
|
224
324
|
*/
|
|
225
325
|
getHtml(): Promise<string | null>;
|
|
326
|
+
/**
|
|
327
|
+
* Retrieves the iframes within this page's detected main content region
|
|
328
|
+
* from `page_main_content_iframes`. Lazy — runs a single SELECT per call.
|
|
329
|
+
* @returns Ordered iframe rows.
|
|
330
|
+
*/
|
|
331
|
+
getIframes(): Promise<import("./meta/types.js").MainContentIframeRow[]>;
|
|
226
332
|
/**
|
|
227
333
|
* Retrieves the JSON-LD entries for this page from `page_jsonld`.
|
|
228
334
|
* Lazy — runs a single SELECT per call. Returns entries in insertion
|
|
@@ -230,6 +336,19 @@ export default class Page {
|
|
|
230
336
|
* @returns Ordered JSON-LD / SpeculationRules rows.
|
|
231
337
|
*/
|
|
232
338
|
getJsonLd(): Promise<readonly JsonLdRow[]>;
|
|
339
|
+
/**
|
|
340
|
+
* Retrieves the images within this page's detected main content region
|
|
341
|
+
* from `page_main_content_images`. Lazy — runs a single SELECT per call.
|
|
342
|
+
* Distinct from the whole-page image scan (`image_items`).
|
|
343
|
+
* @returns Ordered image rows.
|
|
344
|
+
*/
|
|
345
|
+
getMainContentImages(): Promise<import("./meta/types.js").MainContentImageRow[]>;
|
|
346
|
+
/**
|
|
347
|
+
* Retrieves the tables within this page's detected main content region
|
|
348
|
+
* from `page_main_content_tables`. Lazy — runs a single SELECT per call.
|
|
349
|
+
* @returns Ordered table rows.
|
|
350
|
+
*/
|
|
351
|
+
getMainContentTables(): Promise<import("./meta/types.js").MainContentTableRow[]>;
|
|
233
352
|
/**
|
|
234
353
|
* Retrieves the referrers (incoming links) pointing to this page.
|
|
235
354
|
* Uses pre-loaded data if available, otherwise queries the database.
|
|
@@ -248,6 +367,12 @@ export default class Page {
|
|
|
248
367
|
* @returns Ordered tag rows.
|
|
249
368
|
*/
|
|
250
369
|
getTags(): Promise<readonly TagRow[]>;
|
|
370
|
+
/**
|
|
371
|
+
* Retrieves the videos within this page's detected main content region
|
|
372
|
+
* from `page_main_content_videos`. Lazy — runs a single SELECT per call.
|
|
373
|
+
* @returns Ordered video rows.
|
|
374
|
+
*/
|
|
375
|
+
getVideos(): Promise<import("./meta/types.js").MainContentVideoRow[]>;
|
|
251
376
|
/**
|
|
252
377
|
* Checks whether this page is an internal HTML page (not external and has `text/html` content type).
|
|
253
378
|
* @returns `true` if this is an internal HTML page, `false` otherwise.
|
|
@@ -281,8 +406,26 @@ export default class Page {
|
|
|
281
406
|
isInternalPage: boolean;
|
|
282
407
|
getAnchors: Anchor[];
|
|
283
408
|
getReferrers: Referrer[];
|
|
284
|
-
lang: string | number | null;
|
|
285
409
|
dir: string | number | null;
|
|
410
|
+
title: string | number | null;
|
|
411
|
+
main_content_word_count: string | number | null;
|
|
412
|
+
main_content_node_name: string | number | null;
|
|
413
|
+
main_content_id: string | number | null;
|
|
414
|
+
main_content_role: string | number | null;
|
|
415
|
+
main_content_selector: string | number | null;
|
|
416
|
+
main_content_class_list: string | number | null;
|
|
417
|
+
main_content_body_word_count: string | number | null;
|
|
418
|
+
main_content_heading_count: string | number | null;
|
|
419
|
+
main_content_image_count: string | number | null;
|
|
420
|
+
main_content_table_count: string | number | null;
|
|
421
|
+
main_content_button_count: string | number | null;
|
|
422
|
+
main_content_iframe_count: string | number | null;
|
|
423
|
+
main_content_video_count: string | number | null;
|
|
424
|
+
main_content_audio_count: string | number | null;
|
|
425
|
+
main_content_canvas_count: string | number | null;
|
|
426
|
+
scroll_height_desktop: string | number | null;
|
|
427
|
+
scroll_height_mobile: string | number | null;
|
|
428
|
+
lang: string | number | null;
|
|
286
429
|
charset: string | number | null;
|
|
287
430
|
baseHref: string | number | null;
|
|
288
431
|
viewport_raw: string | number | null;
|
|
@@ -291,7 +434,6 @@ export default class Page {
|
|
|
291
434
|
author: string | number | null;
|
|
292
435
|
generator: string | number | null;
|
|
293
436
|
publisher: string | number | null;
|
|
294
|
-
title: string | number | null;
|
|
295
437
|
description: string | number | null;
|
|
296
438
|
keywords: string | number | null;
|
|
297
439
|
robots_raw: string | number | null;
|
package/lib/archive/page.js
CHANGED
|
@@ -60,6 +60,23 @@ const FLAT_META_COLUMNS = [
|
|
|
60
60
|
'tag_count',
|
|
61
61
|
'jsonld_count',
|
|
62
62
|
'tags_providers_csv',
|
|
63
|
+
'main_content_node_name',
|
|
64
|
+
'main_content_id',
|
|
65
|
+
'main_content_role',
|
|
66
|
+
'main_content_selector',
|
|
67
|
+
'main_content_class_list',
|
|
68
|
+
'main_content_word_count',
|
|
69
|
+
'main_content_body_word_count',
|
|
70
|
+
'main_content_heading_count',
|
|
71
|
+
'main_content_image_count',
|
|
72
|
+
'main_content_table_count',
|
|
73
|
+
'main_content_button_count',
|
|
74
|
+
'main_content_iframe_count',
|
|
75
|
+
'main_content_video_count',
|
|
76
|
+
'main_content_audio_count',
|
|
77
|
+
'main_content_canvas_count',
|
|
78
|
+
'scroll_height_desktop',
|
|
79
|
+
'scroll_height_mobile',
|
|
63
80
|
];
|
|
64
81
|
/**
|
|
65
82
|
* Represents a crawled page stored in the archive.
|
|
@@ -171,6 +188,104 @@ export default class Page {
|
|
|
171
188
|
get lastCrawledAt() {
|
|
172
189
|
return this.#raw.lastCrawledAt;
|
|
173
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Detected main-content element's `nodeName` (e.g. `'MAIN'`), or null when
|
|
193
|
+
* no main region was found or the page was not fully rendered.
|
|
194
|
+
*/
|
|
195
|
+
get mainContentNodeName() {
|
|
196
|
+
return this.#raw.main_content_node_name;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Detected main-content element's `id`, or null.
|
|
200
|
+
*/
|
|
201
|
+
get mainContentId() {
|
|
202
|
+
return this.#raw.main_content_id;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Detected main-content element's `role` attribute, or null.
|
|
206
|
+
*/
|
|
207
|
+
get mainContentRole() {
|
|
208
|
+
return this.#raw.main_content_role;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Diagnostic tag+id+class selector for the detected main-content element, or null.
|
|
212
|
+
*/
|
|
213
|
+
get mainContentSelector() {
|
|
214
|
+
return this.#raw.main_content_selector;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Detected main-content element's CSS classes, or null when no main region
|
|
218
|
+
* was found. Parsed from the JSON-encoded `main_content_class_list` column.
|
|
219
|
+
*/
|
|
220
|
+
get mainContentClassList() {
|
|
221
|
+
if (this.#raw.main_content_class_list === null) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
return JSON.parse(this.#raw.main_content_class_list);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Character count of the main region's text content (denormalised
|
|
228
|
+
* aggregate written at scrape time), or null.
|
|
229
|
+
*/
|
|
230
|
+
get mainContentWordCount() {
|
|
231
|
+
return this.#raw.main_content_word_count;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Character count of `document.body`'s text content (denormalised
|
|
235
|
+
* aggregate written at scrape time), or null.
|
|
236
|
+
*/
|
|
237
|
+
get mainContentBodyWordCount() {
|
|
238
|
+
return this.#raw.main_content_body_word_count;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Number of headings within the main region (denormalised aggregate), or null.
|
|
242
|
+
*/
|
|
243
|
+
get mainContentHeadingCount() {
|
|
244
|
+
return this.#raw.main_content_heading_count;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Number of images within the main region (denormalised aggregate), or null.
|
|
248
|
+
*/
|
|
249
|
+
get mainContentImageCount() {
|
|
250
|
+
return this.#raw.main_content_image_count;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Number of tables within the main region (denormalised aggregate), or null.
|
|
254
|
+
*/
|
|
255
|
+
get mainContentTableCount() {
|
|
256
|
+
return this.#raw.main_content_table_count;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Number of button-like elements within the main region (denormalised
|
|
260
|
+
* aggregate), or null.
|
|
261
|
+
*/
|
|
262
|
+
get mainContentButtonCount() {
|
|
263
|
+
return this.#raw.main_content_button_count;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Number of iframes within the main region (denormalised aggregate), or null.
|
|
267
|
+
*/
|
|
268
|
+
get mainContentIframeCount() {
|
|
269
|
+
return this.#raw.main_content_iframe_count;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Number of videos within the main region (denormalised aggregate), or null.
|
|
273
|
+
*/
|
|
274
|
+
get mainContentVideoCount() {
|
|
275
|
+
return this.#raw.main_content_video_count;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Number of audios within the main region (denormalised aggregate), or null.
|
|
279
|
+
*/
|
|
280
|
+
get mainContentAudioCount() {
|
|
281
|
+
return this.#raw.main_content_audio_count;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Number of canvases within the main region (denormalised aggregate), or null.
|
|
285
|
+
*/
|
|
286
|
+
get mainContentCanvasCount() {
|
|
287
|
+
return this.#raw.main_content_canvas_count;
|
|
288
|
+
}
|
|
174
289
|
/**
|
|
175
290
|
* Iterable view over every flat meta column (~47 fields). Returns a frozen
|
|
176
291
|
* record so consumers can pick fields by name without re-enumerating
|
|
@@ -280,6 +395,20 @@ export default class Page {
|
|
|
280
395
|
get robots_raw() {
|
|
281
396
|
return this.#raw.robots_raw;
|
|
282
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* `document.body.scrollHeight` at the desktop-compact preset (denormalised
|
|
400
|
+
* aggregate written at scrape time), or null.
|
|
401
|
+
*/
|
|
402
|
+
get scrollHeightDesktop() {
|
|
403
|
+
return this.#raw.scroll_height_desktop;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* `document.body.scrollHeight` at the mobile-small preset (denormalised
|
|
407
|
+
* aggregate written at scrape time), or null.
|
|
408
|
+
*/
|
|
409
|
+
get scrollHeightMobile() {
|
|
410
|
+
return this.#raw.scroll_height_mobile;
|
|
411
|
+
}
|
|
283
412
|
/**
|
|
284
413
|
* The reason this page was skipped during crawling, or null if it was not skipped.
|
|
285
414
|
*/
|
|
@@ -376,6 +505,39 @@ export default class Page {
|
|
|
376
505
|
}
|
|
377
506
|
return this.#archive.getAnchorsOnPage(this.#raw.id);
|
|
378
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Retrieves the audios within this page's detected main content region
|
|
510
|
+
* from `page_main_content_audios`. Lazy — runs a single SELECT per call.
|
|
511
|
+
* @returns Ordered audio rows.
|
|
512
|
+
*/
|
|
513
|
+
async getAudios() {
|
|
514
|
+
return this.#archive.getAudiosOfPage(this.#raw.id);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Retrieves the button-like elements within this page's detected main
|
|
518
|
+
* content region from `page_main_content_buttons`. Lazy — runs a single
|
|
519
|
+
* SELECT per call.
|
|
520
|
+
* @returns Ordered button rows.
|
|
521
|
+
*/
|
|
522
|
+
async getButtons() {
|
|
523
|
+
return this.#archive.getButtonsOfPage(this.#raw.id);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Retrieves the canvases within this page's detected main content region
|
|
527
|
+
* from `page_main_content_canvases`. Lazy — runs a single SELECT per call.
|
|
528
|
+
* @returns Ordered canvas rows.
|
|
529
|
+
*/
|
|
530
|
+
async getCanvases() {
|
|
531
|
+
return this.#archive.getCanvasesOfPage(this.#raw.id);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Retrieves the headings within this page's detected main content region
|
|
535
|
+
* from `page_main_content_headings`. Lazy — runs a single SELECT per call.
|
|
536
|
+
* @returns Ordered heading rows.
|
|
537
|
+
*/
|
|
538
|
+
async getHeadings() {
|
|
539
|
+
return this.#archive.getHeadingsOfPage(this.#raw.id);
|
|
540
|
+
}
|
|
379
541
|
/**
|
|
380
542
|
* Thin wrapper that forwards this page's id to the accessor's
|
|
381
543
|
* BLOB-read path. Lets callers hold a `Page` reference and ask for its
|
|
@@ -391,6 +553,14 @@ export default class Page {
|
|
|
391
553
|
async getHtml() {
|
|
392
554
|
return this.#archive.getHtmlOfPage(this.#raw.id);
|
|
393
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Retrieves the iframes within this page's detected main content region
|
|
558
|
+
* from `page_main_content_iframes`. Lazy — runs a single SELECT per call.
|
|
559
|
+
* @returns Ordered iframe rows.
|
|
560
|
+
*/
|
|
561
|
+
async getIframes() {
|
|
562
|
+
return this.#archive.getIframesOfPage(this.#raw.id);
|
|
563
|
+
}
|
|
394
564
|
/**
|
|
395
565
|
* Retrieves the JSON-LD entries for this page from `page_jsonld`.
|
|
396
566
|
* Lazy — runs a single SELECT per call. Returns entries in insertion
|
|
@@ -400,6 +570,23 @@ export default class Page {
|
|
|
400
570
|
async getJsonLd() {
|
|
401
571
|
return this.#archive.getJsonLdOfPage(this.#raw.id);
|
|
402
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Retrieves the images within this page's detected main content region
|
|
575
|
+
* from `page_main_content_images`. Lazy — runs a single SELECT per call.
|
|
576
|
+
* Distinct from the whole-page image scan (`image_items`).
|
|
577
|
+
* @returns Ordered image rows.
|
|
578
|
+
*/
|
|
579
|
+
async getMainContentImages() {
|
|
580
|
+
return this.#archive.getMainContentImagesOfPage(this.#raw.id);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Retrieves the tables within this page's detected main content region
|
|
584
|
+
* from `page_main_content_tables`. Lazy — runs a single SELECT per call.
|
|
585
|
+
* @returns Ordered table rows.
|
|
586
|
+
*/
|
|
587
|
+
async getMainContentTables() {
|
|
588
|
+
return this.#archive.getMainContentTablesOfPage(this.#raw.id);
|
|
589
|
+
}
|
|
403
590
|
/**
|
|
404
591
|
* Retrieves the referrers (incoming links) pointing to this page.
|
|
405
592
|
* Uses pre-loaded data if available, otherwise queries the database.
|
|
@@ -447,6 +634,14 @@ export default class Page {
|
|
|
447
634
|
async getTags() {
|
|
448
635
|
return this.#archive.getTagsOfPage(this.#raw.id);
|
|
449
636
|
}
|
|
637
|
+
/**
|
|
638
|
+
* Retrieves the videos within this page's detected main content region
|
|
639
|
+
* from `page_main_content_videos`. Lazy — runs a single SELECT per call.
|
|
640
|
+
* @returns Ordered video rows.
|
|
641
|
+
*/
|
|
642
|
+
async getVideos() {
|
|
643
|
+
return this.#archive.getVideosOfPage(this.#raw.id);
|
|
644
|
+
}
|
|
450
645
|
/**
|
|
451
646
|
* Checks whether this page is an internal HTML page (not external and has `text/html` content type).
|
|
452
647
|
* @returns `true` if this is an internal HTML page, `false` otherwise.
|