jjzjj

躺着就能涨粉?Python自动化短视频搬运(六)|自动发布

也鱼实验室 2023-11-07 原文

脚本四:视频自动发布到平台

好了,影片、封面、标题及实时频道监测,一切准备就绪,我们终于来到了自动化搬运脚本的最后一步:发布。由于可发布的自媒体平台众多,我们需要针对每个平台的Web结构编写独立的脚本,这部分有不少的工作量。但好在这些平台的HTML样式及交互流程基本类似,熟悉了自动发布脚本的编写方法后,扩展到任何一个平台都没有什么难度。

1. Selenium(浏览器自动化工具)

首先,我们先得了解一个大前提,所有平台的视频上传对于脚本来说都只能通过web端进行,并不是通过APP端,但好在他们都提供了web版的“创作中心”。自动发布脚本之所以能自动发布视频的核心原理是让浏览器可以模拟真人进行网页操作,从而完成整个视频上传发布流程。那么接下来就让我隆重推出这个用来模拟用户在浏览器上动作的第三方开源工具-Selenium。

Selenium 是一系列工具和库的综合项目,这些工具和库支持 web 浏览器的自动化。

常见的Selenium执行动作有:将文本输入到字段中,选择下拉值和复选框,并单击文档中的链接。 它还提供许多其他控件,比如鼠标移动、任意 JavaScript 执行等等。虽然Selenium主要用于网站的前端测试,但像我们这样用于网页自动化的项目,也是一个很好的选择。

让我们先用pip安装Selenium:

$ pip install selenium

WebDriver

使用Selenium的核心就是WebDriver,我们需要根据想要操作的浏览器类型,下载对应的WebDriver驱动文件,如Firefox的geckodriver:https://github.com/mozilla/geckodriver/releases,Chrome的chromedriver:https://chromedriver.chromium.org/downloads。对应找到符合你操作系统类型的驱动文件,进行下载。我这篇文章中的案例将采用Firefox浏览器进行。

导入WebDriver后,我们就可以尝试让Selenium快速打开一个网页了(就用快手平台的创作者中心吧):

from selenium import webdriver
driver = webdriver.Firefox(executable_path = './geckodriver')
driver.get("https://cp.kuaishou.com/article/publish/video")

地址栏背景变成红色且出现机器人图标,说明这个页面是由自动化脚本打开的:



你可能会注意到,每次由selenium访问网站时都需要重新登录,即使上一次已经登录成功。那是因为,每次调用webdriver生成一个新的访问session时,浏览器都会为这次session新建一个profile目录,用以存储网页缓存和登录状态,cookie等,因此之前访问过的登录信息默认不会被传递过来。由于我们的脚本是要求浏览器保留登录状态的,避免需要人工介入登录,因此我们要调用webdriver中的profile指定路径的功能,使每次新的访问session都能够获取到已经存在的登录状态,从而跳过登录页面。

首先,我们要找到Firefox默认的profile存放地址,方法是:

  1. 打开Firefox

  2. 地址栏输入about:support

  3. 找到Profile Folder行即是profile存放地址



    有了这个目录地址,使用以下代码拷贝该地址到webdriver的profileDir里:

from selenium import webdriver 
profileDir = r'/Users/yeyu/Library/Application Support/Firefox/Profiles/czstyl61.default-release/'
profile = webdriver.FirefoxProfile(profileDir)
driver = webdriver.Firefox(executable_path = './geckodriver', firefox_profile = profile) 
driver.get("https://cp.kuaishou.com/article/publish/video")

最后,不要忘了手动打开一次 https://cp.kuaishou.com/article/publish/video,通过手机扫码或输入用户名密码,成功登录一次快手平台,生成profile,以后只要登录信息不过期,selenium每次新建网页session时,都能直接进入上传页面而不需要再进行登录了。

2. 自动脚本的基本编写过程

在编写代码前,让我们以最简单的方式了解怎么写一个自动脚本,总结下来就是以下两步:

  • 读取需要进行交互的HTML组件标记
  • 对该标记进行状态判断(clickable)、写入(Send keys)或点击(Click)

参考下图,以Firefox为例,读取HTML组件标记只需要 1)鼠标右击需要操控的HTML组件, 2)点击菜单里Inspect(检查)项,3)读取Inspector窗口中高亮的标记内容,如button类型,class名称等等。


读取web组件标记步骤

虽然我们创建的driver对象有find_element()方法能够找到并生成组件对象,但是在一般的网络交互中,页面打开的时间受网速等很多因素影响,当一个页面切换的时候,无法保证下一个页面中我们感兴趣的元素能够多久刷新出来,因此直接使用find_element()配合固定延时,不是很高效。Selenium提供了一个很实用的WebDriverWait(driver, timeout).until()方法,可以在给定的时间里等待元素可用,一旦可用就立即返回元素对象。对于上面的“上传视频”按钮,直接看代码,我们用到了CSS_SELECTOR来定位button类型元素的class名称:

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

button = WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                                      "button[class='SOCr7n1uoqI-']")))
button.click()

不单是button类型,其他的类型如div等都是支持click()的。另外,input类型包括text/file,都可以send_keys()进行输入操作。这部分会在后面的实际平台操作中详细介绍。

3. 快手平台上传发布

打开快手上传页面:快手创作者服务平台

视频文件上传

根据上两个章节讲到的,免去登录流程后,首先映入眼帘的就是“上传视频”按钮,找到它的组件元素:button class=“SOCr7n1uoqI-”,我们用WebDriverWait等待这个页面的刷新,由于这个页面主要是视频文件输入框,所以我们的脚本并不需要去button.click(),而是找到type为file的input元素,向它输入我们需要上传的视频文件即可:

button = WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                                      "button[class='SOCr7n1uoqI-']")))
search = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
search.send_keys("<文件路径>/v1080p_audio_output.mp4")

运行后,你就能看到下一个页面,并且文件正在上传中,等待一会,就看到了文件上传成功:


上传成功

那么如何用代码判断上传成功呢?同样的我们找到这个“上传成功”文字的HTML标记,得到它是span类型的类名为"DqNkLCyIyfQ-"。



所以我们就用一个while循环来等待这个span标记的出现,从而第一时刻获知视频文件的上传成功。
while "上传成功" != driver.find_element(By.CSS_SELECTOR, "span[class='DqNkLCyIyfQ-']").get_attribute("innerHTML"):
    time.sleep(3)

封面上传

视频上传成功后,我们就可以开始上传在上一篇文章中制作好的封面图片了。首先找到“编辑封面”的HTML元素,<button class="ant-btn ant-btn-primary"...>:



点击操作,代码:

WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                       "button[class='ant-btn ant-btn-primary']"))).click()

在下个页面找到“上传封面”标签的HTML元素,<div id="rc-tabs-1-tab-2"...>:


上传封面

点击操作,代码:

WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                              "div[id='rc-tabs-1-tab-2']"))).click()

再进入到下一个页面后,又来到了熟悉的文件输入页了,对于<button class="ant-btn ant-btn-primary xJ4CDDyNkAs-"...>我们就无需再点击了,只要等它的出现,然后直接对<input type="file"...>进行文件路径输入即可:


上传封面图片

我们就使用上一篇制作的封面“v1080p_audio_output_with_title.jpeg”进行上传,代码部分:

WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[class='ant-btn ant-btn-primary xJ4CDDyNkAs-']")))
search_list = driver.find_elements(By.CSS_SELECTOR, "input[type='file']")
search_list[1].send_keys("<文件路径>/v1080p_audio_output_with_title.jpeg")

最后,在下一个页面中,点击“确定”按钮:



代码:

WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                          "button[class='ant-btn ant-btn-primary TyKzAKboOM0-']"))).click()

填写描述

上传完了视频和封面图片,最后一个需要输入的就是视频描述了,这个就很简单了。找到输入框的HTML元素标记 <div class="clGhv3UpdEo-"...>:



调用send_keys()输入text即可,这里我们就用封面使用的文字“一段不错的舞蹈!”。假设你搬运的都是同一个主题,另外还可以加入一些固定的标签,这里举例如“#小哥哥跳舞 #国外舞蹈达人”:

title_input = WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class='clGhv3UpdEo-']")))
title_input.send_keys("一段不错的舞蹈!")
title_input.send_keys("#小哥哥跳舞 #国外舞蹈达人")

此外,在实际代码开发中,还应该考虑到文本框的字数或视频大小限制等其他边界处理,这里就不展开了。

发布

所有必要的内容都输入完毕,页面上还有一些其他的选项,暂时不必去改动,让我们直接点击发布按钮,


发布按钮

最终发布前我们可以做一个一分钟的延时,避免由于网络问题导致封面没有来得及上传成功,上代码:

import time

time.sleep(60)
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                        "button[class='ant-btn ant-btn-primary GncXo-rrppc-']"))).click()

如果看到跳转到以下的页面,说明脚本自动化发布视频到快手平台已经完成!


总结

至此,我们的整个自动化搬运流程走完了,通过这个系列的文章,整个过程包括频道监测->影片下载->影片处理->自媒体发布,都做了比较详细的介绍和源代码提供。后面还会为大家添加抖音等其他热门平台的自动化脚本,不过如果按照这篇文章走完了快手流程,相信你自己也可以很快复制出其他平台的上传脚本的。此外,后续还会提供从其他国外平台进行搬运的教程,敬请期待吧!

本篇用到的代码:

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

profileDir = '<修改为你的Firefox的profile目录>'
profile = webdriver.FirefoxProfile(profileDir)
driver = webdriver.Firefox(executable_path = '<修改为你的webdriver文件路径>/geckodriver', firefox_profile = profile)
driver.get("https://cp.kuaishou.com/article/publish/video")

#视频上传
button = WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                                      "button[class='SOCr7n1uoqI-']")))
file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
file_input.send_keys("<修改为你的视频文件路径>/v1080p_audio_output.mp4")
while "上传成功" != driver.find_element(By.CSS_SELECTOR, "span[class='DqNkLCyIyfQ-']").get_attribute("innerHTML"):
    time.sleep(3)

#封面上传
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                       "button[class='ant-btn ant-btn-primary']"))).click()
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                              "div[id='rc-tabs-1-tab-2']"))).click()
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                                       "button[class='ant-btn ant-btn-primary xJ4CDDyNkAs-']")))
search_list = driver.find_elements(By.CSS_SELECTOR, "input[type='file']")
search_list[1].send_keys("<修改为你的封面图片文件路径>/v1080p_audio_output_with_title.jpeg")
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                          "button[class='ant-btn ant-btn-primary TyKzAKboOM0-']"))).click()
#填写描述
title_input = WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class='clGhv3UpdEo-']")))
title_input.send_keys("一段不错的舞蹈!")
title_input.send_keys("#小哥哥跳舞 #国外舞蹈达人")

#发布
time.sleep(60)
WebDriverWait(driver, 150).until(EC.element_to_be_clickable((By.CSS_SELECTOR, \
                        "button[class='ant-btn ant-btn-primary GncXo-rrppc-']"))).click()

publish.py

有关躺着就能涨粉?Python自动化短视频搬运(六)|自动发布的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  5. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  10. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

随机推荐