【Python】Selenium自动化测试之动态识别验证码图片方法(附静态图片文字获取)

目录

  

一、前提  返回目录

经常会遇到登录系统时候需要输入动态验证码的情况,但是自动化如何识别图片然后登陆系统

需要用到pytesseract识别验证码图片以及PIL图像处理方法

import pytesseract
from PIL import Image, ImageEnhance

二、获取验证码  返回目录

1、思路

  • 步骤①:定位图片的元素,并且截取当前浏览器的页面图片
  • 步骤②:获取验证码坐标点,以及验证码图片、浏览器、截图的长和宽
  • 步骤③:截取截图里的验证码图片,获得的验证码图片并保存
  • 步骤④:获得验证码code

2、实践方法

以下步骤都在getCodeImg方法里面:

    def getCodeImg(self):
        """获取验证码"""

1)步骤①

imgPath:浏览器截图图片路径

savePath:保存验证码图片路径

加了一个点击验证码图片方法,目的是为了后面重新获取验证码用的。

复制代码
        # 步骤①:
        basePath = Fun().upPath() + "/utils/img/"
        imgPath = basePath + "code.png"
        savePath = basePath + "saveCode.png"
        # 定位图片元素
        imgElement = self.webDriverWait(Loc.codeImg_loc)
        # 点击验证码图片
        imgElement.click()
        # 截取当前页面的图并放到目录里
        self.driver.save_screenshot(imgPath)
复制代码

2)步骤②

获取验证码坐标是为了下面计算验证码占据整个浏览器的百分比。

复制代码
        # 步骤②:
        # 获取验证码x,y轴,x&y代表左上角的坐标点
        imgLocation = imgElement.location
        print(f"图片坐标点:{imgLocation}")
        # 获取验证码长、宽
        imgSize = imgElement.size
        print(f"图片长、宽:{imgSize}")
        # 获取浏览器的长、宽
        windowSize = self.driver.get_window_size()
        print(f"浏览器长、宽:{windowSize}")
        # 打开截图
        openImg = Image.open(imgPath)
        # 获取保存截图的长、宽(宽:2700, 高:1950)
        screenImgSize = openImg.size
        print(f"保存截图的长、宽:{screenImgSize}")
复制代码

 

3)步骤③

计算图片四个边距在真实浏览器的百分比,用这个百分比乘以浏览器截图的长和宽,得出截图里面的验证码大概位置,然后再自己进行调整截图里的边距大小。

最后再把验证码图片进行图片处理,灰色度和增强对比度等等,提高获取验证码图片的识别率。

复制代码
        # 步骤③:截取截图的验证码图片
        # 图片左边距占据整个浏览器的百分比
        left = imgLocation['x']/windowSize['width']
        # 图片上边距占据整个浏览器的百分比
        top = imgLocation['y']/windowSize['height']
        # 图片右边距占据整个浏览器的百分比
        right = (imgLocation['x'] + imgSize['width'])/windowSize['width']
        # 图片下边距占据整个浏览器的百分比
        bottom = (imgLocation['y'] + imgSize['height'])/windowSize['height']

        # 需要截取的坐标
        screenLocation = (
            left * screenImgSize[0],
            top * screenImgSize[1]+150,
            right * screenImgSize[0],
            bottom * screenImgSize[1]+150
        )
        # 打开截图并截取区域并保存
        img = openImg.crop(screenLocation)
        img = img.convert('L')  # 转换模式:L | RGB

     # 提高识别率(见下面
        # enhancer = ImageEnhance.Color(img)
        # enhancer = enhancer.enhance(0)
        # enhancer = ImageEnhance.Brightness(enhancer)
        # enhancer = enhancer.enhance(2)
        # enhancer = ImageEnhance.Contrast(enhancer)      # 增强对比度
        # enhancer = enhancer.enhance(8)
        # enhancer = ImageEnhance.Sharpness(enhancer)
        # img = enhancer.enhance(20)


        img = ImageEnhance.Contrast(img)  # 增强对比度
        img = img.enhance(2.0)
        img.save(savePath)
复制代码

不过识别率还是比较低的,下面有种可以提高识别率的方法,但是见仁见智,实测有时很快有时很慢

参考文章:

pytesseract 识别率低提升方法

【python图像处理】图像的增强(ImageEnhance类详解)

4)步骤④

获取的验证码可能不是我们想要的,会出现中间有大小空格、换行情况,需要替换掉

复制代码
    def remove(self,string):
        """字符串去除空格或换行"""

        str = string.replace(" ", "")  #大空格
        str = str.replace("", "")     #小空格
        str = str.replace('\n', "")    #换行符
        return str


    def getCodeImg(self):
        """获取验证码"""

        # 步骤④:获得code验证码
        code = pytesseract.image_to_string(img).strip()
        print(f"提取的验证码为:【{self.remove(code)}】")
        return self.remove(code)
复制代码

三、获取4位验证码  返回目录

1、思路

  • 因为实际效果我们要获取4位验证码
  • 虽然上一步骤获取到了验证码,但是还是会出现不足4位或者超过4位的验证码
  • 需要进行判断筛选,只要4位的验证码

2、实践方法

先判断是否满足4位,不满足的话while循环重新获取验证码,满足4位跳出循环,并return出来

复制代码
    def getCode(self):
        """获取4位数验证码"""

        # 循环前获取code字数
        code = self.getCodeImg()
        print(f"验证码位数:【{len(code)}】位")
        while len(code) != 4:
            # 重新获取验证码
            code = self.getCodeImg()
            # print(f"验证码位数:【{len(code)}】位")
            # if len(code) != 4:
            #     print("验证码不是4位数!")
        print(f"输出4位验证码为:{code}")
        return code
复制代码

四、判断验证码是否正确  返回目录

1、思路

  • 虽然我们获取了4位验证码,但是因为识别率的问题,获取的验证码仍然不对,导致提示验证码错误

  •  我们还得重新获取一遍验证码,直到获取成功能够登陆为止

2、实践方法

判断页面如果有错误提示,则重新获取4位验证码

复制代码
    def checkCode(self):
        """判断验证码是否正确"""

        try:
            errorMsg = self.get_text(Loc.errorMsg_loc)
            if errorMsg == "验证码错误":
                self.inputCodeAction()
        except:
            print("验证码正确,进入首页!")
复制代码

五、输入验证码登录  返回目录

1、思路

  • 封装一个Action方法,把之前的各种方法封装在一起
  • 实现输入验证码登录
  • 此封装方法只是在获取验证码的类里,输入用户名和密码的方法在另一个类里

2、实践方法

    def inputCodeAction(self):
        """输入验证码登录"""

        code = self.getCode()                    # 获取4位验证码
        self.el_clear_sendKeys(Loc.code_loc, code)        # 清空验证码输入框并输入验证码
        self.el_click(Loc.loginButton_loc)             # 点击登录按钮
        self.checkCode()                        # 判断验证码是否正确

六、登录页面类  返回目录

登录页面类,封装输入用户名、密码、验证码、登录的操作方法

class LoginPage(BasePage):
    """登录页面"""

    def login_action(self,username,password):
        """登录操作"""
        self.el_sendKeys(Loc.username_loc, username)    # 输入用户名
        self.el_sendKeys(Loc.password_loc, password)    # 输入密码
        GetCode(self.driver).inputCodeAction()          # 输入验证码并登录

七、完整的获取验证码类代码  返回目录

复制代码
import pytesseract
from PIL import Image, ImageEnhance
from page_object.page.basePage import BasePage
from page_object.utils.functions import Functions as Fun
from page_object.locator.loginPageLoc import LoginPageLoc as Loc


class GetCode(BasePage):

    def remove(self,string):
        """字符串去除空格或换行"""

        str = string.replace(" ", "")
        str = str.replace("", "")
        str = str.replace('\n', "")
        return str

    def getCodeImg(self):
        """获取验证码"""

        # 步骤①:
        basePath = Fun().upPath() + "/utils/img/"
        imgPath = basePath + "code.png"
        savePath = basePath + "saveCode.png"
        # 定位图片元素
        imgElement = self.webDriverWait(Loc.codeImg_loc)
        # 点击验证码图片
        imgElement.click()
        # print(f"点击【{next(iter(Fun()))}】次验证码图片")
        # 截取当前页面的图并放到目录里
        self.driver.save_screenshot(imgPath)

        # 步骤②:
        # 获取验证码x,y轴,x&y代表左上角的坐标点
        imgLocation = imgElement.location
        print(f"图片坐标点:{imgLocation}")
        # 获取验证码长、宽
        imgSize = imgElement.size
        print(f"图片长、宽:{imgSize}")
        # 获取浏览器的长、宽
        windowSize = self.driver.get_window_size()
        print(f"浏览器长、宽:{windowSize}")
        # 打开截图
        openImg = Image.open(imgPath)
        # 获取保存截图的长、宽(宽:2700, 高:1950)
        screenImgSize = openImg.size
        print(f"保存截图的长、宽:{screenImgSize}")

        # 步骤③:截取截图的验证码图片
        # 图片左边距占据整个浏览器的百分比
        left = imgLocation['x']/windowSize['width']
        # 图片上边距占据整个浏览器的百分比
        top = imgLocation['y']/windowSize['height']
        # 图片右边距占据整个浏览器的百分比
        right = (imgLocation['x'] + imgSize['width'])/windowSize['width']
        # 图片下边距占据整个浏览器的百分比
        bottom = (imgLocation['y'] + imgSize['height'])/windowSize['height']

        # 需要截取的坐标
        screenLocation = (
            left * screenImgSize[0],
            top * screenImgSize[1]+150,
            right * screenImgSize[0],
            bottom * screenImgSize[1]+150
        )
        # 打开截图并截取区域并保存
        img = openImg.crop(screenLocation)
        img = img.convert('L')  # 转换模式:L | RGB

        # enhancer = ImageEnhance.Color(img)
        # enhancer = enhancer.enhance(0)
        # enhancer = ImageEnhance.Brightness(enhancer)
        # enhancer = enhancer.enhance(2)
        # enhancer = ImageEnhance.Contrast(enhancer)      # 增强对比度
        # enhancer = enhancer.enhance(8)
        # enhancer = ImageEnhance.Sharpness(enhancer)
        # img = enhancer.enhance(20)

        img = ImageEnhance.Contrast(img)  # 增强对比度
        img = img.enhance(2.0)
        img.save(savePath)

        # 步骤④:获得code验证码
        code = pytesseract.image_to_string(img).strip()
        print(f"提取的验证码为:【{self.remove(code)}】")
        return self.remove(code)


    def getCode(self):
        """获取4位数验证码"""

        # 循环前获取code字数
        code = self.getCodeImg()
        print(f"验证码位数:【{len(code)}】位")
        while len(code) != 4:
            # 重新获取验证码
            code = self.getCodeImg()
            print(f"验证码位数:【{len(code)}】位")
            if len(code) != 4:
                print("验证码不是4位数!")
        print(f"输出4位验证码为:{code}")
        return code


    def checkCode(self):
        """判断验证码是否正确"""

        try:
            errorMsg = self.get_text(Loc.errorMsg_loc)
            if errorMsg == "验证码错误":
                self.inputCodeAction()
        except:
            print("验证码正确,进入首页!")


    def inputCodeAction(self):
        """输入验证码登录"""

        code = self.getCode()
        self.el_clear_sendKeys(Loc.code_loc, code)
        self.el_click(Loc.loginButton_loc)
        self.checkCode()
复制代码

八、附录:静态图片文字提取  返回目录

1、思路:

  • 首先获取图片的src地址
  • 然后进行GET接口请求,获取图片的二进制数据
  • 再创建一个图片文件,把二进制数据写到图片里
  • 最后读取图片,获取验证码code

2、实践方法

获取图片地址,有两种情况,一种是通过解析页面获取src,一种是通过页面元素获取src

1)获取src

①通过前端页面代码获取src

这种方式比较简单,直接通过前端页面代码获取src

复制代码
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
    }
    # 打开登录页面地址
    url = 'https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx'
    # 获取前端页面代码
    page_text = requests.get(url=url, headers=headers).text    
    # 解析字符串格式的HTML文档对象
    tree = etree.HTML(page_text)
    # 解析出页面中图片的地址
    cod_img_src ='https://so.gushiwen.cn' + tree.xpath('//*[@id="imgCode"]/@src')[0]
复制代码

注:etree.HTML()可以用来解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象。作为_Element对象,可以方便的使用getparent()、remove()、xpath()等方法。

②页面元素获取src

当获取不到前端代码时候,可以用Selenium自动化获取元素属性值

复制代码
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
    }
    # 打开浏览器
    driver = webdriver.Chrome()
    # 浏览器打开登录地址
    driver.get("https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx")
    # CSS定位元素,获取src属性值
    src = driver.find_element_by_css_selector("#imgCode").get_attribute("src")
复制代码

2)获取图片二进制数据

cod_data = requests.get(url=src,headers=headers).content

打印结果:

b'GIF89a7\x00\x16\x00\xf7\x00\x00\x00\x00\x00\x00\x003\x00\x00f\x00\x00\x99\x00\x00\xcc\x00\x00\xff\x00+\x00\x00+3\x00+f\x00+\x99\x00+\xcc\x00+\xff\x00U\x00\x00U3\x00Uf\x00U\x99\x00U\xcc\x00U\xff\x00\x80\x00\x00\x803\x00\x80f\x00\x80\x99\x00\x80\xcc\x00\x80\xff\x00\xaa\x00\x00\xaa3\x00\xaaf\x00\xaa\x99\x00\xaa\xcc\x00\xaa\xff\x00\xd5\x00\x00\xd53\x00\xd5f\x00\xd5\x99\x00\xd5\xcc\x00\xd5\xff\x00\xff\x00\x00\xff3\x00\xfff\x00\xff\x99\x00\xff\xcc\x00\xff\xff3\x00\x003\x0033\x00f3\x00\x993\x00\xcc3\x00\xff3+\x003+33+f3+\x993+\xcc3+\xff3U\x003U33Uf3U\x993U\xcc3U\xff3\x80\x003\x8033\x80f3\x80\x993\x80\xcc3\x80\xff3\xaa\x003\xaa33\xaaf3\xaa\x993\xaa\xcc3\xaa\xff3\xd5\x003\xd533\xd5f3\xd5\x993\xd5\xcc3\xd5\xff3\xff\x003\xff33\xfff3\xff\x993\xff\xcc3\xff\xfff\x00\x00f\x003f\x00ff\x00\x99f\x00\xccf\x00\xfff+\x00f+3f+ff+\x99f+\xccf+\xfffU\x00fU3fUffU\x99fU\xccfU\xfff\x80\x00f\x803f\x80ff\x80\x99f\x80\xccf\x80\xfff\xaa\x00f\xaa3f\xaaff\xaa\x99f\xaa\xccf\xaa\xfff\xd5\x00f\xd53f\xd5ff\xd5\x99f\xd5\xccf\xd5\xfff\xff\x00f\xff3f\xffff\xff\x99f\xff\xccf\xff\xff\x99\x00\x00\x99\x003\x99\x00f\x99\x00\x99\x99\x00\xcc\x99\x00\xff\x99+\x00\x99+3\x99+f\x99+\x99\x99+\xcc\x99+\xff\x99U\x00\x99U3\x99Uf\x99U\x99\x99U\xcc\x99U\xff\x99\x80\x00\x99\x803\x99\x80f\x99\x80\x99\x99\x80\xcc\x99\x80\xff\x99\xaa\x00\x99\xaa3\x99\xaaf\x99\xaa\x99\x99\xaa\xcc\x99\xaa\xff\x99\xd5\x00\x99\xd53\x99\xd5f\x99\xd5\x99\x99\xd5\xcc\x99\xd5\xff\x99\xff\x00\x99\xff3\x99\xfff\x99\xff\x99\x99\xff\xcc\x99\xff\xff\xcc\x00\x00\xcc\x003\xcc\x00f\xcc\x00\x99\xcc\x00\xcc\xcc\x00\xff\xcc+\x00\xcc+3\xcc+f\xcc+\x99\xcc+\xcc\xcc+\xff\xccU\x00\xccU3\xccUf\xccU\x99\xccU\xcc\xccU\xff\xcc\x80\x00\xcc\x803\xcc\x80f\xcc\x80\x99\xcc\x80\xcc\xcc\x80\xff\xcc\xaa\x00\xcc\xaa3\xcc\xaaf\xcc\xaa\x99\xcc\xaa\xcc\xcc\xaa\xff\xcc\xd5\x00\xcc\xd53\xcc\xd5f\xcc\xd5\x99\xcc\xd5\xcc\xcc\xd5\xff\xcc\xff\x00\xcc\xff3\xcc\xfff\xcc\xff\x99\xcc\xff\xcc\xcc\xff\xff\xff\x00\x00\xff\x003\xff\x00f\xff\x00\x99\xff\x00\xcc\xff\x00\xff\xff+\x00\xff+3\xff+f\xff+\x99\xff+\xcc\xff+\xff\xffU\x00\xffU3\xffUf\xffU\x99\xffU\xcc\xffU\xff\xff\x80\x00\xff\x803\xff\x80f\xff\x80\x99\xff\x80\xcc\xff\x80\xff\xff\xaa\x00\xff\xaa3\xff\xaaf\xff\xaa\x99\xff\xaa\xcc\xff\xaa\xff\xff\xd5\x00\xff\xd53\xff\xd5f\xff\xd5\x99\xff\xd5\xcc\xff\xd5\xff\xff\xff\x00\xff\xff3\xff\xfff\xff\xff\x99\xff\xff\xcc\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xfc\x00,\x00\x00\x00\x007\x00\x16\x00\x00\x08\xff\x00\x95\x11\x13Hp\xa0\xc1\x82\x08\x0f*L\xc8p\xa1\xc3}\x10#J\xfc$1\x93\xb2}\x99$\xee\xa3\x08\xd1\xa2\xc6\x8f 5\x12\xe3\xf8\xf1\x13\xb1\x8f\x03\xf7)\xcb\x08\xf1dD\x96!cJ\x14\x08\xd2%H\x8b\'W\xb6\x84x\xd1\xa6L\x8c\x175z\xd4H2d\xce\xa3\x1c]\xc2\x04\xb92\xe8G\x9a\x115a)\xb0i\x1f1P\xbe\x06\xb8x`\xb0\xd1\x80\x16-\xe0\x10K6P\x930\x16V\xd0\x02\xe9\xa8\xefO\x951\x9a \xea\xf3S\xa5\xaa\xc4\x91\x11\x93\xed\x1bD\xe0\x0eDw\x04\\\xec\x88\x06\xb1\x17X\xb0,\xe0\xc4%\xc6\xa8\x85\x15\xc7hYh\x1ak\xa5\x8a\x15Md\x93\xfd\xa1BI\'O\x97\x93\x95\xb9 PU\x9f\x0b\x17\x10"\xea\xc3\xd2"\xd4\xbeF-t\xa8\x94\xe4X\x8d\\@V\xba|j[y\x0c\xe1\xb6U\x96\t\x15\xa8\x17b\x16\x17F\x88aA\x1d\x13\xb6m}\x81X\xc4\xb1J\xfc\x0f\x0bJ\xfa\x00U\xd9^:\x15\x15\xbb\x11\xa1F\xff\xc4Bz\xb4\x8b\xc9\xa0\xee\xea\xbb\xd2b\xc6>M\xfa\x1ek\x1a\x96\xfe\xaa-+cx3\xaar%\x1ap\xe1w\xa5\'\x91 \x05\x04\x16\x98\x05-\r\xa3\x8c&\xca\xb8s\xd8)\xfb\xf4\xf2X}\x11\xf1b\x85\x0e\xc9h\xa7\x89[\xf0yW\xd5HGiD\x9e\x0b\x05h2\x9ak;\xed\xa3\xe0$\xed\x11\x93I\x0b\xfdAD\x962\xc2\xe0\xc7[(\xedX\xa6L\x15\x7fLvWq\x11\x1dW\x00a\x8e\xb8\xa0\x03aA1\xb8\x0f=\xec\xcdwEb61\xc6\x02\x19\xc9T\xd6Y!U\x88\xb1YU8\xa9\xe4\xd3>\xe4\xd9\x05\x98\x0bj\xe8\xe5\xa0\x0b\xd1\x103\x0cX\xa7\xacgE\x99\x0cfRe\x15\x9ad\xe2\x16\x1c\xc3\xe4\xe3\x16\x87>e"\xa0\x8a\xca\x1c\x07\x04A\x88\xb4@\x80&\x93\xb1\xe7W;`M\xd6\x0b\x0b\xd2\x11g\xc5\xa4\x98Y)\xd0.\xdb}w\x97x\x10\x91\x07GT\xa7\xfd\xa0\xcc0\xb0\x1d\x16\xd6X\x8c=\x99\xd6\xa4\x97\x8d\xfa\x87\x15v\r\x89\xb3\'\x8ax\xa5$\x11_q\x0cc\xd5>\xbe\xb4\xe0\x02\x84\xfbPr\x98]\xe9)\xf3\xe8\xaa9\xa8\xa6\xdd$\xa0\x0c\x14\xc9\x96\x80~\x16\x93S\xd3\xa2\xeaSA\xa0\xd07P\xb3-\x05\xb5`Dx\xfd\xa4\x11B\n2\x88\x19\x83_\xf2\xa4+D\x02\x1a4S\xba\x1aaF\x0c\x83\xc3\x9c+\xd1\xba\xe2\xde\xab\xd2P\x11)h\x94I\xf9R\x9b\xef>\xdc^\x84\xaf\x97&5\x05"A\xda\x8e\xda\xac@&5K/\xc4c\xd1\xdb\xec\xc2\nV|\xd5U\xe5\x12\x13\x10\x00;'

3)数据写入到图片中,并识别验证码

    # 读取二进制数据写入到图片中
    with open('./code.jpg', 'wb') as fp:
        fp.write(cod_data)
    # 识别图片中的文字
    text = pytesseract.image_to_string(Image.open(r'./code.jpg'))

3、总结

但是这种通过接口方式获取的验证码并不是你想要的,因为每请求一次接口,图片就会发生变化,所以只能适用于静态不变的图片比较合适。

 

参考文章:《Pytesseract的安装与使用

 

posted @   Owen_ET  阅读(7797)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 模様 (TV size ver.) Ivy to Fraudulent Game
  3. 3 河口恭吾
  4. 4 愛してる 高鈴
  5. 5 一生所爱 卢冠廷,莫文蔚
  6. 6 世间美好与你环环相扣 柏松
  7. 7 理想三旬 陈鸿宇
  8. 8 不浪漫罪名 王杰
  9. 9 樱花树下 张敬轩
  10. 10 因为你在 达闻西乐队,福禄寿FloruitShow
  11. 11 悬溺 葛东琪
世间美好与你环环相扣 - 柏松
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 尹初七

作曲 : 柏松

编曲 : 彭圣杰

偏偏秉烛夜游

偏偏秉烛夜游

午夜星辰 似奔走之友

爱你每个结痂伤口

酿成的陈年烈酒

入喉尚算可口

入喉尚算可口

怎么泪水 还偶尔失守

邀你细看心中缺口

裂缝中留存 温柔

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

让樱花偷偷 吻你额头

让世间美好 与你环环相扣

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

当樱花开的纷纷扬扬

当世间美好 与你环环相扣

特别鸣谢:槿葵,我们的海报制作妹妹。

原唱:柏松

吉他:柏松

和声:柏松

录音:柏松

混音:张强

点击右上角即可分享
微信分享提示