2021-08-19 利用爬虫制作每日一图

本文介绍了如何使用Python爬虫从北京天文馆网站抓取每日更新的天文图片和相关文字,然后进行图片处理和文字排版,最终合成每日一图。主要涉及了requests、lxml和PIL库的使用,包括XPath路径选择、图片缩放、文字提取和图片合并等技术。
摘要由CSDN通过智能技术生成

 前几天学会了一点爬虫,我就想利用它做一个每日一图,经过自己的努力做出来了。

步骤也不是很多,让我们一起来看看吧!

主要分为3个大步

1.利用爬虫把网页每天更新的文章里的图片和文字提取出来

2.把图片缩小后放在模板的合适位置

3.把文字分排后放在图片下方进行解释

代码所需要的的第三方库

#coding:utf-8
import requests
from lxml import etree
from PIL import Image
from PIL import ImageFilter
from PIL import ImageEnhance
from PIL import ImageDraw, ImageFont

一.利用爬虫

1.我爬的网站是北京天文馆http://www.bjp.org.cn/mryt/index.shtml,它的首页页全是文章的链接

我们先把每天更新的文章的链接(就是第一个链接)提取出来

代码如下

#coding:utf-8
import requests
from lxml import etree
from PIL import Image
from PIL import ImageFilter
from PIL import ImageEnhance
from PIL import ImageDraw, ImageFont



class Char(object):

    def __init__(self):
        self.url = ("http://www.bjp.org.cn/mryt/index.shtml")

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'
        }

    def get_data(self,url):
        response = requests.get(url,headers=self.headers)
        #测试
        '''with open("2.html", "wb")as f:
            f.write(response.content)'''
        return response.content


    def parse_data(self,data):
        #创建element对象
        data = data.decode().replace("<!--","").replace("-->","")

        html = etree.HTML(data)

        el_list = html.xpath('/html/body/table[3]/tbody/tr/td/b[1]/a')

        temp = {}
        for el in el_list:

            temp['link'] = 'http://www.bjp.org.cn/'+el.xpath("./@href")[0]

            print(temp['link'])
        return temp['link']

    def run(self):
        data = self.get_data(self.url)
        self.parse_data(data)

if __name__ == '__main__':
    char = Char()
    char.run()

 运行后结果就是文章的链接http://www.bjp.org.cn//mryt/4028c1367b55b353017b570cd7840002.shtml

其中难点在于xpath的路径

只需右键点检查,点击元素选择器,选择文字“围绕着环状星云的环”,右边就会出现加深的代码,

再右键复制xpath,再用此办法对其他同级的文字就会发现为/html/body/table[3]/tbody/tr/td/b[1]/a

其中只有b[]中间的数字在变化,但我们是每日一图,就为1,也可以改下数字获取其他天的

2.提取文章中的说明文字

将上一个代码def run()删去加入以下代码

    def get_str(self,url2):
        #data2
        response = requests.get(url2, headers=self.headers)
        #测试
        '''with open("4.html", "wb")as f:
            f.write(response.content)'''
        data2 = self.get_data(url2)

        # 创建element对象
        data = data2.decode().replace("<!--", "").replace("-->", "").replace(",即可听声音。"," ").replace("点击本链接:","")
        #print(data)
        html = etree.HTML(data)
        # 获取文字
        el_list = html.xpath('//p[contains(@style,"text-align: justify; text-indent")]')
        for el in el_list:
            temp = {}
            temp['text'] = el.xpath('./text()')[0]
            return temp['text']

    def run(self):
        data = self.get_data(self.url)
        new_url=self.parse_data(data)
        str = self.get_str(new_url)
        print(str)

代码中的xpath用的是contains(包含)通过属性style找有"text-align: justify; text-indent"

在用./text()提取文字,因为htmi.xpath提取的为列表,所以用循环提取每一个元素

3.提取文章中的图片

将上一个代码def run()删去加入以下代码

    def get_picture(self,url2):
        # data2
        response = requests.get(url2, headers=self.headers)
        # 测试
        '''with open("4.html", "wb")as f:
            f.write(response.content)'''
        data2 = self.get_data(url2)

        # 创建element对象
        data = data2.decode().replace("<!--", "").replace("-->", "").replace(",即可听声音。", " ").replace("点击本链接:", "")
        # print(data)
        html = etree.HTML(data)
        el_list2 = html.xpath('//span/img')

        for el2 in el_list2:
            temp3 = {}
            temp3['ad'] = el2.xpath("./@src")[0]
            new_ad = 'http://www.bjp.org.cn' + temp3['ad']
            print(new_ad)
            pic = requests.get(new_ad).content
            path = 'D:/send/' + '1.jpg'#写保存在代码同级的目录下的地址
            with open(path, 'wb') as f:
                f.write(pic)


    def run(self):
        data = self.get_data(self.url)
        new_url=self.parse_data(data)
        str = self.get_str(new_url)
        print(str)
        self.get_picture(new_url)

运行后会出现1.jpg,其实提取图片和文字可以合并在一个函数中,我为了方便大家理解就分开了

二.放入图片

首先要直接设置一个每日一图的背景模板,我们的模板是,并把它改名成‘mb.jpg’,放在代码的同级目录下:

 合并图片的代码为,将上一个代码def run()删去加入以下代码

    def merge_image(self):
        im = Image.open("1.jpg")  #文件存在的路径,如果没有路径就是当前目录下文件
        #print(im.format, im.size, im.mode)
        im.thumbnail((700, 700)) #按比例缩小
        im.save("1.jpg")
        im2 = Image.open("mb.jpg")
        im = Image.open("1.jpg")
        #print(im.size[0])
        #print(im.size[1])
        if im.size[0] < 700:  # 判断宽
            wide = int((700 - im.size[0]) / 2)
            im2.paste(im, (100 + wide, 400))
        elif im.size[1] < 700:#判断高
            high = int((700 - im.size[1]) / 2)
            im2.paste(im, (100, 400 + high))
        else:
            im2.paste(im, (100, 400))#这个初始位置要自己找
            im2.save("mb1.jpg")
        print(im.format, im.size, im.mode)

    def run(self):
        data = self.get_data(self.url)
        new_url=self.parse_data(data)
        str = self.get_str(new_url)
        print(str)
        self.get_picture(new_url)
        self.merge_image()

中间我用了判断语句,因为有些照片等比例缩小后,宽和高小于700,就将它上下移动差距的一半,做出来的效果才美观

三.放入图片

    def merge_text(self,str):
        im = Image.open('mb1.jpg')
        draw = ImageDraw.Draw(im)
        fnt = ImageFont.truetype(r'C:\Windows\Fonts\STXINGKA.TTF', 40)#设置字体,这是电脑自带的字体
        w0 = 110
        h0 = 1100
        #print(len(str))
        num = len(str)
        # 第一排要空2格
        str1 = str[0:19]
        draw.text((w0, h0), str1, fill='blACK', font=fnt)
        a = 19
        '''其余就一直取21个字出来,写入后,把位置向下移,直到写完'''
        while a < num:
            h0 += 45
            str2 = str[a:a + 21]
            draw.text((w0 - 70, h0), str2, fill='blACK', font=fnt)
            print(str2)
            a += 21
        im.save("mb1.jpg")

字体可以去自己的电脑C:\Windows\Fonts\下去找

完整代码如下

#coding:utf-8
import requests
from lxml import etree
from PIL import Image
from PIL import ImageFilter
from PIL import ImageEnhance
from PIL import ImageDraw, ImageFont



class Char(object):

    def __init__(self):
        self.url = ("http://www.bjp.org.cn/mryt/index.shtml")

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'
        }

    def get_data(self,url):
        response = requests.get(url,headers=self.headers)
        #测试
        '''with open("2.html", "wb")as f:
            f.write(response.content)'''
        return response.content


    def parse_data(self,data):
        #创建element对象
        data = data.decode().replace("<!--","").replace("-->","")

        html = etree.HTML(data)

        el_list = html.xpath('/html/body/table[3]/tbody/tr/td/b[1]/a')

        temp = {}
        for el in el_list:

            temp['link'] = 'http://www.bjp.org.cn/'+el.xpath("./@href")[0]

            #print(temp['link'])
        return temp['link']

    def get_str(self,url2):
        #data2
        response = requests.get(url2, headers=self.headers)
        #测试
        '''with open("4.html", "wb")as f:
            f.write(response.content)'''
        data2 = self.get_data(url2)

        # 创建element对象
        data = data2.decode().replace("<!--", "").replace("-->", "").replace(",即可听声音。"," ").replace("点击本链接:","")
        #print(data)
        html = etree.HTML(data)
        # 获取文字
        el_list = html.xpath('//p[contains(@style,"text-align: justify; text-indent")]')
        for el in el_list:
            temp = {}
            temp['text'] = el.xpath('./text()')[0]
            return temp['text']

    def get_picture(self,url2):
        # data2
        response = requests.get(url2, headers=self.headers)
        # 测试
        '''with open("4.html", "wb")as f:
            f.write(response.content)'''
        data2 = self.get_data(url2)

        # 创建element对象
        data = data2.decode().replace("<!--", "").replace("-->", "").replace(",即可听声音。", " ").replace("点击本链接:", "")
        # print(data)
        html = etree.HTML(data)
        el_list2 = html.xpath('//span/img')

        for el2 in el_list2:
            temp3 = {}
            temp3['ad'] = el2.xpath("./@src")[0]
            new_ad = 'http://www.bjp.org.cn' + temp3['ad']
            print(new_ad)
            pic = requests.get(new_ad).content
            path = 'D:/send/' + '1.jpg'#写保存在代码同级的目录下的地址
            with open(path, 'wb') as f:
                f.write(pic)

    def merge_image(self):
        im = Image.open("1.jpg")  #文件存在的路径,如果没有路径就是当前目录下文件
        #print(im.format, im.size, im.mode)
        im.thumbnail((700, 700)) #按比例缩小
        im.save("1.jpg")
        im2 = Image.open("mb.jpg")
        im = Image.open("1.jpg")
        #print(im.size[0])
        #print(im.size[1])
        if im.size[0] < 700:  # 判断宽
            wide = int((700 - im.size[0]) / 2)
            im2.paste(im, (100 + wide, 400))
        elif im.size[1] < 700:#判断高
            high = int((700 - im.size[1]) / 2)
            im2.paste(im, (100, 400 + high))
        else:
            im2.paste(im, (100, 400))#这个初始位置要自己找
            im2.save("mb1.jpg")
        #print(im.format, im.size, im.mode)



    def merge_text(self,str):
        im = Image.open('mb1.jpg')
        draw = ImageDraw.Draw(im)
        fnt = ImageFont.truetype(r'C:\Windows\Fonts\STXINGKA.TTF', 40)#设置字体,这是电脑自带的字体
        w0 = 110
        h0 = 1100
        #print(len(str))
        num = len(str)
        # 第一排要空2格
        str1 = str[0:19]
        draw.text((w0, h0), str1, fill='blACK', font=fnt)
        a = 19
        '''其余就一直取21个字出来,写入后,把位置向下移,直到写完'''
        while a < num:
            h0 += 45
            str2 = str[a:a + 21]
            draw.text((w0 - 70, h0), str2, fill='blACK', font=fnt)
            print(str2)
            a += 21
        im.save("mb1.jpg")

    def run(self):
        data = self.get_data(self.url)
        new_url=self.parse_data(data)
        str = self.get_str(new_url)
        print(str)
        self.get_picture(new_url)
        self.merge_image()
        self.merge_text(str)


if __name__ == '__main__':
    char = Char()
    char.run()

不知道你学会没,快去操练起来!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值