对图片我们能做些什么?
这次熟悉了两个很重要的关于图片处理的库:PIL,三个关于二维码的库:qrcode、qrcode-terminal、lilith、qrtools和pyqrcode。
PIL全称Python Imaging Library,可以为Python解释器添加图片处理能力。它和它包含的模块一起几乎可以实现所有你想要对图片的操作。
这里举个例子,例子的来源为:https://zhuanlan.zhihu.com/p/34658133。作用是将一张图片处理成九等份,方便发朋友圈LOL。
image = Image.open('pencil.jpg')
# (1)将图片补充为正方形,变成以长边为准
width, height = image.size
edge = max(width, height)
# 因为图片之后会被分为9份,这里保证边长是3的倍数
if edge % 3 != 0:
edge = edge + 3 - edge%3
new_image = Image.new(image.mode, (edge, edge), color='white')
if width < height:
new_image.paste(image, ((edge-width)//2, 0))
else:
new_image.paste(image, (0, (edge-height)//2))
# (2)将图片切割成3x3份
n = edge / 3
boxes = []
# 分割,数学问题
for i in range(3):
for j in range(3):
boxes.append((i*n, j*n, (i+1)*n, (j+1)*n,))
subimages = [image.crop(box) for box in boxes]
# (3)保存分割后的图片
idxs = [1,4,7,2,5,8,3,6,9]
for subimage, idx in zip(subimages, idxs):
subimage.save("{0:s}-{1:d}.{2:s}".format(image.filename.split('.')[0], idx, image.format))
二维码
做爬虫不可避免的会遇到二维码,二维码的原理这里就不说了。个库分别对应三种不同的功能,几乎可以满足关于二维码的所有要求。
- qrcode和pyqrcode,包含几乎关于二维码的常用操作,多用于创建。
- qrcode-terminal和lilith,可以将一个字符串转换为二维码并在终端上打印出来,这个库用到了qrcode的部分功能。pyqrcode也支持二维码打印到终端,但是对象是Linux的终端。
- qrtools,解析一个二维码图片的内容
qrcode
生成一个内容为ipa
的img
二维码对象,并保存为qrcode.jpg
。这个img
也可以作为qrcode-terminal
库的参数,解析之后可以在终端上打印一个二维码。
import qrcode
ipa="https://journal.ethanshub.com/"
qr = qrcode.QRCode(
version = 2,
error_correction = qrcode.constants.ERROR_CORRECT_L,
box_size = 10,
border = 1,
)
qr.add_data(ipa)
qr.make(fit=True)
img = qr.make_image( fill_color="black", back_color="white")
img.save('qrcode.jpg')
qrcode2terminal - windows
但是做爬虫,接触最多的其实是扫描二维码这个操作,之前模拟淘宝登陆的时候,我是将二维码保存到本地再手动扫描,这里我准备把二维码图片解析并打印到终端上,这样就可以直接扫描了。
另外,目前看的几个在终端打印二维码的都是针对Linux终端的,我这个例子可以在windows cmd里使用,亲测有效。
qrcode-terminal
中,关于打印部分是这样的:
def qr_terminal_str(str,version=1):
qr = qrcode.QRCode(version)
qr.add_data(str)
qr.make()
output = white_block*(qr.modules_count+2) + new_line
for mn in qr.modules:
output += white_block
for m in mn:
if m:
output += black_block
else:
output += white_block
output += white_block + new_line
output += white_block*(qr.modules_count+2) + new_line
return output
因为它所使用的qr图示由qrcode
库生成的,因此它可以直接访问modules_count
获取每一行有多少个方块(包括黑色的和白色的),但是现在我面临的情况是从图片中读取二维码,如果采用PIL
打开一张图片,那么可以使用getpixel
方法获取图片的某个点的像素值,因为是二维码,所以这个值只能是(0,0,0)或(255,255,255),非黑即白。
如果采取遍历所有像素点的方法,遇到白的打印一个white_block
,黑的打印一个black_block
,这样是可行的,但是打印出来的二维码会非常大,一般屏幕是显示不出来的。解决这个问题的核心要素是如何获取每行的方块数。
如图,现在有一张二维码图片,我用一条直线从左往右逐个像素扫描。每右移一个像素,就会从上往下获取每个像素的值,因为是黑白的,所以这个值只能是1或者0,将这些值累加起来,这样每扫一行就会得到一个类似于10101010101010100110010000
的字符串。继续往右扫,每次都会得到一个字符串,将这个字符串和上一个字符串比较,如果相同,说明还没有到移动满一个方块;如果不同,那么横向的位移就是方块的像素大小,用图片的宽度除以方块的大小就可以获得方块的数量了。代码如下:
# 打开图片
img = Image.open('qrcode.jpg')
text = ''
sample = ''
cnt = 0
# 开始扫描
for w in range(img.width):
tmp = ''
for h in range(img.height):
res = img.getpixel((w, h))
if res:
tmp += '1'
else:
tmp += '0'
if sample == '':
sample = tmp
if sample == tmp:
cnt += 1
else:
break
# 得到方块大小和每一行的方块数量
cell_size = cnt
cell_num = img.width//cnt
# 打印到终端
# 注意这里会给原先的二维码包裹一个边框,看起来舒服点
# 取像素点的时候取的是每个方块的中心
white_block = '▇'
black_block = ' '
new_line = '\n'
text += white_block*(cell_num+2) + new_line
for w in range(cell_num):
text += white_block
for h in range(cell_num):
res = img.getpixel((w*cell_size+cell_size/2, h*cell_size+cell_size/2,))
text += white_block if res == 0 else black_block
text += white_block + new_line
text += white_block*(cell_num+2) + new_line
print (text)
打出来的效果是这样的,我试了下用iphone的相机可以识别:
qrcode-res.jpgqrtools
qrtools依赖于一个叫zbar的外部库,这个库不能直接用pip安装,官方据说只支持到Python 2.7。windows上我没成功,好在解析二维码
这个功能其实需求不大,所以就暂且放一边了。
from qrtools.qrtools import QR
qr = qrtools.QR()
qr.decode("qrcode.jpg")
print(qr.data)
网友评论