连接池已满,通过Selenium和Python放弃与ThreadPoolExecutor和多个无头浏览器的连接
我正在使用连接池已满,通过Selenium和Python放弃与ThreadPoolExecutor和多个无头浏览器的连接,python,selenium,threadpool,threadpoolexecutor,urllib3,Python,Selenium,Threadpool,Threadpoolexecutor,Urllib3,我正在使用selenium==3.141.0,python3.6.7,chromedriver 2.44编写一些自动化软件 大多数逻辑都可以由单个浏览器实例执行,但对于某些部分,我必须启动10-20个实例才能获得适当的执行速度 一旦涉及到由ThreadPoolExecutor执行的部分,浏览器交互将开始抛出此错误: WARNING|05/Dec/2018 17:33:11|connectionpool|_put_conn|274|Connection pool is full, discardi
selenium==3.141.0
,python3.6.7
,chromedriver 2.44
编写一些自动化软件
大多数逻辑都可以由单个浏览器实例执行,但对于某些部分,我必须启动10-20个实例才能获得适当的执行速度
一旦涉及到由ThreadPoolExecutor
执行的部分,浏览器交互将开始抛出此错误:
WARNING|05/Dec/2018 17:33:11|connectionpool|_put_conn|274|Connection pool is full, discarding connection: 127.0.0.1
WARNING|05/Dec/2018 17:33:11|connectionpool|urlopen|662|Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))': /session/119df5b95710793a0421c13ec3a83847/url
WARNING|05/Dec/2018 17:33:11|connectionpool|urlopen|662|Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fcee7ada048>: Failed to establish a new connection: [Errno 111] Connection refused',)': /session/119df5b95710793a0421c13ec3a83847/url
相关代码:
def init_chromedriver(cls):
try:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument(f"user-agent={Utils.get_random_browser_agent()}")
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(driver_paths['chrome'],
chrome_options=chrome_options,
service_args=['--verbose', f'--log-path={bundle_dir}/selenium/chromedriver.log'])
driver.implicitly_wait(10)
return driver
except Exception as e:
logger.error(e)
with ProfileParser(acc) as pparser:
pparser.collect_user_info(posts[0])
ProfileParser
实例化webdriver并执行一些页面交互。我认为交互本身并不相关,因为没有ThreadPoolExecutor
,一切都可以运行。
然而,简言之:
class ProfileParser(object):
def __init__(self, acc):
self.driver = Utils.init_chromedriver()
def __exit__(self, exc_type, exc_val, exc_tb):
Utils.shutdown_chromedriver(self.driver)
self.driver = None
collect_user_info(post_url)
self.driver.get(post_url)
profile_url = self.driver.find_element_by_xpath('xpath_here')]').get_attribute('href')
在ThreadPoolExecutor
中运行时,上面的错误出现在此时self.driver.find\u element\u by_xpath
或self.driver.get
这起作用了:
def init_chromedriver(cls):
try:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument(f"user-agent={Utils.get_random_browser_agent()}")
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(driver_paths['chrome'],
chrome_options=chrome_options,
service_args=['--verbose', f'--log-path={bundle_dir}/selenium/chromedriver.log'])
driver.implicitly_wait(10)
return driver
except Exception as e:
logger.error(e)
with ProfileParser(acc) as pparser:
pparser.collect_user_info(posts[0])
这些选项不起作用:(连接池错误
)
更新:
def init_chromedriver(cls):
try:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument(f"user-agent={Utils.get_random_browser_agent()}")
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(driver_paths['chrome'],
chrome_options=chrome_options,
service_args=['--verbose', f'--log-path={bundle_dir}/selenium/chromedriver.log'])
driver.implicitly_wait(10)
return driver
except Exception as e:
logger.error(e)
with ProfileParser(acc) as pparser:
pparser.collect_user_info(posts[0])
我找到了一个临时解决方案(它不会使这个初始问题无效)——在ProfileParser
类之外实例化webdriver
。我不知道它为什么有效,但首字母无效。我想原因在某些语言细节中?
感谢您的回答,但是问题似乎并不在于ThreadPoolExecutor
max\u workers
限制-正如您在我尝试提交单个实例的其中一个选项中看到的,它仍然不起作用
当前解决方法:
futures = []
with ThreadPoolExecutor(max_workers=10) as executor:
for p in posts:
driver = Utils.init_chromedriver()
futures.append({
'future': executor.submit(collect_user_info, driver, acc, p),
'driver': driver
})
for f in futures:
f['future'].done()
Utils.shutdown_chromedriver(f['driver'])
请查看您的错误
ProtocolError('Connection aborted.',
RemoteDisconnected('Remote end closed connection without response',))
'NewConnectionError('<urllib3.connection.HTTPConnection object at >:
Failed to establish a new connection: [Errno 111] Connection refused',)':
ProtocolError('Connection aborted'),
RemoteDisconnected('远程端关闭连接,无响应',))
“NewConnectionError(”:
无法建立新连接:[Errno 111]连接被拒绝',)':
该错误是因为您的多重连接速度太快,可能是服务器关闭或服务器阻止了您的请求 此错误消息
WARNING|05/Dec/2018 17:33:11|connectionpool|_put_conn|274|Connection pool is full, discarding connection: 127.0.0.1
WARNING|05/Dec/2018 17:33:11|connectionpool|urlopen|662|Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))': /session/119df5b95710793a0421c13ec3a83847/url
WARNING|05/Dec/2018 17:33:11|connectionpool|urlopen|662|Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fcee7ada048>: Failed to establish a new connection: [Errno 111] Connection refused',)': /session/119df5b95710793a0421c13ec3a83847/url
是使用线程池异步执行调用的子类。当与未来关联的可调用对象等待另一个未来的结果时,可能会发生死锁
class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())
- 一个Executor子类,它使用最多包含max_工作线程的池异步执行调用
- 初始值设定项是一个可选的可调用项,在每个工作线程开始时调用;initargs是传递给初始值设定项的参数元组。如果初始值设定项引发异常,则所有当前挂起的作业都将引发BrokenThreadPool,以及任何向该池提交更多作业的尝试
- 从3.5版开始:如果没有或没有指定max_workers,则默认为计算机上的处理器数量乘以5,假设ThreadPoolExecutor经常用于重叠I/O而不是CPU工作,并且Worker数量应高于ProcessPoolExecutor的Worker数量
- 从3.6版开始:添加了thread_name_prefix参数,允许用户控制线程。为便于调试,池创建的工作线程的线程名称
- 从版本3.7开始:添加了初始值设定项和initargs参数
\u get\u conn()
从池中获取None,它只会创建一个新连接。但奇怪的是,它应该从所有这些None对象开始,而且_put_conn()不够聪明,无法用连接替换None
然而,合并已经解决了这个问题
解决方案
增加默认连接池大小10,这是以前硬编码的,现在是可配置的,将解决您的问题
更新 根据您的评论更新…提交单个实例,结果相同。。。。根据讨论中的@meferguson84: 我将代码插入到它挂载适配器的地方,只是为了处理池大小,看看它是否有所不同。我发现队列中充满了非类型对象,实际上载连接是列表中的最后一项。这个列表有10个条目(这很有意义)。没有意义的是,池的unfinished_tasks参数是11。当队列本身只有11个项目时,这怎么可能呢?另外,队列中充满了非类型对象,并且我们使用的连接是列表中的最后一项,这正常吗 在您的用例中,这听起来也是一个可能的原因。这听起来可能有些多余,但您仍可以执行以下几个特殊步骤:
- 通过IDE清理项目工作区,并仅使用所需的依赖项重建项目
- (仅限Windows OS)在执行测试套件之前和之后,使用该工具清除所有操作系统杂务
- (仅限LinuxOS)在执行测试套件之前和之后
max\u workers
参数限制,ThreadPoolExecutor
假设将其作为一个队列处理,同时执行的实例数为max\u workers
。更新了question@user1935987我添加了一个答案更新。让我知道情况。我真的认为问题不在于遗嘱执行人本身。原因-我刚刚尝试了另一种方法,在与ThreadPoolExecutor
和我相同的类中实例化webdriver