python - 多线程冻结程序
问题描述
我有一个 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:\Users\Bassel Attia\Documents\Trading Core\1.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()
解决方案
不幸的是,通过检查您提供的代码,我无法重现该问题,但有些事情可能会出现问题:
- 文件 currentStock.png 被删除两次(我很惊讶它不会在您第二次尝试删除它时引发异常)
- 您不断覆盖相同的“screenshot.png”文件
- args 不是列表
如果这有帮助,这是一个最小的工作示例:
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()
推荐阅读
- javascript - 使用 splice() 删除对象的数组元素
- html - 如何制作动画(收藏)图标?
- stripe-payments - 条纹收集和支付
- azure - 如何限制 Azure 应用注册的 Microsoft Graph 权限?
- python - 烧瓶阅读字典
- swift - 语法解释: () -> Swift 中的文本
- solr - Solr seach 完全匹配返回而不修改配置文件
- php - FreeNAS - FAMP(用于 Piwigo):未加载 PHP 扩展“mysqli”
- java - 返回数组中每个数字的最后一位
- android - 如何使用 Oboe(用于 Android 低延迟音频的 C++ 库)从 DatagramPacket 接收 byte[] 缓冲区?