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

请问一下可以在一个浏览器中开多个页面,并且多个页面设置不同的代理吗 #104

Closed jiaxian-lin closed 1 year ago

jiaxian-lin commented 1 year ago

网站反扒有点厉害,速度不能太快,想多用几个进程提速,但是开太多个谷歌的话又很占用性能

ClericPy commented 1 year ago

呃, 到底是要太快还是不要太快...

Chromium 可以用 context 在一个 chrome 下开多个上下文, 分别用不同的 proxyServer 挂不同代理就行了. 不用开多进程, 协程里就行了, 子进程我这里会帮你启动.

简单地说, BrowserContext 有点像平时用的隐私模式, 而且也不用自己清理缓存什么的挺方便的, chrome 似乎不支持挂不同代理(实验性功能). 具体用法文档里有个例子挂代理的

jiaxian-lin commented 1 year ago

就是单个代理访问不能太快,这部分有示例代码吗

ClericPy commented 1 year ago

async with cd.incognito_tab(proxyServer='http://127.0.0.1:8080') as tab: 就行了, 每个匿名 tab 都是单独的 Context, 和单独实例差不多. 并发的话就是 asyncio.create_task 那套. 实际只启动了一个默认的 chrome 主实例, 然后匿名模式开了多个浏览器上下文和其他上下文不共享数据

jiaxian-lin commented 1 year ago

谢谢解答,那我想问一下 如果运行到一半这个ip被封了,我可以直接更换这个tab的ip吗?还是得关掉这个tab重新开一个

ClericPy commented 1 year ago

默认 CDP 协议一个 BrowserContext 只有一个 proxyServer 的, 反正用 Chromium + Headless + incognito_tab 就行了, 调试的时候别开 Headless 看看效果吧, 这里 incognito_tab 实际上就是新建了一个 Context (也就是 IncognitoTabContext 对象) 然后在那里面新开个 tab, 是一整套包装好的, async with 离开的时候会把 Context 一起关闭的

jiaxian-lin commented 1 year ago

这个是我目前实现并发的方式,然后我如果以tab为传参的话会报错,大佬您说的这个Chromium是什么

async def run(dp_port):
    udd = f'/googlehome/{dp_port}'
    async with AsyncChromeDaemon(port=dp_port, disable_image=True,proxy="http://192.168.112.1:24000", user_data_dir=udd) as cd:
        async with cd.connect_tab() as tab:

async def main():
    db_list = [9310 + offset for offset in range(7)]
    async with aiomultiprocess.Pool() as aio_pool:
        await aio_pool.map(run, db_list)
    await aio_pool.join()
ClericPy commented 1 year ago

我一般用原生的 asyncio. 而且没必要多进程, 用协程的 asyncio.create_task 的方式启动多个任务收集到 list 里, 然后挨个 await 就行了吧, 不过前提是用 Chromium 浏览器, 否则实验性功能那个每个 tab 用不同代理会不生效. 你这个用协程来并发也可以的, 反正我本来就控制了多进程

没报错信息么

ClericPy commented 1 year ago

tab 不要传到别的进程里啊... 协程的主要要求就是保证在同一个线程里的同一个时间循环. 你这段代码抛错了么

jiaxian-lin commented 1 year ago

这段代码没问题,但是这段代码启动了很多个chrome,我想通过下面这段代码解决,但是报错了

async def run(tab):
    await tab.goto('https://baidu.com', timeout=5)
    print(await tab.html)

async def main():
    async with AsyncChromeDaemon() as cd:
        async with cd.incognito_tab(proxyServer='http://192.168.112.1:24000') as tab:
            asyncio.create_task(run(tab))

报错信息

ichrome.exceptions.ChromeRuntimeError: [closed] <Tab(disconnected-<Chrome(disconnected): 9222>): 2A8C3BD5873539F64C43E0501214E0AF> ws has been closed
ClericPy commented 1 year ago

因为你没 await 它结束, 所以没阻塞就离开了 tab 的上下文人家就关了连接

你是 asyncio.run(main()) 启动的么. 匿名 tab 启动的多个上下文实际就是多个浏览器窗口, Headless 一下就没事了, 成本比冷启动多个 AsyncChromeDaemon 要低一些

首先需要并发创建 task 的入参应该是 cd, 在单个任务里启动多个 tab. 启动多个 chrome 原因是你并发任务里 async with AsyncChromeDaemon() as cd: 就是启动一个 chrome 实例

此外, 系统自带 chrome 不一定能挂上不同代理, 之前我是安装 Chromium 解决的, 自己下载安装个 Chromium 然后把 exe 文件路径传入 Daemon 对象启动就行了

jiaxian-lin commented 1 year ago

大佬你是这个意思吗

async def run(tab):
    await tab.goto('https://baidu.com', timeout=5)
    print(await tab.html)

async def main():
    task_list = []
    async with AsyncChromeDaemon() as cd:
        for i in range(5):
            async with cd.incognito_tab(proxyServer='http://192.168.112.1:24000') as tab:
                task_list.append(asyncio.create_task(run(tab)))
        for task in task_list:
            await task

可是还是报了一样的错,我不用list的时候是没问题的

ichrome.exceptions.ChromeRuntimeError: [closed] <Tab(disconnected-<Chrome(disconnected): 9222>): D041473DEA5F4C3106018284F03E3D2A> ws has been closed
ClericPy commented 1 year ago

async def run(cd):
    async with cd.incognito_tab(
            proxyServer='http://192.168.112.1:24000') as tab:
        await tab.goto('https://baidu.com', timeout=5)
        print(await tab.html)

async def main():
    task_list = []
    async with AsyncChromeDaemon() as cd:
        for i in range(5):
            task_list.append(asyncio.create_task(run(cd)))
        for task in task_list:
            await task

说了是传入 cd, 不要传入 tab. 你得让 tab 在使用时它自己上下文没跳出去, 否则跳出去肯定就断开了

incognito_tab 如果想挂不同代理, 最好先请求 httpbin.org/ip 试试是否生效

jiaxian-lin commented 1 year ago

那这种方式其实是只启动了多个上下文是嘛?

ClericPy commented 1 year ago

对, 启动了多个上下文(指纹或者 Cookie 什么的都是隔离的), 但是代理是否有效我不确定, 早些时候 chrome 是不行的, Chromium 可以. 不过那实验室功能不一定转正了没有

jiaxian-lin commented 1 year ago

okok,明白了 多谢大佬!!!

ClericPy commented 1 year ago

刚才试了下 chrome 还是挂不上代理...

ClericPy commented 1 year ago

python -m ichrome --install=./chromium 可以自动下载解压缩到当前目录, 然后把 .exe 文件填写到程序里就行了

过程中也会提示最新的地址 https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Win_x64%2F1063735%2Fchrome-win.zip?alt=media 自己下载解压也行.

jiaxian-lin commented 1 year ago

我用的是ubuntu 可以挂上代理

ClericPy commented 1 year ago

啊想起来了... 之前我一直可以挂上是因为我 linux 上测的, 当时问的那个人是 Windows chrome. OK 祝愉快

jiaxian-lin commented 1 year ago

感谢感谢~ 我觉得你做的这个非常不错~希望以后我更熟悉以后可以帮忙维护~

ClericPy commented 1 year ago

好的, 发现 bug 随时提, 一般 24 小时内修, 如果能直接提 PR 更好

挺长时间没维护这个库了, 当初在上家公司一直用它做分布式 Facebook 养号发现大量 bug, 几乎每周都在修. 新公司以后同事用 playwright 去了我也就懒得折腾了

打算写点别的有意思的去了

jiaxian-lin commented 1 year ago

嗯嗯,发现一个问题,headless与daili 如果一起启用的时候,代理会失效,不懂什么原因

ClericPy commented 1 year ago

换 Chromium 试试?

有点离谱, 我 Windows 上 Chromium 都挂不上代理了... 太久没关注这东西了不知道有变啥了

之前 chrome 有个坑就是非 127 的 host 只能用 Headless, 很麻烦还得端口转发

ClericPy commented 1 year ago

问题不再关注, 关闭 (我之前发现挂代理相关的东西 chrome 有可能不行, Chromium 就可以. 然后你想每个页面挂不同代理, 我是通过代理转发服务实现的, 挂同样的代理地址, 但是请求的时候自动切换代理)