smtplib发送含特殊字符爬取内容报UnicodeEncodeError问题求助
问题原因
触发UnicodeEncodeError的核心原因有两点,同时原代码还存在两个易触发运行错误的逻辑问题:
- 你手动拼接的邮件字符串包含
\u201D(右弯引号)、\u2022(圆点项目符号)这类超出ASCII编码范围(0-127)的Unicode字符,而smtplib.SMTP.sendmail()方法默认使用ASCII编码处理传入的消息内容,遇到非ASCII字符就会抛出编码错误。 - 手动拼接邮件字符串的写法不符合SMTP协议规范,没有声明内容编码,即使部分场景下能发送成功,也容易出现主题乱码、正文截断的问题。
- 原代码参数不匹配:定义
send_email函数时声明了type、data两个入参,实际调用时仅传入了result_title一个参数,修复编码问题后也会触发参数报错。 - 原代码DOM取值逻辑错误:
response.html.find('ul.srp-results li.s-item')返回的是匹配到的所有列表项组成的列表,列表对象没有find方法,直接调用会抛出属性错误。
修复方案
最稳妥的解决方式是使用Python标准库自带的email模块构建合规的邮件对象,模块会自动处理非ASCII字符的编码和邮件头合规性,不需要手动拼接字符串。
修复后的可运行代码如下:
import os import smtplib from email.mime.text import MIMEText from requests_html import HTMLSession session = HTMLSession() # 建议从环境变量读取邮箱账号密码,避免硬编码泄露 EMAIL_ADDRESS = os.getenv("EMAIL_ADDR") EMAIL_PASSWORD = os.getenv("EMAIL_PWD") def send_email(mail_type, data): with smtplib.SMTP('smtp.gmail.com', 587) as smtp: smtp.ehlo() smtp.starttls() smtp.ehlo() smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD) to_addr = 'toemail@example.com' # 构建UTF-8编码的纯文本邮件,自动处理特殊字符编码 msg = MIMEText(data, 'plain', 'utf-8') msg['From'] = EMAIL_ADDRESS msg['To'] = to_addr msg['Subject'] = f'NEW EBAY RESULT(S) FOR: {mail_type}' smtp.send_message(msg) response = session.get('https://www.ebay.com/sch/i.html?_from=R40&_nkw=blink+182&_sacat=0&_sop=10&rt=nc&LH_PrefLoc=2') # 取第一个搜索结果项,如需遍历所有结果可加循环处理 result = response.html.find('ul.srp-results li.s-item')[0] result_title = result.find('h3.s-item__title', first=True).text.replace('New Listing', '') # 按函数定义传入两个参数,示例中搜索关键词作为邮件类型标识,爬取的标题作为邮件内容 send_email("blink 182", result_title)
如果不想引入email模块,也可以在手动拼接消息时添加编码声明头,再将内容按UTF-8编码后传入sendmail,但是这种方式兼容性较差,不推荐在生产环境使用:
msg = f'Subject: {subject}\nContent-Type: text/plain; charset=utf-8\n\n{body}' smtp.sendmail(EMAIL_ADDRESS, addresses, msg.encode('utf-8'))
内容的提问来源于stack exchange,提问作者Mario Parra
相关产品推荐
相关产品推荐

