4 回答

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超6個(gè)贊
正如其他答案所指出的那樣,這是一個(gè)復(fù)雜的正則表達(dá)式,可以針對(duì)網(wǎng)頁(yè)源代碼的大部分執(zhí)行。一種可能的解決方法包括使用 Promises 或 Web Worker 來(lái)利用瀏覽器的異步功能來(lái)解凍 UI,但我認(rèn)為您對(duì)具體解決此問(wèn)題不感興趣。似乎您正在嘗試抓取網(wǎng)絡(luò)數(shù)據(jù),因此在此過(guò)程中 UI 是否被凍結(jié)都不會(huì)產(chǎn)生影響。
我的建議是分而治之。讓我們分別處理每個(gè)選擇器和它們。
script[type="application/json"]
這似乎很簡(jiǎn)單。您可能只需要獲取其內(nèi)部?jī)?nèi)容,瞧,您就有了一個(gè) JSON。
div[class*="json"]
我相信這是一種非標(biāo)準(zhǔn)的方式來(lái)指定網(wǎng)頁(yè)的初始狀態(tài)。它可能會(huì)落入與上述相同的解析器。您可能只需要獲取其內(nèi)部文本并嘗試將其解析為 JSON。
script[type="text/javascript"]
這是最棘手的部分,因?yàn)槲覀儾辉偬幚?JSON,而是處理可能包含或不包含 JSON 數(shù)據(jù)的可執(zhí)行 JavaScript。對(duì)于這個(gè),您可以使用簡(jiǎn)化的正則表達(dá)式,但我會(huì)更進(jìn)一步并提出其他建議。
您可以檢查 JavaScript 對(duì)象并嘗試將它們轉(zhuǎn)換為 JSON。這可以通過(guò)內(nèi)置 API 或使用 JavaScript 解析器輕松完成(例如,如果您使用的是 Scrapy 之類(lèi)的東西,則可以使用 js2py)。我不確定這項(xiàng)任務(wù)的性能,但我相信它會(huì)比復(fù)雜的正則表達(dá)式更快,可能值得一試。
它適用于類(lèi)似的情況,var initialState = { ... };
但在嘗試處理像 . 這樣的內(nèi)聯(lián)值時(shí)可能會(huì)帶來(lái)一些挑戰(zhàn)hypedFramework.init({ ... })
。在后一種情況下,您可能需要一些 JavaScript 解析來(lái)隔離這些值。但這仍然是可能的??焖贋g覽一下https://esprima.org/demo/parse.html,看看它是如何從函數(shù)參數(shù)中提取對(duì)象表達(dá)式的。

TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超6個(gè)贊
正則表達(dá)式運(yùn)行時(shí)是非多項(xiàng)式的,這意味著對(duì)于復(fù)雜的模式,它可能需要一段時(shí)間??!你有兩個(gè)選擇;要么在主線(xiàn)程之外運(yùn)行正則表達(dá)式,以確保頁(yè)面保持響應(yīng),要么找到一種更有效的方法來(lái)實(shí)現(xiàn)您嘗試使用正則表達(dá)式做的事情,或者至少找到一個(gè)更好的(CPU 密集度較低的)正則表達(dá)式;
對(duì)于第一個(gè)選擇,您可以使用web workers,這是一個(gè)干凈的解決方案,或者您可以使用 kinda hacky workaround 并使用setTimeout()或使用 promise;但我強(qiáng)烈建議您使用網(wǎng)絡(luò)工作者,如果它的瀏覽器支持適合您的用例(誰(shuí)關(guān)心 IE?)
下面是一個(gè)Promise利用 CPU 密集型任務(wù)遠(yuǎn)離主線(xiàn)程的示例:
const inefficientPattern = /({(?:\s|\n)*(?:"|')(?:\s|\n|.)*?(?:"|'):(?:\s|\n)*(?:"|'|\[|{)(?:\s|\n|.)+?})(?:;|$)/g;
for (let el of document.querySelectorAll(['div[class*="json"]', 'script[type="text/javascript"]', 'script[type="application/json"]'])) {
if (el.innerHTML) {
new Promise( function (resolve, reject) {
resolve(el.innerHTML.match(inefficientPattern))
}).then( matches => {
console.log(matches)
})
}
}
有趣的東西:立即執(zhí)行承諾回調(diào);我錯(cuò)了 ?? 查看這個(gè)答案:Are JavaScript Promise asynchronous?

TA貢獻(xiàn)1863條經(jīng)驗(yàn) 獲得超2個(gè)贊
我認(rèn)為您可以使用 setTimeout 將 for 循環(huán)拆分為多個(gè)迭代。這樣瀏覽器就可以有時(shí)間在每次調(diào)用繁重的正則表達(dá)式解析之間進(jìn)行渲染。
const results = [];
let checkAll = (elements) => {
results.push(checkOne(elements[0]));
if (elements.length > 1) {
setTimeout(0, () => checkAll(elements.slice(1)));
} else {
// do something with results ...
}
}

TA貢獻(xiàn)1839條經(jīng)驗(yàn) 獲得超15個(gè)贊
嘗試在 try/catch 組中使用 JSON.parse,就像這樣
for (el of document.querySelectorAll(['div[class*="json"]', 'script[type="text/javascript"]', 'script[type="application/json"]'])) {
if (el.innerHTML) {
try {
let matches = JSON.parse(el.innerHTML)
console.log(JSON.stringify(matches))
catch (err) {
console.log('element was not a json')
}
}
}
如果元素的內(nèi)容確實(shí)是有效的 JSON 語(yǔ)法,它將執(zhí)行而不會(huì)拋出錯(cuò)誤,否則你可以在 catch 組中做一些特殊的事情
精確
這不會(huì)在元素中找到 JSON 位,整個(gè)元素需要是有效的 JSON 語(yǔ)法
添加回答
舉報(bào)