记一次诡异的python脚本中编码报错,crontab执行报错,但手动执行正常

一、背景

通过python脚本上传图片到阿里云的OSS存储桶内。

二、环境

群晖存储设备,该设备上没有crontab命令,配置定时任务必须指明用户。

操作系统:Linux RackStation 3.10.102 #15101 SMP Fri Apr 28 02:48:03 CST 2017 x86_64 GNU/Linux synology_broadwell_rs18017xs+

三、报错信息

Traceback (most recent call last):

File "/volume1/scripts/backupToOSS.py", line 59, in 

bucket.put_object_from_file(ossName, tfile)

File "/usr/lib/python2.7/site-packages/oss2/api.py", line 380, in put_object_from_file

with open(to_unicode(filename), 'rb') as f:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 9-10: ordinal not in range(128)


Traceback (most recent call last):

File "/volume1/scripts/backupToOSS.py", line 59, in 

bucket.put_object_from_file(ossName, tfile)

File "/usr/lib/python2.7/site-packages/oss2/api.py", line 380, in put_object_from_file

with open(to_unicode(filename), 'rb') as f:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 9-10: ordinal not in range(128)

从报错信息看,应该是脚本中在执行bucket.put_object_from_file(ossName, tfile)的时候,调用/usr/lib/python2.7/site-packages/oss2/api.py报错的,

四、整个python脚本

#!/usr/bin/env python

#-*- coding: utf-8 -*-

#Filename: backupToOSS.py

#Author:

#Desc:该脚本用于把给定的文件传输到阿里云的OSS中。


import os

import datetime

import commands

import oss2

import logging

import sys

reload(sys)

sys.setdefaultencoding('utf-8')


# 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。

# 通过环境变量获取,或者把诸如“<你的AccessKeyId>”替换成真实的AccessKeyId等。

#

# 以杭州区域为例,Endpoint可以是:

# http://oss-cn-hangzhou.aliyuncs.com

# https://oss-cn-hangzhou.aliyuncs.com

# 分别以HTTP、HTTPS协议访问。

access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', 'aaaaaaaaaaaaaaaaaa')

access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', 'xxxxxxxxxxxx')

bucket_name = os.getenv('OSS_TEST_BUCKET', 'yyyyyyyy')

endpoint = os.getenv('OSS_TEST_ENDPOINT', 'zzzzzzzzzzzzzzzz')


# 确认上面的参数都填写正确了

for param in (access_key_id, access_key_secret, bucket_name, endpoint):

assert '<' not in param, '请设置参数:' + param


# 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行

bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)

cmdYsd = 'date -d "yesterday" +"%Y%m%d"'

#getoutput(cmd)方法返回的是一个字符串,用于构成变动文件名称列表文件名

oYsd = commands.getoutput(cmdYsd)

#findWithOSS.sh脚本生成的前一天变动文件的名称列表文件

dataFile = "/opt/tmp/datadir/filelist.log-" + oYsd

logging.basicConfig(filename="/opt/tmp/osslogs/ossError.log-" + oYsd, level=logging.ERROR)

#把本地文件上传到OSS,新的Object名称存储在变量"ossName”中,ossName的命名规则:1,使用UTF-8编码;2,长度必须在1-1023字节之间;3,不能以“/”或者“\”字符开头。

fileListFile = open(dataFile, 'r')

fileList = fileListFile.readlines()

fileListFile.close()

with open("/opt/tmp/osslogs/ossTransferedFiles.log-"+oYsd, 'a+', buffering=1024) as transLog:

for tfile in fileList:

tfile = tfile.strip()

ossName = tfile.lstrip('/')

# fexist = bucket.object_exists(ossName)

# print fexist

#判断文件在oss上是否存在,如果不存在则上传,这样可以避免文件重传浪费时间;

# if not fexist:

nowTime = datetime.datetime.now().strftime('%Y%m%d_%T')

try:

bucket.put_object_from_file(ossName, tfile)

transLog.write("{0} {1}\n".format(nowTime, tfile))

except IOError:

logging.exception("######"+nowTime+"######")

except:

logging.exception("######"+nowTime+"######")

tmpFile = open("/opt/tmp/osslogs/ossCurrentFileWhenExit.log", 'w+')

tmpFile.write("{0} {1}\n".format(nowTime, tfile))

tmpFile.close()

sys.exit()

五、crontab配置

#backup data to Aliyun OSS

30 00 * * * root /bin/bash /volume1/scripts/findWithOSS.sh

30 09 * * * root /bin/python /volume1/scripts/backupToOSS.py

六、诡异现象

奇怪的是,完全一样的脚本,使用crontab跑定时任务就会报上面的错误,但是手动执行就完全没有问题:

nohup python ./backupToOSS.py &

七、原因分析

crontab执行脚本时的环境变量跟直接以root用户身份手动执行的时候环境变量不同。

八、解决办法

在/etc/crontab文件中添加一条载入命令source即可:经过测试这种方法生效了,没有再报错。

#backup data to Aliyun OSS

30 00 * * * root /bin/bash /volume1/scripts/findWithOSS.sh

55 10 * * * root source /etc/profile && /bin/python /volume1/scripts/backupToOSS.py

你可能感兴趣的:(Python,Shell)