perf: localhost→127.0.0.1 fix IPv6 2s delay; simphtml radio/checkbox/svg/dropdown fixes; poll interval 0.5→0.2s
This commit is contained in:
@@ -34,7 +34,7 @@ class Session:
|
|||||||
|
|
||||||
|
|
||||||
class TMWebDriver:
|
class TMWebDriver:
|
||||||
def __init__(self, host: str = 'localhost', port: int = 18765):
|
def __init__(self, host: str = '127.0.0.1', port: int = 18765):
|
||||||
self.host, self.port = host, port
|
self.host, self.port = host, port
|
||||||
self.sessions, self.results, self.acks = {}, {}, {}
|
self.sessions, self.results, self.acks = {}, {}, {}
|
||||||
self.default_session_id = None
|
self.default_session_id = None
|
||||||
@@ -202,7 +202,7 @@ class TMWebDriver:
|
|||||||
hasjump = acked = False
|
hasjump = acked = False
|
||||||
|
|
||||||
while exec_id not in self.results:
|
while exec_id not in self.results:
|
||||||
time.sleep(0.5)
|
time.sleep(0.2)
|
||||||
if not acked and exec_id in self.acks:
|
if not acked and exec_id in self.acks:
|
||||||
acked = True; start_time = time.time()
|
acked = True; start_time = time.time()
|
||||||
if tp == 'ws':
|
if tp == 'ws':
|
||||||
@@ -266,4 +266,4 @@ class TMWebDriver:
|
|||||||
return self.execute_js(f'GM_openInTab("{url}");')
|
return self.execute_js(f'GM_openInTab("{url}");')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
driver = TMWebDriver(host='localhost', port=18765)
|
driver = TMWebDriver(host='127.0.0.1', port=18765)
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
// @grant GM_xmlhttpRequest
|
// @grant GM_xmlhttpRequest
|
||||||
// @grant GM_openInTab
|
// @grant GM_openInTab
|
||||||
// @grant unsafeWindow
|
// @grant unsafeWindow
|
||||||
// @connect localhost
|
// @connect 127.0.0.1
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wsUrl = 'ws://localhost:18765';
|
const wsUrl = 'ws://127.0.0.1:18765';
|
||||||
const httpUrl = 'http://localhost:18766/';
|
const httpUrl = 'http://127.0.0.1:18766/';
|
||||||
|
|
||||||
function isWebSocketServerAlive(callback) {
|
function isWebSocketServerAlive(callback) {
|
||||||
GM_xmlhttpRequest({
|
GM_xmlhttpRequest({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'http://localhost:18765/',
|
url: 'http://127.0.0.1:18765/',
|
||||||
onload: () => callback(true),
|
onload: () => callback(true),
|
||||||
onerror: () => callback(false)
|
onerror: () => callback(false)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -104,4 +104,7 @@ web_scan失败时按序排查:
|
|||||||
①TM没装?→遍历本机所有Chromium浏览器(Chrome/Edge/Brave…)用户数据目录下Extensions/,各子目录manifest.json搜"tampermonkey"
|
①TM没装?→遍历本机所有Chromium浏览器(Chrome/Edge/Brave…)用户数据目录下Extensions/,各子目录manifest.json搜"tampermonkey"
|
||||||
没找到→走web_setup_sop;找到→记住装在哪个浏览器
|
没找到→走web_setup_sop;找到→记住装在哪个浏览器
|
||||||
②浏览器没开?→检查①对应的浏览器进程是否在跑(tasklist/ps),没有则启动并打开正常URL(⚠about:blank等内部页不加载扩展)
|
②浏览器没开?→检查①对应的浏览器进程是否在跑(tasklist/ps),没有则启动并打开正常URL(⚠about:blank等内部页不加载扩展)
|
||||||
③WS后台挂了?→socket.connect_ex(('localhost',18766))非0即dead→手动`from TMWebDriver import TMWebDriver; TMWebDriver()`起master
|
③WS后台挂了?→socket.connect_ex(('127.0.0.1',18766))非0即dead→手动`from TMWebDriver import TMWebDriver; TMWebDriver()`起master
|
||||||
|
|
||||||
|
## 性能
|
||||||
|
- ⚠ URL必须用`127.0.0.1`不用`localhost`。Windows下localhost先尝试IPv6(::1)超时2s再回退IPv4,每次HTTP请求多2s
|
||||||
@@ -17,12 +17,14 @@ function createEnhancedDOMCopy() {
|
|||||||
if (sourceNode.nodeType === 3) return sourceNode.cloneNode(false);
|
if (sourceNode.nodeType === 3) return sourceNode.cloneNode(false);
|
||||||
const clone = sourceNode.cloneNode(false);
|
const clone = sourceNode.cloneNode(false);
|
||||||
if ((sourceNode.tagName === 'INPUT' || sourceNode.tagName === 'TEXTAREA') && sourceNode.value) clone.setAttribute('value', sourceNode.value);
|
if ((sourceNode.tagName === 'INPUT' || sourceNode.tagName === 'TEXTAREA') && sourceNode.value) clone.setAttribute('value', sourceNode.value);
|
||||||
|
if (sourceNode.tagName === 'INPUT' && (sourceNode.type === 'radio' || sourceNode.type === 'checkbox') && sourceNode.checked) clone.setAttribute('checked', '');
|
||||||
else if (sourceNode.tagName === 'SELECT' && sourceNode.value) clone.setAttribute('data-selected', sourceNode.value);
|
else if (sourceNode.tagName === 'SELECT' && sourceNode.value) clone.setAttribute('data-selected', sourceNode.value);
|
||||||
try { if (sourceNode.matches && sourceNode.matches(':-webkit-autofill')) { clone.setAttribute('data-autofilled', 'true'); if (!sourceNode.value) clone.setAttribute('value', '⚠️受保护-读tmwebdriver_sop的autofill章节提取'); } } catch(e) {}
|
try { if (sourceNode.matches && sourceNode.matches(':-webkit-autofill')) { clone.setAttribute('data-autofilled', 'true'); if (!sourceNode.value) clone.setAttribute('value', '⚠️受保护-读tmwebdriver_sop的autofill章节提取'); } } catch(e) {}
|
||||||
|
|
||||||
const isDropdown = sourceNode.classList?.contains('dropdown-menu') ||
|
const isDropdown = sourceNode.classList?.contains('dropdown-menu') ||
|
||||||
/dropdown|menu/i.test(sourceNode.className) || sourceNode.getAttribute('role') === 'menu';
|
/dropdown|menu/i.test(sourceNode.className) || sourceNode.getAttribute('role') === 'menu';
|
||||||
const isSmallDropdown = isDropdown && (sourceNode.querySelectorAll('a, button, [role="menuitem"], li').length <= 7 && sourceNode.textContent.length < 500);
|
const _ddItems = isDropdown ? sourceNode.querySelectorAll('a, button, [role="menuitem"], li').length : 0;
|
||||||
|
const isSmallDropdown = _ddItems > 0 && _ddItems <= 7 && sourceNode.textContent.length < 500;
|
||||||
|
|
||||||
const childNodes = [];
|
const childNodes = [];
|
||||||
for (const child of sourceNode.childNodes) {
|
for (const child of sourceNode.childNodes) {
|
||||||
@@ -704,6 +706,7 @@ js_findMainContent = '''
|
|||||||
def optimize_html_for_tokens(html):
|
def optimize_html_for_tokens(html):
|
||||||
if type(html) is str: soup = BeautifulSoup(html, 'html.parser')
|
if type(html) is str: soup = BeautifulSoup(html, 'html.parser')
|
||||||
else: soup = html
|
else: soup = html
|
||||||
|
for svg in soup.find_all('svg'): svg.clear()
|
||||||
[tag.attrs.pop('style', None) for tag in soup.find_all(True)]
|
[tag.attrs.pop('style', None) for tag in soup.find_all(True)]
|
||||||
for tag in soup.find_all(True):
|
for tag in soup.find_all(True):
|
||||||
if tag.has_attr('src'):
|
if tag.has_attr('src'):
|
||||||
@@ -788,6 +791,10 @@ def find_changed_elements(before_html, after_html):
|
|||||||
for sig, els in after_sigs.items():
|
for sig, els in after_sigs.items():
|
||||||
if sig not in before_sigs: changed.extend(els)
|
if sig not in before_sigs: changed.extend(els)
|
||||||
elif len(els) > len(before_sigs[sig]): changed.extend(els[:len(els) - len(before_sigs[sig])])
|
elif len(els) > len(before_sigs[sig]): changed.extend(els[:len(els) - len(before_sigs[sig])])
|
||||||
|
if len(changed) == 0 and str(before_soup) != str(after_soup):
|
||||||
|
before_els, after_els = before_soup.find_all(True), after_soup.find_all(True)
|
||||||
|
for i in range(min(len(before_els), len(after_els))):
|
||||||
|
if get_sig(before_els[i]) != get_sig(after_els[i]): changed.append(after_els[i])
|
||||||
# 变化边界: parent不在changed中的元素
|
# 变化边界: parent不在changed中的元素
|
||||||
cids = set(id(el) for el in changed)
|
cids = set(id(el) for el in changed)
|
||||||
boundaries = [el for el in changed if el.parent is None or id(el.parent) not in cids]
|
boundaries = [el for el in changed if el.parent is None or id(el.parent) not in cids]
|
||||||
|
|||||||
Reference in New Issue
Block a user