# -*- coding: utf-8 -*-
"""精确查找标题输入框"""
import socket, json, urllib.request, urllib.parse

HOST = 'localhost'
PORT = 9223

pages = json.loads(urllib.request.urlopen(f'http://{HOST}:{PORT}/json').read())
page_id = [p['id'] for p in pages if 'baijiahao.baidu.com' in p['url']][0]

ws_url = f'ws://{HOST}:{PORT}/devtools/page/{page_id}'
parsed = urllib.parse.urlparse(ws_url)
sock = socket.create_connection((parsed.hostname, parsed.port or 80), timeout=15)
key = 'dGhlIHNhbXBsZSBub25jZQ=='
handshake = f'GET {parsed.path} HTTP/1.1\r\nHost:{parsed.hostname}:{parsed.port}\r\nUpgrade:websocket\r\nConnection:Upgrade\r\nSec-WebSocket-Key:{key}\r\nSec-WebSocket-Version:13\r\n\r\n'
sock.send(handshake.encode())
resp = b''
while b'\r\n\r\n' not in resp:
    resp += sock.recv(4096)

def send(s, d):
    data = json.dumps(d).encode('utf-8')
    n = len(data)
    mask = b'\x01\x02\x03\x04'
    if n <= 125:
        hdr = bytes([0x81, n|0x80]) + mask
    elif n <= 65535:
        hdr = bytes([0x81, 0xFE]) + n.to_bytes(2, 'big') + mask
    s.send(hdr + bytes(data[i] ^ mask[i%4] for i in range(n)))

def recv(s):
    h = s.recv(2)
    n = h[1] & 0x7f
    if n == 126:
        n = int.from_bytes(s.recv(2), 'big')
    elif n == 127:
        n = int.from_bytes(s.recv(8), 'big')
    return s.recv(n).decode('utf-8')

# 查找 input-box 容器及其子元素
expr = """
(function(){
    var results = [];
    
    // 找到 input-box
    var inputBox = document.querySelector('.input-box');
    if(inputBox){
        results.push('=== input-box found ===');
        
        // 它的所有子元素
        var children = inputBox.children;
        for(var i=0; i<children.length; i++){
            var c = children[i];
            results.push('child[' + i + ']: ' + c.tagName + ' class=' + (c.className || '').substring(0,40));
            
            // 查找 contenteditable
            var editables = c.querySelectorAll('[contenteditable]');
            for(var j=0; j<editables.length; j++){
                var e = editables[j];
                results.push('  editable[' + j + ']: ' + e.tagName + ' class=' + (e.className || '').substring(0,40) + ' content=' + (e.innerText || '').substring(0,30));
            }
            
            // 查找 textarea
            var textareas = c.querySelectorAll('textarea');
            for(var t=0; t<textareas.length; t++){
                var ta = textareas[t];
                results.push('  textarea[' + t + ']: class=' + (ta.className || '').substring(0,40) + ' value=' + (ta.value || '').substring(0,30));
            }
        }
        
        // 直接子代的 contenteditable
        var directEditable = inputBox.querySelector(':scope > [contenteditable]');
        if(directEditable){
            results.push('direct editable: ' + directEditable.tagName + ' class=' + (directEditable.className || '').substring(0,40));
        }
    }
    
    // 也查找 titleInput wrapper
    var titleInputWrap = document.querySelector('[class*="titleInput"]');
    if(titleInputWrap){
        results.push('=== titleInput wrapper ===');
        results.push('tag: ' + titleInputWrap.tagName + ' class: ' + (titleInputWrap.className || '').substring(0,50));
        var editables = titleInputWrap.querySelectorAll('[contenteditable]');
        for(var e of editables){
            results.push('  editable: ' + e.tagName + ' class=' + (e.className || '').substring(0,40) + ' content=' + (e.innerText || '').substring(0,30));
        }
    }
    
    return JSON.stringify(results);
})()
"""
send(sock, {'id':1,'method':'Runtime.evaluate','params':{'expression':expr}})
r = recv(sock)
print('标题输入框结构:')
print(json.loads(r)['result']['result']['value'])

sock.close()
