python - 使用 splinter/selenium 加速网页解析
问题描述
我正在尝试实现以下目标。
- 使用 splinter 访问 URL
- 将浏览器实例传递给使用多进程( multiprocessing.Process )的所有方法
- 所有方法都在线程中执行,减少了总时间
示例代码如下所示。
from splinter import Browser
from multiprocessing import Process, Queue, current_process, freeze_support
#
# Function run by worker processes
#
def worker(input, output):
for func, args in iter(input.get, 'STOP'):
result = calculate(func, args)
output.put(result)
#
# Function used to calculate result
#
def calculate(func, args):
print(args)
result = func(*args)
return '%s says that %s%s = %s' % \
(current_process().name, func.__name__, args, result)
def get_meta_tag_title(browser):
return browser.find_by_xpath('//title')[0]['text']
def get_meta_tag_description(browser):
return browser.find_by_xpath('//description')[0]['text']
#
#
#
def test():
browser = Browser(headless=True)
browser.visit('https://example.com')
NUMBER_OF_PROCESSES = 2
TASKS1 = [(get_meta_tag_title, (browser)), (get_meta_tag_description, (browser))]
# Create queues
task_queue = Queue()
done_queue = Queue()
# Submit tasks
for task in TASKS1:
task_queue.put(task)
# Start worker processes
for i in range(NUMBER_OF_PROCESSES):
Process(target=worker, args=(task_queue, done_queue)).start()
# Get and print results
print('Unordered results:')
for i in range(len(TASKS1)):
print('\t', done_queue.get())
browser.quit()
if __name__ == '__main__':
freeze_support()
test()
我的问题是——
- 这是正确的方法吗?,使用浏览器实例获取所有元素信息/值是否是线程安全的
- 将浏览器实例添加到队列会导致
TypeError: cannot serialize '_io.BufferedWriter' object
我应该使用池吗?
解决方案
Splinter 基于 selenium WebDriver
,它不是线程安全的,因此您可能不应该在生产中的单独线程中使用它。实际上,它可能会起作用,因为您正在执行的操作是只读的。不使用线程的另一个可能原因是您尝试并行化的操作是 CPU 密集型的,并且在大多数此类情况下,由于 GIL,python 线程不会提高性能。
另一方面,多处理确实可以帮助您并行处理 CPU 密集型工作。但是将浏览器对象传递给每个工作进程(就像您所做的那样)将不起作用,因为浏览器拥有打开的文件、套接字,并且拥有自己的有状态驱动程序实例。这些不能被轻易复制并传递给另一个进程。相反,您可以做的是在每个工作人员中创建一个浏览器对象,导航到该页面并随后在其上执行您的任务。
编辑
要进一步缩短执行时间,您可以尝试:- 使用除 之外的定位器方法
find_by_xpath
,它本质上很慢,因为它遍历整个 DOM。 - 使用
requests
库来获取 html 内容并lxml
解析它而不是使用 selenium,因为 webdriver 可能会导致一些严重的开销。
推荐阅读
- java - HTTP 错误:503 服务不可用 IntelliJ IDEA GWT
- javascript - 如何将控件保持在同一页面上,直到文本框正确为止。字符?
- mysql - MySQL Query - 如何根据多列内连接的一列获取唯一行
- list - 基于条件的 Ansible 合并列表
- reactjs - Material UI TextField 标签出现在 popper 上
- javascript - 循环通过 NodeList 删除元素
- c - 如何将 long long 转换为字符串?
- java - 如何初始化具有特定泛型类型的对象数组?
- dynamic - 访问动态元素中的属性
- java - 如何多次读取 Jetty HttpInput (ServletInputStream)?