ClericPy / ichrome

Chrome controller for Humans, based on Chrome Devtools Protocol(CDP) and python3.7+.
https://pypi.org/project/ichrome/
MIT License
227 stars 29 forks source link

document.querySelector 被网站反爬检测到 #111

Closed zenghh closed 1 year ago

zenghh commented 1 year ago

能不能增加使用cdp 的DOM.querySelector获取元素的方法,直接js执行document.querySelector被网站反爬检测了,或者说有其他方式能避开它这个检测吗

ClericPy commented 1 year ago

DOM 对象那个我看过, 有点复杂没把我绕死... 要维护不少对象, 最后太冷门了就没指望它, 用的 JS 原生

反爬检测那段代码有没有考虑截断流量把 JS 替换掉, CDP 是可以在 Network 协议里拿到流量的时候篡改的.

话说... 为啥不把 HTML 渲染完毕以后直接拿出来用 selectolax / lxml 之类的去选择, 是要 click 之类的么

zenghh commented 1 year ago

是要点击,而且只能实际的鼠标点击才不会 被检测,所以要获取元素位置才能点击,但是直接用document.querySelector又被网站检测到,网站直接重写了document.querySelector

ClericPy commented 1 year ago

没啥好办法... 如果是专门的纯反作弊的 JS, 考虑在它下载前就 block 掉它的流量, 如果那段必须执行, 考虑导入个别的 jQuery 之类的能替代么

我这边点击位置也是基于 css 找到位置 dispatch Event 的方式, 没啥简单方式

如果 DOM 对象能用, 可以自己 send recv 试试, 我当时觉得太复杂没深挖这个 domain , 看起来要先拿 root 的 node id 然后 select 它.

ClericPy commented 1 year ago

具体过程可以参考 async 版本里面这段

https://github.com/ClericPy/ichrome/blob/master/ichrome/async_utils.py#L2195

zenghh commented 1 year ago
            # get nodeId
            data = await tab.send("DOM.getDocument", timeout=10)

            # get selector
            data = await tab.send(
                "DOM.querySelector",
                nodeId=1,
                selector="div.hm-MainHeaderRHSLoggedOutNarrow_Login",
                timeout=10,
            )

            # get selector object
            data = await tab.send("DOM.resolveNode", nodeId=35, timeout=10)

            # get cord from object
            data = await tab.send(
                "Runtime.callFunctionOn",
                objectId="-2356252709899708064.1.5",
                functionDeclaration="(function() {rect = this.getBoundingClientRect();return JSON.stringify(rect);})",
                timeout=10,
            )

            # click
            await tab.mouse_click(733, 0)

目前我是这样

ClericPy commented 1 year ago

解决了不? 这是写死了位置么

zenghh commented 1 year ago

不是写死,就大概流程是这样

ClericPy commented 1 year ago

我也没其他啥办法, 这是绕开了? 看起来挺好啊

zenghh commented 1 year ago

这可以,但挺繁琐,这块可以抽出来放asynctab里

ClericPy commented 1 year ago

当时没做主要还是挺麻烦... 我主要是没想好抽象成几个对象, 不过看起来确实是可复用的样子

这得花时间研究研究, 当初还是对这部分不深入, 看到对象太多属性太多就选了个捷径, 实际上你的方法确实比原生 JS 更好.

欢迎提 PR 咱们一块讨论一下, ichrome 这个库刚开始写的时候我连领域驱动都不懂, 现在里面结构一团糟. 然后也比较冷门, 能满足我日常需求之后就关注的少了. 实际上实体抽象有很多很多不合理的部分, 好多东西也耦合的特别紧, 有一段时间想大刀阔斧重构 async_utils

zenghh commented 1 year ago

问一下,能否直接注入tampermonkey的脚本呢

ClericPy commented 1 year ago

安装 tampermonkey 然后当普通浏览器用是可以, 至于注入, 很多依赖不确定它有没有, 没试过

zenghh commented 1 year ago

AsyncChromeDaemon怎么常驻不退出啊,run_forever好像没用

ClericPy commented 1 year ago

本来就不退出啊, 在 async with 里面. 你可以把 async with 拆成 __aenter__ __aexit__

zenghh commented 1 year ago
async def main():
    async with AsyncChromeDaemon(
        clear_after_shutdown=True,
        headless=False,
        disable_image=False,
    ) as cd:
        async with cd.connect_tab(0, auto_close=True) as tab:
            await cd.run_forever()

直接退出了啊,浏览器 关了,我想让浏览器一直开着

ClericPy commented 1 year ago

呃, 看了下是个 bug

应该遵循 block 参数, 结果遵循的是 AsyncChromeDaemon 对象的 _block 参数了.

临时处理一下可以在 AsyncChromeDaemon 加参数 block=True. 下次发版修它

zenghh commented 1 year ago

好像也不行,加了block之后,卡住了,代码不执行

ClericPy commented 1 year ago

这个 bug 超过 3 年没发现, 是因为很少用它, 拆成 __aenter__ __aexit__ 算了

也就是启动的时候

cd = AsyncChromeDaemon(
        clear_after_shutdown=True,
        headless=False,
        disable_image=False,
    )
await cd.__aenter__()

回收的时候

await cd.__aexit__()
ClericPy commented 1 year ago

简单地说, 在 async with 上下文包裹里面, 进程是不关闭的

await cd.run_forever() 是阻塞的

zenghh commented 1 year ago

带验证的代理要怎么写呢

ClericPy commented 1 year ago

https://github.com/ClericPy/ichrome/issues/86

zenghh commented 1 year ago

http://username:password@host:port/ 这种格式可以吗

ClericPy commented 1 year ago

上面那个 issue 说的很明白了

zenghh commented 1 year ago
async def main():
    async with AsyncChromeDaemon(
        clear_after_shutdown=True,
        headless=False,
        disable_image=False,
        # user_data_dir="./data365",
    ) as cd:
        async with cd.incognito_tab() as tab:

这样的话除了打开隐私模式的一个窗口,还会打开一个默认的,怎么关掉这个默认的

ClericPy commented 1 year ago

默认的在 flatten 模式里是 ws 的主连接, 一般关不上. 不过貌似强制关了的时候活着的浏览器上下文会接替主进程活下来.

我没关过, 一直 Headless 反正看不见

zenghh commented 1 year ago

Page.createIsolatedWorld 这个有用过吗,好像用这个能避开检测?

ClericPy commented 1 year ago

没有, 只用过更改定位/时区之类以及屏蔽指纹的

zenghh commented 1 year ago

怎么判断一个元素是否已经可以点击呢

ClericPy commented 1 year ago

我是用 JS 判断 HTML 源码的. 先 wait_tag 等 tag 出现, 然后看它是不是 disabled

zenghh commented 1 year ago

有不用document.querySelector的方法吗

ClericPy commented 1 year ago

不知道了

zenghh commented 1 year ago

await tab.keyboard_send 要删除的话要怎么做

ClericPy commented 1 year ago

https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent

keyIdentifier string Unique key identifier (e.g., 'U+0041') (default: ""). code string Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: ""). key string Unique DOM defined string value describing the meaning of the key in the context of active modifiers, keyboard layout, etc (e.g., 'AltGr') (default: "").

找对应按键的标准识别码

ClericPy commented 1 year ago
    Keyboard Events:
        code:
            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
        key:
            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
        keyIdentifier(Deprecated):
            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyIdentifier

之前忘记放文档里了. 有中文

zenghh commented 1 year ago

谢谢

ClericPy commented 1 year ago

客气, 那几个按键标识码我之前用过几次就忘了放文档里了

zenghh commented 1 year ago

cdp有办法控制firefox吗

ClericPy commented 1 year ago

https://chromedevtools.github.io/devtools-protocol/

The Chrome DevTools Protocol allows for tools to instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browsers. Many existing projects currently use the protocol. The Chrome DevTools uses this protocol and the team maintains its API.

ClericPy commented 1 year ago

https://firefox-source-docs.mozilla.org/remote/index.html

Firefox implements a subset of the Chrome DevTools Protocol (CDP) in order to support third party automation tools such as puppeteer. The documentation for the remote protocol (CDP) implement can be found at remote/cdp.