掘金自动发布文章优化合集|Python 主题月

本文正在参加「Python主题月」,详情查看 活动链接

背景介绍

如下两篇文章中从登录掘金到发布文章的全过程。之所以会有两篇文章,是因为写文章的时候后面的功能还没有完成。今天的文章是对整个项目的优化以及补充。

正文开始

此项目目前已经实现自动部署、邮件提醒、开关配置等功能。

项目主页提供详细的使用文档,如果你有需要欢迎 Fork 掘金自动发布文章

滑块拖拽优化

效果对比

之前的文章中有提到滑块的拖拽很慢(甚至会出现超时的情况),我们直接看优化前后的对比:

  • 优化前

Large GIF (382x320).gif

  • 优化后

Large GIF (382x320).gif

优化分析

这里是利用的正太分布的曲线是一条完美的先加速后减速的图像。下面对比一下两种方式的轨迹:

  • 拖拽的总距离为 100 px
  • 横坐标为第几次位移,纵坐标为位移的距离

image.png

总的来前者对应的方式较慢且误差较大。后者对应的方式为先加速后减速的过程。后者应该更符合拖拽逻辑。(这里不分好坏,只看结果。如果后者有一天被检测出违规拖拽,那么依然是可以使用前者)

代码实现

完整代码见 track.py

下面是关于优化后生成轨迹的代码:

def gen_normal_track(distance):
    def norm_fun(x, mu, sigma):
        pdf = np.exp(-((x - mu) ** 2) / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi))
        return pdf

    result = []
    # TODO 这里的移动次数可以根据 distance 灵活配置
    for i in range(-10, 10, 1):
        result.append(norm_fun(i, 0, 1) * distance)
    # 为了减少误差
    result.append(sum(result) - distance)
    return result
复制代码

优化页面等待

项目中使用很多 time.sleep(),有没有更优雅的方式。

因为懒。再者项目本身比较简单,发布属于一次性任务,对于程序的执行时间没有严格的限制,所以就偷懒直接就忽略这些细节。至于优化的方式肯定是有的,如下代码就会等待10秒,如果10秒内找到元素则立即返回,否则会抛出 TimeoutException 异常,WebDriverWait 默认每500毫秒调用一下ExpectedCondition直到它返回成功为止。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://juejin.cn/")
try:
    element = WebDriverWait(driver,10).until(
        EC.presence_of_element_located((By.XPATH, '''//div[@class="sc-kkGfuU bujTgx"]'''))
    )
finally:
    driver.quit()
复制代码

当然有更简单的方式直接使用全局的参数配置, 默认等待时间统一设置为10秒。

driver.implicitly_wait(10) # seconds
复制代码

错误重试机制

因滑块的识别以及滑块的拖拽存在失败的概率,导致登录不成功 代码见 juejin.py

  • 新增登录成功的判断
  • 新增登录失败重试机制

核心代码如下:


# 登录成功的判断
JUEJIN_NICKNAME = "西红柿蛋炒饭"
juejin_avatar_alt = JUEJIN_NICKNAME + "的头像"
driver.find_element(By.XPATH, f'//img[@alt="{juejin_avatar_alt}"]')


# 重试
for retry in range(self.retry):
    # ...
    get_cookies()
    # ...
    try:
        avatar = self.driver.find_element(By.XPATH, '''//img[@alt="西红柿蛋炒饭的头像"]''')
        if avatar:
            break
    except NoSuchElementException:
        pass
复制代码

新增邮件功能

完整代码见 mail.py

新增文章发布完成邮件通知功能,邮件代码如下:

# 邮箱的配置请自行设置
def send(content: str, subject: str, mail_from: str, mail_to: list):
    msg_root = MIMEMultipart('related')
    msg_text = MIMEText(content, 'html', 'utf-8')
    msg_root.attach(msg_text)
    msg_root['Subject'] = subject
    msg_root['From'] = mail_from
    msg_root['To'] = ";".join(mail_to)

    try:
        stp = smtplib.SMTP_SSL(MAIL_HOST, MAIL_PORT)
        # stp.set_debuglevel(1)
        stp.ehlo()
        stp.login(MAIL_USER, MAIL_PASSWORD)
        stp.sendmail(MAIL_ADDRESS, mail_to, msg_root.as_string())
        stp.quit()
    except Exception as e:
        print(traceback.format_exc(e))
复制代码

需要注意的是邮箱需要开通 POP3/SMTP/IMAP 服务,本文的配置开通的是 POP3/SMTP 服务,您可以根据邮箱的配置设置邮箱帐号密码。

变量 描述 示例
MAIL_USER 发件人邮箱用户名 xxx.qq.com
MAIL_ADDRESS 发件人邮箱地址 xxx.qq.com
MAIL_HOST 发件人邮箱服务器 smt.qq.com
MAIL_PASSWORD 发件人邮箱密码 xxxxxx
MAIL_PORT 邮箱服务器端口 465
MAIL_TO 收信邮箱 xxx.qq.com

备注:这里测试过网易邮箱以及 QQ 邮箱的配置,均可正常发送邮件。

邮件结果如下:

image.png

写在最后

  1. 关于滑块检测成功率较低怎么处理?

这里关于滑块检测的算法有很多中比如基于 CV2 的 边缘检测;还有基于 YOLO 的目标识别技术。这里不做展开,其中基于机器学习的目标识别的成功率能达到 99%,有兴趣的小伙伴可以自行搜索。

  1. 关于项目未知错误的处理方式。

可以直接查看 GitHub Action 的运行结果,该项目会打印所有异常信息。

image.png

如果你觉得我的项目对你有帮助,欢迎一键三连❤️❤️❤️

此项目所有代码见 我的GitHub仓库 ,欢迎 star fork。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享