#python #web-scraping
Вопрос:
У меня есть программа на python, в которой есть функция, takeScreenshot
которая делает снимок экрана с 10 введенными веб-страницами. Я хочу использовать потоковую обработку, чтобы часть веб-очистки при создании снимка экрана выполнялась в фоновом режиме, пока программа продолжает вводить дополнительные веб-страницы. После того, как вы сделаете 10 скриншотов, они должны быть отображены в программе.
Вопрос в том, как заставить программу отображать их после завершения последнего takeScreenshot
потока (десятого потока), чтобы не вызвать ошибку? Другими словами, как убедиться, что все потоки завершены? Я попытался составить список всех запущенных потоков и создать их .join()
после ввода последней веб-страницы (в последнем цикле). Однако это приводит к зависанию программы после ввода последней веб-страницы.
threads=[]
n=0
while n<10:
webpage = input("Enter the webpage")
thread = threading.Thread(target = takeScreenshot, args = webpage)
thread.start()
threads.append(thread)
if n==9:
for thread in threads:
thread.join()
n
Я попытался исследовать больше, поэтому обнаружил, что программа зависает в последнем цикле, когда она устанавливает атрибут класса, равный снимку экрана: self.graph = PhotoImage(file='screenshot.png')
. Обратите внимание, что снимок экрана последней веб-страницы обычно загружается, поэтому ошибка не связана с отсутствием снимка экрана. Предыдущая строка кода включена в takeScreenshot
функцию.
Вот takeScreenshot
метод (это часть класса, называемого scraping
:
ublockPath = r'C:UsersBassel AttiaDocumentsTrading Core1.37.2_0'
chromeOptions = Options()
chromeOptions.add_argument("--log-level=3")
chromeOptions.add_argument('load-extension=' ublockPath)
self.driver = webdriver.Chrome(ChromeDriverManager().install(),
chrome_options=chromeOptions)
self.driver.get(webpage)
self.driver.get_screenshot_as_file('screenshot.png')
self.image = Image.open('screenshot.png')
#crop screenshot
area = (20, 290, 1250, 800)
croppedImage=self.image.crop(area)
os.remove('currentStock.png')
croppedImage.save('screenshot.png')
self.image = Image.open('screenshot.png')
#resizeImage
newHeight = 300
newWidth = int(newHeight / self.image.height * self.image.width)
resizedImage = self.image.resize((newWidth, newHeight))
os.remove('currentStock.png')
resizedImage.save('screenshot.png')
self.image = Image.open('screenshot.png')
self.image.close()
self.driver.quit()
Комментарии:
1. Я тебя не понимаю. Не могли бы вы поподробнее, пожалуйста?
2. Я бы посоветовал вам использовать a
multiprocessing.pool.ThreadPool
, потому что вы можете отправить ему все задачи, которые хотите, а затем вызвать егоjoin()
метод, чтобы дождаться их завершения. Или вы могли бы сделать что-то подобное сconcurrent.futures.ThreadPoolExecutor
помощью, как предложено в связанной документации.3. Фрагмент кода, который вы отправили, кажется мне правильным.
.join()
ждет завершения потока. Я уверен, что ошибка в функции takeScreenshot4. @alec Я обновил пост, чтобы включить
takeScreenshot
функцию. А ты как думаешь?
Ответ №1:
Изучив предоставленный вами код, к сожалению, я не смог воспроизвести проблему, но есть некоторые вещи, которые могут быть проблематичными:
- файл currentStock.png удаляется дважды (и я удивлен, что при второй попытке его удаления не возникает исключение).
- вы продолжаете перезаписывать один и тот же файл «скриншот.png»
- аргументы-это не список
Если это может помочь, вот минимальный рабочий пример:
import os, io, threading, uuid
from PIL import Image
from selenium import webdriver
def screen(wid, webpage):
opts = webdriver.FirefoxOptions()
opts.add_argument('--headless')
print(wid, 'starting webdriver')
driver = webdriver.Firefox(options=opts)
driver.get(webpage)
print(wid, 'taking screenshot')
image_data = driver.get_screenshot_as_png()
image = Image.open(io.BytesIO(image_data))
area = (20, 290, 1250, 800)
cropped = image.crop(area)
h = 300
w = int(h / cropped.height * cropped.width)
resized = cropped.resize((w, h))
if not os.path.isdir('screen'):
os.mkdir('screen')
fname = os.path.join('screen', f'{uuid.uuid4()}.png')
resized.save(fname)
print(wid, f'screenshot saved to {fname}')
driver.quit()
def main():
threads = []
for wid in range(4):
webpage = input('Webpage: ')
thread = threading.Thread(target = screen, args = [wid, webpage])
thread.start()
threads.append(thread)
for i, thread in enumerate(threads):
thread.join()
print('joined thread : ', i)
if __name__ == '__main__':
main()