目标
下载收集中国全国范围内各大高校的校徽,并批量制作比赛名牌。
背景
我们学校承办了ICPC济南站,给我分配的任务是给每家学校做一个类似于下图的带校徽的海报。
其中中间的校徽要替换成别的学校的。参赛名单上有两三百个学校,挨个手工下载校徽再手工合成不如直接找印务公司。所以开始思考这个任务可以分解成两步:
- 根据队伍名单批量收集所需大学的校徽
- 将校徽批量嵌入到海报中去
批量收集校徽
第一想法是找找有没有现成的API,搜了一圈后无果。
第二想法是找个有资源的网站批量爬取。又想到很多学校举办大型竞赛的时候都应该遇到这个问题,应该有与我同样想法的程序员干过同样的事儿。遂直接到github上搜索。运气很好的看到了下面这个项目:
dashjay/UniversityBadge: 中国大部分大学校徽,来自百度百科
不过拿这个项目直接爬下来的校徽太小了,我稍微改了改代码让下载下来的校徽变得高清了一点
# -*- coding: UTF-8 -*-
import os
import json
import requests
import re
from bs4 import BeautifulSoup
from urllib import request
# ---------------获取大学信息,将对应大学url储存在Urllist中-----------------------------------
Urllist = []
f = open("university_name.csv", "r")
line = f.readline()
while line:
Urllist.append("https://baike.baidu.com/item/"+line.strip())
line = f.readline()
# ---------------------------------------------------------------------------------------
# ---------------------Badge Spider------------------------------------------------------
# 无法直接请求的url = 41
heads = [{'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},
{'User-Agent': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}]
UCurl = []
# img格式选择函数
def getImgUrl(a=[], b=[]):
if(a == []):
return b
else:
return a
folder = os.path.exists("Badges")
if not folder:
os.makedirs("Badges")
for url in Urllist:
num = 0
response = requests.get(url, allow_redirects=False,
headers=heads[num % len(heads)])
# 判断请求的 url 是否有效
if response.status_code == 200:
response.encoding = ('utf-8') # 将请求到的页面转码
html = response.text # 请求的 url 的 html 代码
soup = BeautifulSoup(html, 'html.parser') # 用html.parser对网页解析
img2 = soup.select(
'body > div.body-wrapper.feature.feature_small.collegeSmall > div.feature_poster > div > div.poster-right > div > a > img')
# 选择校徽图片的位置,得到校徽块相关信息
img1 = soup.select(
'body > div.body-wrapper > div.content-wrapper > div > div.side-content > div.summary-pic > a > img')
# 由于百度百科的 badge 图片的html格式有所不同,但基本为这两个格式,所以添加两个img格式
img = getImgUrl(img1, img2)
if img == []:
with open('unfinishedURL.txt', 'a') as fo:
fo.writelines(url)
fo.writelines('\n')
continue
img_url = img[0].get_attribute_list('src')[0] # 获取校徽图片地址
img_url = re.match('https[\S]+process=image', img_url).group() # 去除修饰后缀,获取原始清晰度图片
if img_url == None:
# 理应永远执行不到这里
print('error : ' + url)
exit()
# 将获得的校徽图片保存本地
pic = requests.get(img_url)
path = 'Badges/'+url[29:]+'.jpg'
with open(path, 'wb') as fp:
fp.write(pic.content)
# url 地址请求失败时,将失败的URL存入 unfinishedURL 文本中
else:
with open('unfinishedURL.txt', 'a') as fo:
fo.writelines(url)
fo.writelines('\n')
num = num + 1
print(url)
print("OK!Well Done!")
下载下来的校徽还不能直接用,大概有5%的会有百度百科的水印。因为个数少,人工挨个改改就行。还有极少数图片带有非白色的边框,也得挨个改改。
批量合成图片
我拿到的图片是这样的空白图。主要思路就行把别的校徽按比例缩放到和右侧校徽同等高度后,居中放置。不按宽度缩放是因为部分学校的校徽是长方形的。
这部分工作主要借助PIL库实现,代码很简单。
import csv
from PIL import Image
with open('university_name.csv') as f:
reader = csv.reader(f)
for row in reader:
base_img = Image.open('blank.jpg')
tmp_img = Image.open('Badges\\' + str(row[0]) + '.jpg')
tmp_img = tmp_img.convert("RGB")
region = tmp_img
# 标准情况下中间校徽的尺寸
tbox = (1395,525, 2110,1245)
# 计算缩放后的宽高
height = tbox[3] - tbox[1]
width = tmp_img.width*(height/tmp_img.height)
mid = (tbox[0]+tbox[2])/2 # 中轴线
box = (int(mid - width/2) , tbox[1], int(mid + width/2) , int(tbox[1]+height) )
region = region.resize((box[2] - box[0], box[3] - box[1]))
base_img.paste(region, box)
base_img.save('out\\' + str(row[0]) + '.jpg')
print(str(row[0]))
后记
比较悲催的是打印店告知我做的图太小了,作为1米多的海报打出来太糊了。所以我把标题从批量制作海报改成了批量制作队牌了。
再见,我去学怎样用PS了。