巧用Python:批量“扫码”
2025-05-26 04:08:31
这一讲我们来看看如何通过Python程序进行批量“扫码”。
改变方案
尝试用摄像头“扫码”时遇到挫折后,我决定采用扫描图片文件的方式获得书籍的条形码,之前的准备工作就是将每本书的ISBN码拍照,这时我才注意到有些上了年纪的书根本没有ISBN码,这样的书将来只能人工录入了。
获得文件夹中的所有文件名
批量扫码时,首先要先将这些包含条形码信息的图片存在同一个文件夹中,方便起见,在实现时我将这个文件夹BarImages放在了和python源码同级的目录。
在对文件系统进行操作时,我们一般会用到os库,所以要先引入:
import os
在程序中,对文件夹中的文件进行处理之前,要先判断这个文件夹是否存在,并且还要判断文件夹中是否有文件。
if not os.path.exists('BarImages'):
print('There are no image folder')
else:
= os.listdir('BarImages')
imageslist if len(imageslist)>0:
print(str(len(imageslist)))
else:
print('There are no images')
这里首先判断BarImages是否存在,如果不存在,打印提示,如果存在,则调用os里的listdir方法,得到对应文件夹里的文件名称列表imageslist。需要注意一点的是,如果文件夹中包含了非图片格式的文件时,可能会报错,我在macOS系统上在文件夹里做了删除文件的操作后会出现一个隐藏文件,如果遇到这种情况,可以用条件语句判断一下来跳过这种特殊情况。
在视频教程中,当判断imageslist的长度大于0时就可以开始遍历文件夹中的每一项来进行解码了:
if not os.path.exists('BarImages'):
print('There are no image folder')
else:
= os.listdir('BarImages')
imageslist if len(imageslist)>0:
print(str(len(imageslist)))
for image in imageslist:
= decode(Image.open(f'BarImages/{image}'))
readData #print(str(readData))
= False
flag for idata in readData:
if len(idata.data.decode('utf-8'))==13:
= True
flag = idata.data.decode('utf-8')
isbn if isbn not in scannedISBNList:
scannedISBNList.append(isbn) else:
print(f'The ISBN {isbn} is existed!')
if not flag:
print(f'Failed:{image}')
failedlist.append(image) print(f'Scanned ISBN:{str(scannedISBNList)} \
length:{len(scannedISBNList)}')
print(f'Failed Images:{str(failedlist)} \
length:{len(failedlist)}')
else:
print('There are no images')
这里外部的for循环负责遍历图片名称列表imageslist中的每一项,组合出图片所在路径后打开对应文件,并解码得出readData值。
由于readData也是一个列表,所以还要遍历这个列表中的每一项idata,这个临时变量保存的是一个已命名tuple类型的数据,包含着data、type、rect、 polygon属性,这里我们只需要取data属性的值,用点“.”操作符来获取,由于取到的值是字节型数据,还需要对它解码为utf-8编码类型的字符串。
取得代表ISBN的字符串之后,就可以将其加入到存放已经获得的ISBN列表scannedISBNList之中。这里用了一个布尔类型的标记来记录是否成功取到了ISBN值,在一幅图扫码结束后来通过这个标记的值来判断,如果没有成功取到,将该图片的名称加入存放失败图片的列表failedlist。
存储数据至json文件
得到了包含有ISBN的列表scannedISBNList之后,如果不将其保存至文件,程序结束后这些数据也将灰飞烟灭,因此这里用到了json库来协助将这些数据保存至json文件:
import json
最初的程序,在开始时scannedISBNList是空的列表,假设我们已经有了存放已有ISBN的json文件ScannedISBNList.json,我们在程序开头时就要将这个文件里的内容变成Python程序中的数据格式,传递给scannedISBNList列表,以免同一本书被多次记录:
if os.path.exists('ScannedISBNList.json'):
with open('ScannedISBNList.json') as f:
= json.loads(f.read())
scannedISBNList print(f'The list from json file:{str(scannedISBNList)} \
length:{str(len(scannedISBNList))}')
json库中的loads方法将从文件ScannedISBNList.json中读到的内容转为了Python程序可识别的数据格式。接下来会看到,保存scannedISBNList中的数据到json文件时,保存的是列表格式,所以在程序开头的这段接收json文件中数据的代码,也是用列表变量来接收的。
在文件夹中的文件都被遍历解码之后,就可以将含有ISBN码的列表导入到json文件中了:
with open('ScannedISBNList.json','w') as fout:
json.dump(scannedISBNList, fout)
这里用json的dump方法,将scannedISBNList中的数据写入了文件对象fout对应的json文件ScannedISBNList.json。
**** 未来扩展
成功存储到这些ISBN码只是图书管理系统的第一步,这些ISBN码在将来可以作为搜索的关键字来从网上获得对应书籍的信息,进一步完善图书信息,批量获得这些信息可以考虑用爬虫抓取,或者找到一些网站提供的api接口来获得包含有图书详细信息的json数据,再从中挑取需要的信息。
本节课完整代码
from pyzbar.pyzbar import decode
from PIL import Image
import os
import json
= []
imageslist = []
scannedISBNList = []
failedlist
if os.path.exists('ScannedISBNList.json'):
with open('ScannedISBNList.json') as f:
= json.loads(f.read())
scannedISBNList print(f'The list from json file:{str(scannedISBNList)} \
length:{str(len(scannedISBNList))}')
if not os.path.exists('BarImages'):
print('There are no image folder')
else:
= os.listdir('BarImages')
imageslist if len(imageslist)>0:
print(str(len(imageslist)))
for image in imageslist:
= decode(Image.open(f'BarImages/{image}'))
readData #print(str(readData))
= False
flag for idata in readData:
if len(idata.data.decode('utf-8'))==13:
= True
flag = idata.data.decode('utf-8')
isbn if isbn not in scannedISBNList:
scannedISBNList.append(isbn)else:
print(f'The ISBN {isbn} is existed!')
if not flag:
print(f'Failed:{image}')
failedlist.append(image) print(f'Scanned ISBN:{str(scannedISBNList)} \
length:{len(scannedISBNList)}')
print(f'Failed Images:{str(failedlist)} \
length:{len(failedlist)}')
else:
print('There are no images')
with open('ScannedISBNList.json','w') as fout:
json.dump(scannedISBNList, fout)
#readData = decode(Image.open('bar8.png'))
#print(readData[0].data.decode('utf-8'))