Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
581a18d
implement client-side rendering detection in qa
emma-sg Mar 11, 2026
d155568
add test & always write csr clues out when checking for them
emma-sg Mar 11, 2026
b4e4f42
save csr data to page state, and improve test specficity
emma-sg Mar 11, 2026
5fbc89b
fix test
emma-sg Mar 11, 2026
dee920f
wip 1
emma-sg Mar 17, 2026
05f3d5d
get jsdom-based text extraction on raw response html working
emma-sg Mar 18, 2026
0e7e23c
refactor text extraction & generate text from raw response when missing
emma-sg Mar 18, 2026
2a7011b
fix duplicate csp clue name
emma-sg Mar 23, 2026
f6baffc
move csr clues into main "comparison" object in comparison data
emma-sg Mar 24, 2026
3580ffc
first pass at tests
emma-sg Mar 24, 2026
36e3ebc
include raw text output when running qa
emma-sg Mar 31, 2026
842f375
fix incorrect replay suffixes
emma-sg Mar 31, 2026
395dece
compare original text against extracted raw text, rather than replayed
emma-sg Mar 31, 2026
2f5469b
expand CSR detection patterns
emma-sg Mar 31, 2026
39b6fb9
ensure text from response & html text gets written to output warcs in qa
emma-sg Mar 31, 2026
9b81b6f
add `WARC-Refers-To` records to outputs
emma-sg Apr 1, 2026
f02b7bc
finish passing through `refersTo` uuid
emma-sg Apr 1, 2026
e6bf4ee
capture and track document request id for raw text extraction in qa
emma-sg Apr 1, 2026
f8bd4e5
only do raw text compare for 200 status code pages
ikreymer Apr 1, 2026
ca9439d
ensure status exists
ikreymer Apr 1, 2026
cf1dc0d
add more logging & timeout for loading frame
emma-sg Apr 2, 2026
23e8127
remove logger from frame.evaluate()
ikreymer Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"iso-639-1": "^3.1.5",
"js-levenshtein": "^1.1.6",
"js-yaml": "^4.1.0",
"jsdom": "^29.0.0",
"normalize-url": "^9.0.0",
"p-queue": "^7.3.4",
"pixelmatch": "^5.3.0",
Expand All @@ -50,6 +51,7 @@
"@types/get-folder-size": "^3.0.4",
"@types/js-levenshtein": "^1.1.3",
"@types/js-yaml": "^4.0.8",
"@types/jsdom": "^28.0.0",
"@types/node": "^20.8.7",
"@types/pixelmatch": "^5.2.6",
"@types/pngjs": "^6.0.4",
Expand Down
113 changes: 102 additions & 11 deletions src/crawler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import yaml from "js-yaml";
import { WACZ, WACZInitOpts, mergeCDXJ } from "./util/wacz.js";

import { HealthChecker } from "./util/healthcheck.js";
import { TextExtractViaSnapshot } from "./util/textextract.js";
import {
TextExtractViaResponse,
TextExtractViaSnapshot,
} from "./util/textextract.js";
import {
initStorage,
getFileSize,
Expand Down Expand Up @@ -1178,11 +1181,55 @@ self.__bx_behaviors.selectMainBehavior();
recorder.pageSeedDepth = depth;
}

// Enable Network domain to track document request for raw text extraction
let documentRequestId: string | null = null;
let trackDocumentRequest:
| ((params: Protocol.Network.ResponseReceivedEvent) => void)
| null = null;

if (this.params.text.includes("to-warc-from-raw")) {
await cdp.send("Network.enable");
trackDocumentRequest = (
params: Protocol.Network.ResponseReceivedEvent,
) => {
if (params.type === "Document" && !documentRequestId) {
documentRequestId = params.requestId;
logger.debug(
"Captured document request ID",
{ requestId: documentRequestId, url: params.response.url },
"text",
);
}
};
cdp.on("Network.responseReceived", trackDocumentRequest);
}

// run custom driver here, if any
if (this.driver) {
await this.driver({ page, data, crawler: this, seed });
} else {
await this.loadPage(page, data, seed);
try {
if (this.driver) {
await this.driver({ page, data, crawler: this, seed });
} else {
await this.loadPage(page, data, seed);
}
} finally {
// Store document request ID and clean up listener
if (documentRequestId) {
data.documentRequestId = documentRequestId;
logger.info(
"Stored document request ID for raw text extraction",
{ url: data.url, requestId: documentRequestId },
"text",
);
} else if (trackDocumentRequest) {
logger.warn(
"No document request ID captured",
{ url: data.url },
"text",
);
}
if (trackDocumentRequest) {
cdp.off("Network.responseReceived", trackDocumentRequest);
}
}

data.title = await timedRun(
Expand Down Expand Up @@ -1235,23 +1282,61 @@ self.__bx_behaviors.selectMainBehavior();
}
}

let textextract = null;
let textExtract = null;

if (this.textWriter) {
textextract = new TextExtractViaSnapshot(cdp, {
textExtract = new TextExtractViaSnapshot(cdp, {
writer: this.textWriter,
url,
skipDocs: this.skipTextDocs,
});
const { text } = await textextract.extractAndStoreText(
const { text } = await textExtract.extractAndStoreText(
"text",
false,
this.params.text.includes("to-warc"),
data.originalWarcRecordId,
);

if (text !== null && (this.textInPages || saveOutput)) {
data.text = text;
}

if (this.params.text.includes("to-warc-from-raw")) {
logger.info(
"Extracting text from raw response",
{
url,
hasRequestId: !!data.documentRequestId,
refersTo: String(data.originalWarcRecordId),
},
"text",
);
textExtract = new TextExtractViaResponse(cdp, {
writer: this.textWriter,
url,
skipDocs: this.skipTextDocs,
requestId: data.documentRequestId,
});
const { text: textFromResponse } =
await textExtract.extractAndStoreText(
"text-from-response",
false,
this.params.text.includes("to-warc-from-raw"),
data.originalWarcRecordId,
);
logger.info(
"Extracted text from raw response result",
{
url,
hasText: textFromResponse !== null,
refersTo: String(data.originalWarcRecordId),
},
"text",
);
if (textFromResponse !== null && (this.textInPages || saveOutput)) {
data.textFromResponse = textFromResponse;
}
}
}

data.loadState = LoadState.EXTRACTION_DONE;
Expand Down Expand Up @@ -1280,8 +1365,13 @@ self.__bx_behaviors.selectMainBehavior();
data.loadState = LoadState.BEHAVIORS_DONE;
}

if (textextract && this.params.text.includes("final-to-warc")) {
await textextract.extractAndStoreText("textFinal", true, true);
if (textExtract && this.params.text.includes("final-to-warc")) {
await textExtract.extractAndStoreText(
"textFinal",
true,
true,
data.originalWarcRecordId,
);
}

if (
Expand Down Expand Up @@ -2640,6 +2730,7 @@ self.__bx_behaviors.selectMainBehavior();
logDetails: LogDetails = {},
ts = 0,
pageid?: string,
originalWarcRecordId?: string,
) {
if (this.limitHit) {
return false;
Expand All @@ -2658,7 +2749,7 @@ self.__bx_behaviors.selectMainBehavior();
}

const result = await this.crawlState.addToQueue(
{ url, seedId, depth, extraHops, ts, pageid },
{ url, seedId, depth, extraHops, ts, pageid, originalWarcRecordId },
this.pageLimit,
);

Expand Down
Loading
Loading