Python selenium 多处理

2025-03-25 08:47:00
admin
原创
13
摘要:问题描述:我用 python 编写了一个脚本,结合 selenium 从其登录页面抓取不同帖子的链接,最后通过跟踪指向其内页的 url 来获取每篇帖子的标题。虽然我在这里解析的内容是静态的,但我使用了 selenium 来查看它在多处理中的工作原理。但是,我的目的是使用多处理进行抓取。到目前为止,我知道 se...

问题描述:

我用 python 编写了一个脚本,结合 selenium 从其登录页面抓取不同帖子的链接,最后通过跟踪指向其内页的 url 来获取每篇帖子的标题。虽然我在这里解析的内容是静态的,但我使用了 selenium 来查看它在多处理中的工作原理。

但是,我的目的是使用多处理进行抓取。到目前为止,我知道 selenium 不支持多处理,但看来我错了。

我的问题是:当使用多处理运行时,如何使用 selenium 减少执行时间?

This is my try (it's a working one)

import requests
from urllib.parse import urljoin
from multiprocessing.pool import ThreadPool
from bs4 import BeautifulSoup
from selenium import webdriver

def get_links(link):
  res = requests.get(link)
  soup = BeautifulSoup(res.text,"lxml")
  titles = [urljoin(url,items.get("href")) for items in soup.select(".summary .question-hyperlink")]
  return titles

def get_title(url):
  chromeOptions = webdriver.ChromeOptions()
  chromeOptions.add_argument("--headless")
  driver = webdriver.Chrome(chrome_options=chromeOptions)
  driver.get(url)
  sauce = BeautifulSoup(driver.page_source,"lxml")
  item = sauce.select_one("h1 a").text
  print(item)

if __name__ == '__main__':
  url = "https://stackoverflow.com/questions/tagged/web-scraping"
  ThreadPool(5).map(get_title,get_links(url))

解决方案 1:

当使用多处理运行时,如何使用 selenium 减少执行时间

您的解决方案中,很多时间都花在为每个 URL 启动 Web 驱动程序上。您可以通过每个线程仅启动一次驱动程序来减少此时间:

(... skipped for brevity ...)

threadLocal = threading.local()

def get_driver():
  driver = getattr(threadLocal, 'driver', None)
  if driver is None:
    chromeOptions = webdriver.ChromeOptions()
    chromeOptions.add_argument("--headless")
    driver = webdriver.Chrome(chrome_options=chromeOptions)
    setattr(threadLocal, 'driver', driver)
  return driver


def get_title(url):
  driver = get_driver()
  driver.get(url)
  (...)

(...)

在我的系统上,这将时间从 1 分 7 秒缩短至 24.895 秒,提升了约 35%。若要自行测试,请下载完整脚本。

注意:ThreadPool使用受 Python GIL 约束的线程。如果大部分任务受 I/O 限制,那么这样做没问题。根据您对抓取结果进行的后处理,您可能希望改用multiprocessing.Pool。这将启动并行进程,这些进程作为一个组不受 GIL 约束。其余代码保持不变。

解决方案 2:

我认为巧妙的“每个线程一个驱动程序”解决方案的一个潜在问题是,它忽略了“退出”驱动程序的任何机制,因此留下了进程挂起的可能性。我会做以下更改:

  1. 而是使用类Driver来创建驱动程序实例并将其存储在线程本地存储中,但也有一个析构函数,quit当线程本地存储被删除时,该驱动程序将析构:

class Driver:
    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument("--headless")
        self.driver = webdriver.Chrome(options=options)

    def __del__(self):
        self.driver.quit() # clean up driver when we are cleaned up
        #print('The driver has been "quitted".')
  1. create_driver现在变成:

threadLocal = threading.local()

def create_driver():
    the_driver = getattr(threadLocal, 'the_driver', None)
    if the_driver is None:
        the_driver = Driver()
        setattr(threadLocal, 'the_driver', the_driver)
    return the_driver.driver
  1. 最后,在您不再使用ThreadPool实例之后但在终止之前,添加以下几行以删除线程本地存储并强制Driver调用实例的析构函数(希望如此):

del threadLocal
import gc
gc.collect() # a little extra insurance

解决方案 3:

我的问题:如何减少执行时间?

Selenium 似乎不适合进行网页抓取 - 尽管我很欣赏 YMMV,特别是当你需要模拟用户与网站的交互或者存在某些 JavaScript 限制/要求时。

对于不需要太多交互的抓取任务,我使用开源Scrapy Python 包进行大规模抓取任务取得了良好的效果。它具有开箱即用的多处理功能,可以轻松编写新脚本并将数据存储在文件或数据库中 - 而且速度非常

当作为完全并行的 Scrapy 蜘蛛实现时,你的脚本看起来会像这样(注意,我没有测试过这个,请参阅选择器的文档)。

import scrapy
class BlogSpider(scrapy.Spider):
    name = 'blogspider'
    start_urls = ['https://stackoverflow.com/questions/tagged/web-scraping']

    def parse(self, response):
        for title in response.css('.summary .question-hyperlink'):
            yield title.get('href')

要运行,请将其放入blogspider.py并运行

$ scrapy runspider blogspider.py

请参阅Scrapy 网站以获取完整教程。

请注意,得益于 @SIM 的提示,Scrapy 还通过scrapy-splash支持 JavaScript 。到目前为止,我还没有接触过它,所以除了它看起来与 Scrapy 的工作方式很好地集成在一起之外,我无法谈论它。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1950  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1439  
  在企业运营过程中,跨部门协作效率的高低直接影响着项目的推进速度与质量,进而关乎企业的整体竞争力。PLM(产品生命周期管理)项目管理软件作为一种强大的工具,正逐渐在提升跨部门协作效率方面发挥着关键作用。它打破了部门之间的信息壁垒,优化了业务流程,为企业各部门之间的协同工作提供了有力支持。PLM项目管理软件打破信息壁垒信息...
plm合规性管理   17  
  PLM(Product Lifecycle Management)软件,即产品生命周期管理软件,旨在助力企业对产品从概念设计到退役处理的全生命周期进行有效管理。通过整合产品数据、流程以及人员,PLM软件能显著提升企业的创新能力、生产效率并降低成本。然而,PLM软件的实施并非易事,众多企业在落地过程中遭遇诸多挑战。要实现...
国内plm系统排名   19  
  研发过程的可视化对于企业提升效率、保障项目顺利推进至关重要。PLM(产品生命周期管理)系统作为整合产品全生命周期信息的重要工具,与甘特图相结合,能为研发过程可视化提供强大支持。通过对PLM系统支撑下甘特图的优化展现,可以让项目团队成员、管理层等清晰了解研发进度、资源分配等关键信息,从而做出更科学的决策。接下来,我们将详...
plm系统主要干什么的   16  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用