【问题标题】:Speeding up webpage parsing with splinter/selenium使用 splinter/selenium 加速网页解析
【发布时间】:2020-07-20 09:32:52
【问题描述】:

我正在尝试实现以下目标。

  1. 使用 splinter 访问 URL
  2. 将浏览器实例传递给使用多进程 (multiprocessing.Process) 的所有方法
  3. 所有方法都在线程中执行,减少了总时间

示例代码如下所示。

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()

我的问题是 -

  1. 这是正确的方法吗?,使用浏览器实例获取所有元素信息/值是否线程安全
  2. 将浏览器实例添加到队列会导致TypeError: cannot serialize '_io.BufferedWriter' object 我应该使用池吗?

【问题讨论】:

  • 1.您在问题中说您正在使用线程,但您的代码正在使用进程。 2. 你真的有性能问题吗?瓶颈是什么?
  • 是的,基本上我的代码使用浏览器实例来查找元标记、内联样式、内部链接、社交链接等一些东西。我想让这些功能同时运行以减少整体执行时间。

标签: python multithreading thread-safety python-multithreading splinter


【解决方案1】:

Splinter 基于 selenium 的WebDriver,即not thread safe,因此您可能不应该在生产中的单独线程中使用它。实际上,它可能会起作用,因为您正在执行的操作是只读的。不使用线程的另一个可能原因是,您尝试并行化的操作是 CPU 密集型的,在大多数情况下,由于 GIL,python 线程不会提高性能。

另一方面,多处理确实可以帮助您并行处理 CPU 密集型工作。但是将浏览器对象传递给每个工作进程(如您所做的那样)将不起作用,因为浏览器拥有打开的文件、套接字,并拥有自己的有状态驱动程序实例。这些不能被轻易复制并传递给另一个进程。相反,您可以做的是在每个工作人员中创建一个浏览器对象,导航到该页面并随后在其上执行您的任务。

编辑

要进一步缩短执行时间,您可以尝试:
  1. 使用 find_by_xpath 以外的定位器方法,它本身就很慢,因为它遍历整个 DOM。
  2. 使用 requests 库获取 html 内容并使用 lxml 解析它而不是使用 selenium,因为 webdriver 可能会导致一些严重的开销。

【讨论】:

  • 有道理,我的目标是扫描网页以寻找可能的改进。您是否会建议任何其他技术堆栈来帮助改善整体执行时间
  • 我使用 selenium 的原因是——我对网页在被真正的最终用户访问时的行为更感兴趣——例如加载网页需要多长时间,包括作为 JS 的资产, CSS - 有时会花费大量时间来加载会降低用户体验。我正在考虑的另一种方法是让 WebSocket 更新每个组件并在结果准备好后立即将数据发送回 WebSocket - 想法?
  • 有什么想法吗?
  • 这听起来像是一个完全不同的问题。您应该单独发布它
猜你喜欢
  • 2021-11-18
  • 2020-10-03
  • 2020-05-27
  • 2018-05-03
  • 2020-04-11
  • 2014-10-10
  • 2018-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多