Stack Exchange
value error i/o operation on closed file. openpyxlのエラーを解消したい
PythonでSeleniumを使って下記のWEBサイトをスクレイピングしています。
https://shoply.co.jp/
エクセルからJAN_CODEを読み込んで、サイトへJAN_CODEを検索して、画像・商品名・価格をエクセルに入れています。
エクセルデータ
JAN_CODE,画像,商品名,価格
2201047397049
4953103289055

画像,商品名,価格は取得できますが、下記のvalue errorが表示されます。
ヘアゴム 【チャイハネ】インディオノンパチヘアゴム
¥358
Traceback (most recent call last):
  File "c:\Users\test\Documents\python\test1.py", line 123, in <module>
    wb.save(file_excel)
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\workbook\workbook.py", line 407, in save
    save_workbook(self, filename)
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
    writer.save()
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
    self.write_data()
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\writer\excel.py", line 77, in write_data
    self._write_images()
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\writer\excel.py", line 116, in _write_images
    self._archive.writestr(img.path[1:], img._data())
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\drawing\image.py", line 48, in _data
    img = _import_image(self.ref)
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\openpyxl\drawing\image.py", line 16, in _import_image
  File "C:\Users\test\AppData\Local\Programs\Python\Python39\lib\site-packages\PIL\Image.py", line 3096, in open     
    fp.seek(0)
ValueError: I/O operation on closed file.

wb.save(file_excel)エクセルを保存するときに問題ありますでしょうか。
pip listのPackage Versionはこちら使っています。
pip list
Package            Version
------------------ ---------
install            1.3.4
openpyxl           3.0.10
packaging          21.0
pandas             1.4.3
Pillow             9.2.0
pip                22.2.1
PyAutoGUI          0.9.53
PyGetWindow        0.0.9
PyMsgBox           1.0.9
pyparsing          2.4.7
pyperclip          1.8.2
PyRect             0.1.4
PyScreeze          0.1.27
python-dateutil    2.8.2
python-dotenv      0.20.0
PyTweening         1.0.3
pytz               2022.1
requests           2.26.0
selenium           3.141.0
webdriver-manager  3.8.2

value error i/o operation on closed file.を解消できる方法ありますでしょうか。
もし分かる方がいましたら、教えていただけると幸いです。
お手数ですが、よろしくお願い致します。
全体のコード
from cmath import exp
from email.mime import image
import pandas as pd
import time
from datetime import datetime as dt, date, timedelta
from dateutil.relativedelta import relativedelta
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys
from openpyxl import load_workbook
import requests
import openpyxl
from openpyxl.drawing.image import Image
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
import uuid

#エクセル
file_excel=r"C:\Users\test\Desktop\JAN1.xlsx"

#画像挿入するエクセルファイルを指定
wb = openpyxl.load_workbook(file_excel)
ws = wb["Sheet1"]

#1行ずつ読み込み
#2行目からループを行う
for i in range(2,ws.max_row+1):
 
 options = Options()
 options.add_argument('--headless') 
 options.add_argument('--no-sandbox')
 options.add_argument('--disable-gpu')
     
 driver = webdriver.Chrome(executable_path=ChromeDriverManager().install())

 #JAN_CODE a列を読み込む
 JAN_CODE = ws['a'+str(i)].value

 #画像 b列を読み込む
 image_excdel = ws['b'+str(i)].value
 
 #url指定
 #url = "https://www.google.com/search?q="+row.JAN_CODE
 url="https://shoply.co.jp/"
 #url="https://shoply.co.jp/"+str(JAN_CODE)+"の価格と最安値"
 print(url)
 
 #検索サイトを開く
 driver.get(url)
 
 #2秒待機
 time.sleep(2)

 #商品名検索
 shyohinmai_kensaku=driver.find_element_by_xpath('//*[@id="js-tp-sbar"]/div[2]/div/div/div[2]/input').send_keys(str(JAN_CODE))

 time.sleep(2)

 kensaku_button=driver.find_element_by_xpath('//*[@id="js-tp-sbar"]/div[2]/div/div/div[3]').click()

 time.sleep(5)

 try:
   #画像取得
   gazou=driver.find_element_by_xpath('//*[@id="result-list"]/ul/li[1]/div/a/div[3]/img')
   print(gazou)
   
   img_url = gazou.get_attribute('src')

   #unique作成
   unique=str(uuid.uuid4())[-6:]
   
   #画像保存
   file_image = r"C:\Users\test\Desktop\Image\Image"+unique+".jpg"

   response = requests.get(img_url)
   image = response.content

   with open(file_image, "wb") as aaa:
     aaa.write(image)

   #挿入する画像を指定
   img = Image(file_image)
   
   img.width = 100
   img.height = 100
   
   #画像挿入
   ws.add_image(img, 'b'+str(i))
   
   #商品名取得
   shyohinmai=driver.find_element_by_xpath('//*[@id="result-list"]/ul/li[1]/div/a/div[4]/span[2]').text
   print(shyohinmai)
   
   #Excelへ書き込み
   ws['c'+str(i)].value = shyohinmai
   
   #価格取得
   kakaku=driver.find_element_by_xpath('//*[@id="result-list"]/ul/li[1]/div/a/div[5]/span').text
   print(kakaku)
   
   #Excelへ書き込み
   ws['d'+str(i)].value = kakaku
  
   #xlsx書き出し
   wb.save(file_excel)
   
   driver.close()
 
 except NoSuchElementException:
   driver.close()


エラーメッセージのコールスタック的に、ネットから取得したイメージをローカルに書き込んだ結果を更に読み込もうとしてファイルポインタを先頭に移動しようとしてエラーになっている感じですね。該当のファイル名やその状態を確認してみてはどうでしょう？ あるいは1項目のデータが揃うごとにExcelファイルに書いていますが、一時的にそれをやめてループ処理がすべて終わってからwb.save(file_excel)するというのを試してみてはどうでしょう？

ありがとうございます。ループの処理が終わったらwb.save(file_excel)を入れましたら今のところ問題なく処理されいています。
ただ途中エラーされましたら、ループの処理の中でも保存できるようにしたいです。

こんな記事 Adding image fails if any operations done after loading and before add があって、wb.save(file_excel)の前にimg.thumbnail((20,20))とかを実行してみると何とかなるかもしれません。試してみてください。

ありがとうございます。img.thumbnailの方法で試してみます。
