首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当我使用ThreadPool时,程序在完成后等待关闭

当我使用ThreadPool时,程序在完成后等待关闭
EN

Stack Overflow用户
提问于 2021-11-18 19:34:01
回答 1查看 35关注 0票数 0

我的代码从网站保存页面,并使用bs4获取其他页面的urls。在我之前的问题中,我被建议使用多线程而不是多处理,我得到的代码一开始确实对我有帮助。然而,当我在100+操作上测试它时,它并没有在完成后关闭(等待了10分钟),我注意到程序并没有保存所有的页面(在不同的运行中,它也不会保存不同的页面,大约是5-8个页面)。对于30个操作,它一致地保存所有操作,并等待大约10秒才停止。也许代码在等待剩余的线程?如何修复未结账?这是我得到的代码:

代码语言:javascript
复制
# libraries
import os
from bs4 import BeautifulSoup
from selenium import webdriver
from multiprocessing.pool import ThreadPool
import threading

# variables
url = "https://eldorado.ua/"
directory = os.path.dirname(os.path.realpath(__file__))
env_path = directory + "\chromedriver"
chromedriver_path = env_path + "\chromedriver.exe"
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 " \
            "Safari/537.36 "
dict1 = {"Смартфоны и телефоны": "https://eldorado.ua/node/c1038944/",
         "Телевизоры и аудиотехника": "https://eldorado.ua/node/c1038957/",
         "Ноутбуки, ПК и Планшеты": "https://eldorado.ua/node/c1038958/",
         "Техника для кухни": "https://eldorado.ua/node/c1088594/",
         "Техника для дома": "https://eldorado.ua/node/c1088603/",
         "Игровая зона": "https://eldorado.ua/node/c1285101/",
         "Гаджеты и аксесуары": "https://eldorado.ua/node/c1215257/",
         "Посуда": "https://eldorado.ua/node/c1039055/",
         "Фото и видео": "https://eldorado.ua/node/c1038960/",
         "Красота и здоровье": "https://eldorado.ua/node/c1178596/",
         "Авто и инструменты": "https://eldorado.ua/node/c1284654/",
         "Спорт и туризм": "https://eldorado.ua/node/c1218544/",
         "Товары для дома и сада": "https://eldorado.ua/node/c1285161/",
         "Товары для детей": "https://eldorado.ua/node/c1085100/"}
count = 0
threaded_data = threading.local()  # Создаёт хранилище (класс) для потоков, чтобы не вызывать webdriver при каждой итерации
os.environ['PATH'] += env_path  # Добавляет chromedriver в PATH


class Driver:
    def __init__(self):
        options = webdriver.ChromeOptions()
        options.headless = True
        options.add_experimental_option("excludeSwitches", ['enable-automation'])
        options.add_argument(f'--user-agent={UserAgent}')
        self.driver = webdriver.Chrome(executable_path=chromedriver_path, options=options)

    def __del__(self):
        self.driver.quit()  # driver.quit(), когда переменная больше не используется (при окончании выполнения потока)
        print('The driver has been quited.')


def create_driver():
    the_driver = getattr(threaded_data, 'the_driver', None)
    if the_driver is None:
        the_driver = Driver()
        setattr(threaded_data, 'the_driver', the_driver)
    return the_driver.driver


def processing_brand_pages(name):
    with open(f"{directory}\section_pages\\{name}.html", encoding="utf-8") as file:
        soup = BeautifulSoup(file.read(), "lxml")
    links = soup.find_all("div", class_="title")
    driver = create_driver()
    for n in links:
        ref = url + n.find('a').get('href')
        global count
        print(n.text, count)
        count += 1
        driver.get(ref)
        try:
            with open(f"{directory}\\brand_pages\\{name}\\{n.text}.html", "w", encoding="utf-8") as file:
                file.write(driver.page_source)
        except Exception as ex:
            print(ex)


if __name__ == "__main__":
    ThreadPool(processes=6).map(processing_brand_pages, dict1.keys())
    del threaded_data  # Quit all the Selenium drivers
    import gc
    gc.collect()

我已经将其修改为不使用Class (个人偏好):

代码语言:javascript
复制
# libraries
import os
from bs4 import BeautifulSoup
from selenium import webdriver
from multiprocessing.pool import ThreadPool
import threading

# variables
url = "https://eldorado.ua/"
directory = os.path.dirname(os.path.realpath(__file__))
env_path = directory + "\chromedriver"
chromedriver_path = env_path + "\chromedriver.exe"
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 " \
            "Safari/537.36 "
dict1 = {"Смартфоны и телефоны": "https://eldorado.ua/node/c1038944/",
         "Телевизоры и аудиотехника": "https://eldorado.ua/node/c1038957/",
         "Ноутбуки, ПК и Планшеты": "https://eldorado.ua/node/c1038958/",
         "Техника для кухни": "https://eldorado.ua/node/c1088594/",
         "Техника для дома": "https://eldorado.ua/node/c1088603/",
         "Игровая зона": "https://eldorado.ua/node/c1285101/",
         "Гаджеты и аксесуары": "https://eldorado.ua/node/c1215257/",
         "Посуда": "https://eldorado.ua/node/c1039055/",
         "Фото и видео": "https://eldorado.ua/node/c1038960/",
         "Красота и здоровье": "https://eldorado.ua/node/c1178596/",
         "Авто и инструменты": "https://eldorado.ua/node/c1284654/",
         "Спорт и туризм": "https://eldorado.ua/node/c1218544/",
         "Товары для дома и сада": "https://eldorado.ua/node/c1285161/",
         "Товары для детей": "https://eldorado.ua/node/c1085100/"}
count = 0
threaded_data = threading.local()  # Создаёт экземпляр класса (типо хранилище) для потоков, чтобы не вызывать webdriver при каждой итерации
os.environ['PATH'] += env_path  # Добавляет chromedriver в PATH


def processing_brand_pages(name):
    with open(f"{directory}\section_pages\\{name}.html", encoding="utf-8") as file:
        soup = BeautifulSoup(file.read(), "lxml")
    links = soup.find_all("div", class_="title")
    driver = put_driver_in_threaded_data()
    for n in links:
        ref = url + n.find('a').get('href')
        global count
        print(n.text, count)
        count += 1
        driver.get(ref)
        try:
            with open(f"{directory}\\brand_pages\\{name}\\{n.text}.html", "w", encoding="utf-8") as file:
                file.write(driver.page_source)
        except Exception as ex:
            print(ex)


def put_driver_in_threaded_data():
    threaded_driver = getattr(threaded_data, 'driver_in_threaded_data', None)
    if threaded_driver is None:
        options = webdriver.ChromeOptions()
        options.headless = True
        options.add_experimental_option("excludeSwitches", ['enable-automation'])
        options.add_argument(f'--user-agent={UserAgent}')
        threaded_driver = webdriver.Chrome(executable_path=chromedriver_path, options=options)
        setattr(threaded_data, 'driver_in_threaded_data', threaded_driver)
    return threaded_driver


if __name__ == "__main__":
    ThreadPool(processes=6).map(processing_brand_pages, dict1.keys())
    del threaded_data  # Quit all the Selenium drivers
    import gc
    gc.collect()

两者都以相同的方式工作,问题也都发生在它们身上。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-18 19:51:33

我认为你需要写:

代码语言:javascript
复制
with ThreadPool(processes=6) as pool:
    pool.map(processing_brand_pages, dict1.keys())

这会强制在执行下一条语句之前执行pool.join()。现在你的代码已经写好了,你只需要启动线程,然后继续往前冲。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70025698

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档