我们分享博客的方式有很多种,最常见的无非就是分享链接。或者是编辑一条消息,写上标题链接等东西。但是这种方式都不够直观,相比之下图片的方式要更引人注目。CSDN移动端提供了分享图的功能,但是展示的内容是固定的,所以我就想到用Python自己生成分享图。本文只是技术分享,所以在效果上没有下太多功夫,生成的图片比官方是要丑得多,还需包含。
我们要生成博客分析图,就需要先获得一些信息,像是作者的名字,头像,文章的摘要等。这就需要使用到爬虫了,先选取本人的一篇博客:学会这些Python美图技巧,就等着女朋友夸你吧,我们在浏览器打开,右击检查就可以看到下图:
在左上角的框我们可以看到作者的头像和名字,那就是我们需要的内容。我们先点击右边红框,然后在网页中点击我们需要的内容,比如ZackSock
,这样浏览器在源码部分会自动定位到该标签:
我们可以看到该标签是一个span
,而且class设置为name,这个时候我们就可以用BeautifulSoup解析,安装语句如下:
pip install BeautifulSoup4
然后进行爬取:
import requests
from bs4 import BeautifulSoup
# 要生成分享图的博客地址
url = 'https://blog.csdn.net/ZackSock/article/details/105833676'
# 浏览器头信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
# 发送请求,获取网页源码
response = requests.get(self.url, headers=headers)
# 获取BeautifulSoup对象
bs = BeautifulSoup(response.text, 'html.parser')
# 找到源码中class为name的span标签
name = bs.find('span', {'class':'name'})
# 获取标签里面的文字
name = name.text.strip()
这样我们就将博主的名字爬了出来。通过这个方法我们还可以爬取头像,但是摘要就不知道怎么爬了。进行我的不专业分析,发现文章的主体都在一个id
为content_views
的div
中,如果文章格式比较规范的话,第一段非标题文字就在div
中第一个非空p
标签中。于是我们就可以用下面代码分析出摘要:
import requests
from bs4 import BeautifulSoup
# 要生成分享图的博客地址
url = 'https://blog.csdn.net/ZackSock/article/details/105833676'
# 浏览器头信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
# 发送请求,获取网页源码
response = requests.get(self.url, headers=headers)
# 获取BeautifulSoup对象
bs = BeautifulSoup(response.text, 'html.parser')
# 获取正文的html
content = bs.find('div', {'id':'content_views'})
# 获取正文中的p
p_s = content.find_all('p')
# 将正文第一个非空p输出
for p in p_s:
if p.text != '':
print(p.text)
爬取头像的算法也非常简单,代码如下:
import requests
from bs4 import BeautifulSoup
# 要生成分享图的博客地址
url = 'https://blog.csdn.net/ZackSock/article/details/105833676'
# 浏览器头信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
# 发送请求,获取网页源码
response = requests.get(self.url, headers=headers)
# 获取BeautifulSoup对象
bs = BeautifulSoup(response.text, 'html.parser')
# 找到显示头像的img标签
head_img = bs.find('img', {'class': 'avatar_pic'})
with open('head.jpg', 'wb') as f:
# 保存图片
f.write(requests.get(head_img['src']).content)
但是我们爬到的图片是正方形的,我们需要进行一个处理。
首先我们需要生成一个圆形的头像,这就需要用到Pillow模块,安装如下:
pip install pillow
具体代码如下:
from PIL import ImageDraw
from PIL import Image
# 读取头像图片
im = Image.open('head.jpg').convert('RGBA')
# 创建一个和头像大小一样的图片
bg = Image.new('RGBA', im.size, (230, 230, 230, 255))
# 在创建的图片上抠一个透明圆形
drawer = ImageDraw.Draw(bg)
drawer.ellipse((0, 0, bg.size[0], bg.size[0]), fill=(0, 0, 0, 0), width=3)
r, g, b, a = bg.split()
# 将头像和创建的头像合并,就合成了一个圆形图片
im.paste(bg, (0, 0), mask=a)
# 保存
im.convert('RGB').save('head.jpg')
另外,我们需要用一个二维码让别人可以跳转到我们的博客,这需要用到qrcode模块:
pip install qrcode
生成二维码的代码如下,我们需要在add_data方法中传入博客地址:
import qrcode
qr = qrcode.QRCode(
version=5, # 二维码的大小,取值1-40
box_size=10, # 二维码最小正方形的像素数量
error_correction=qrcode.constants.ERROR_CORRECT_H, # 二维码的纠错等级
border=1 # 白色边框的大小
)
qr.add_data('博客地址') # 设置二维码数据
img = qr.make_image() # 创建二维码图片
img.save('qrcode.png')
对qrcode模块有兴趣的读者可以观看: https://blog.csdn.net/ZackSock/article/details/105222763 。
上面我们把准备工作做完了,可以开始我们的整合了。大家前期可以获取一些自己需要的信息然后按照自己的布局整合,这里我就是按照从上到下依次头像、名称、摘要、二维码的排序:
import re
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
bg_im = Image.new('RGB', (350, 600), (230, 230, 230))
# 放置头像
head_im = Image.open('head.jpg')
bg_im.paste(head_im, (140, 70))
# 放置名字
drawer = ImageDraw.Draw(bg_im)
font = ImageFont.truetype('simsun.ttc', 14)
w, h = drawer.textsize(name)
drawer.text(((bg_im.size[0]-w)/2, 160), name, font=font, fill=(15, 15, 15))
# 放置摘要
st = re.findall(r'.{20}', abstract)
line = 0
for i in st:
w, h = drawer.textsize(i.encode('utf-8'))
drawer.text(((bg_im.size[0]-w)/2-20, 220+line*16), i, font=font, fill=(15, 15, 15))
line += 1
# 放置二维码
qrcode = Image.open('qrcode.png')
qrcode = qrcode.resize((100, 100))
bg_im.paste(qrcode, ((bg_im.size[0]-100)//2, 220+line*16+30))
# 保存
bg_im.save('results.jpg')
因为摘要比较长,所以我把摘要分成了数个长度为20的子串然后再写到图片上。
我们将上面的函数整合一个类,完整代码如下:
import re
import qrcode
import requests
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from bs4 import BeautifulSoup
class SharedGenerator():
def __init__(self, url):
self.size = (350, 600)
self.url = url
def get_bs(self):
# 浏览器头信息
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
# 发送请求
response = requests.get(self.url, headers=headers)
bs = BeautifulSoup(response.text, 'html.parser')
return bs
def get_img(self, bs):
head_img = bs.find('img', {'class': 'avatar_pic'})
with open('head.jpg', 'wb') as f:
f.write(requests.get(head_img['src']).content)
# 将头像转换成圆框
im = Image.open('head.jpg').convert('RGBA')
bg = Image.new('RGBA', im.size, (230, 230, 230, 255))
drawer = ImageDraw.Draw(bg)
drawer.ellipse((0, 0, bg.size[0], bg.size[0]), fill=(0, 0, 0, 0), width=3)
r, g, b, a = bg.split()
im.paste(bg, (0, 0), mask=a)
im.convert('RGB').save('head.jpg')
def get_name(self, bs):
name = bs.find('span', {'class':'name'})
return name.text.strip()
def get_abstract(self, bs):
# 获取正文的html
content = bs.find('div', {'id':'content_views'})
# 获取正文中的p
p_s = content.find_all('p')
# 将正文第一个非空p输出
for p in p_s:
if p.text != '':
return p.text
def get_qrcode(self):
qr = qrcode.QRCode(
version=5, # 二维码的大小,取值1-40
box_size=10, # 二维码最小正方形的像素数量
error_correction=qrcode.constants.ERROR_CORRECT_H, # 二维码的纠错等级
border=1 # 白色边框的大小
)
qr.add_data(self.url) # 设置二维码数据
img = qr.make_image() # 创建二维码图片
img.save('qrcode.png')
def generate(self, name, abstract):
bg_im = Image.new('RGB', self.size, (230, 230, 230))
# 放置头像
head_im = Image.open('head.jpg')
bg_im.paste(head_im, (140, 70))
# 放置名字
drawer = ImageDraw.Draw(bg_im)
font = ImageFont.truetype('simsun.ttc', 14)
w, h = drawer.textsize(name)
drawer.text(((bg_im.size[0]-w)/2, 160), name, font=font, fill=(15, 15, 15))
# 放置摘要
st = re.findall(r'.{20}', abstract)
line = 0
for i in st:
w, h = drawer.textsize(i.encode('utf-8'))
drawer.text(((bg_im.size[0]-w)/2-20, 220+line*16), i, font=font, fill=(15, 15, 15))
line += 1
qrcode = Image.open('qrcode.png')
qrcode = qrcode.resize((100, 100))
bg_im.paste(qrcode, ((bg_im.size[0]-100)//2, 220+line*16+30))
bg_im.save('results.jpg')
if __name__ == '__main__':
url = 'https://blog.csdn.net/ZackSock/article/details/105833676'
# 创建生成器对象
generator = SharedGenerator(url)
# 获取BeautifulSoup对象
bs = generator.get_bs()
# 下载并处理头像
generator.get_img(bs)
# 获取名字
name = generator.get_name(bs)
# 获取摘要
abstract = generator.get_abstract(bs)
# 生成二维码
generator.get_qrcode()
# 生成分享图
generator.generate(name, abstract)
上面就完整的实现了分享图的实现,下面是效果图:
我把原本的二维码替换成了图中的美女。我没有什么艺术细胞,大家可以发挥自己的想象定制一个更美观的分享图。