AutoPublish: 多平台文章发布软件
简介
当我们完成一篇文章时,当然希望将自己的文章发布到多个不同的平台,让更多人看到,但自己一个个手动登录然后手动去发送实在太枯燥的,自己也有这样的需求,希望自己公众号的文章可以同步到知乎、CSDN 等各种不同的平台上,找了一下市面上的工具,没有特别满意的,所以就着手自己开发一个。
现在已经开源到 Github 上:https://github.com/ayuLiao/AutoPublish
欢迎大家使用以及提 PR
至于如何使用,Github 的 README.md 中有比较详细的说明,这里就不再说明,本文主要从源码层面介绍一下 AutoPublish
原理分析
平台登录
为了快速实现这个文章多平台发送的功能,选择使用 Selenium 来实现登录和文章发布的逻辑,但在实现过程中遇到了一些问题,如知乎、CSDN 登录时都会检测到 Selenium。
在开发AutoPublish时主要使用 Chrome,这里尝试让 Selenium 通过开发者模式控制 Chrome,开发者模型下的 Chrome 在某些关键参数上会与正常使用相同,但是可惜的是依旧没有绕过检查,这说明这些网站使用了其他参数来判断你使用了 Selenium,只是这个参数我们自身无法确定,遇到这种情况,有三种解决方法
1. 使用中间人 mitmproxy,将请求中的参数修改,这里可以将 Selenium 中所有的参数都修改了 (推荐)
2. 编写 Chrome 插件,Selenium 通过插件模式加载 Chrome,让插件通过 JS 直接修改 Chrome 的参数 (编写插件难度较大,本人未使用过)
3. 重新编译 Selenium,替换关键变量名 (难度大,本人未使用过)
但目前支持的 3 个平台 (知乎、CSDN、豆瓣) 都没有使用上面 3 种方式,而是直接使用 requests 通过模拟请求的方式来实现登录,其中知乎的登录规则最为恶心 :(。
使用 Selenium
完成登录后,会获得对应的 Cookies,这些 Cookies 就类似于身份证一样的存在,有了正确的 Cookies 你就可以在登录状态做相应的事情了,比如在登录的账号下发表文章。
其实发表文章理论上也是可以使用 requests 的形式来实现的,但简单看一下,不同平台发送文章的逻辑不相同,图片处理、样式处理这些也比较棘手,为了最快速度的实现项目,依旧通过 Selenium 的形式去实现,简单快速。
但在使用 Selenium 的过程中也遇到了一些问题,比如文章中图像的输入,像 CSDN 还好,因为后台就是 MarkDown 编辑器,样式这些不需要我们关心,而知乎需要自己将 MarkDown 渲染成 HTML,此时图像输入就比较麻烦了,此外 Selenium 不支持输入 emoji 表情,我的部分文章为了让读者不感觉到无趣,在部分段落中添加了 emoji,而 Selenium 发送输入包含 emoji 的文字时就会抛出异常。
使用 autogui
最后决定使用 autogui,autogui 可以控制计算机的鼠标与键盘,从而实现点击、输入等效果,安装 autogui 需要安装相应的依赖驱动,这也操作了一些困扰,当 autogui 控制你鼠标或键盘时,你就无法使用鼠标或键盘了,因为它是通过驱动去控制的,与通过真实鼠标去控制是类似的,所以你使用 autogui 会暂时失去对鼠标或键盘的控制。
如果不在意暂时失去鼠标或键盘的控制,autogui 就是非常好用了,直接通过控制键盘的方式,实现「键盘级」的复制粘贴,此时内容就会完全复制到不同平台相应编写内容的区域了,但这其实也隐藏着一个问题,就是操作对象必须获得了「焦点」,即浏览器要在所有窗口前,此时复制的内容才会被正确复制在浏览器对应的位置。
如果你使用 PyCharm 来运行该项目,此时代码无法完整的运行完,这是因为 PyCharm 无论是运行模式还是 Debug 模式,其实都占据了「焦点」,autogui 复制的内容会出现在 PyCharm 光标处。
代码分析
Selenium 二次封装
因为整个项目会经常使用 Selenium,为了让代码更加简洁,这里以单例模式创建浏览器实例并将 Selenium 的常用方法了二次封装。
简单看一下单例模式的实现方式,代码如下,其实就是利用了 __new__方法,先判断实例是否存在,不存在再创建。
class Driver(object):
_instance = None
driver = None
# Singleton mode
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Driver, cls).__new__(cls, *args, **kwargs)
cls.driver = cls._instance.initdriver()
return cls._instance
def initdriver(self, plug=False, brower='Chrome'):
if brower == 'Chrome':
option = webdriver.ChromeOptions()
# Remove warnings from browser that 'Chrome is under the control of automated software'
option.add_argument('disable-infobars')
# No interface
# option.add_argument('headless')
driver = webdriver.Chrome(executable_path=CHROMEDIRVER, chrome_options=option)
driver.set_window_size(1200, 900)
elif brower == 'FireFox':
if plug:
# open %APPDATA%\Mozilla\Firefox\Profiles\ find firefox plugin,then load plugin configuration.
firefox_plug_dir = ''
profile_directory = os.path.join(appdata, 'Mozilla\Firefox\Profiles', firefox_plug_dir)
profile = webdriver.FirefoxProfile(profile_directory)
# Launch browser
driver = webdriver.Firefox(firefox_profile=profile)
return driver
接着看一下对 Selenium 的二次封装,比如一些点击的操作,为了确保操作对象的存在,这里会先隐式判断元素是否存在,如果存在再点击
@run_time
def waitxpath(self, xpath):
try:
WebDriverWait(self.driver, WAITTIME, 1).until(
lambda x: x.find_element_by_xpath(xpath)
)
except:
traceback.print_exc()
return ERROR, 'waif xpath 20s timeout, try again'
return SUCCESS, 'wait xpath finish'
@run_time
def choice_select(self, xpath, content, sleeptime=0):
'''
Choick select element
:param xpath: select xpath
:param content: select value
'''
self.waitxpath(xpath)
select = Select(self.driver.find_element_by_xpath(xpath))
# select the value of text='xxx'
select.select_by_visible_text(content)
if sleeptime:
time.sleep(sleeptime)
tkinter 编写界面
为了方便使用,我还是 tkinter 编写了一个「很丑」的界面,之所以选择 tkinter 是因为它是 Python 的内置库,使用起来也比较简单。
使用 tkinter 制作界面有个关键点,就是不能让负责界面渲染的主线程执行耗时操作,不然,界面就会出现严重的卡顿现象,常规的做法就是开启一个新线程来负责耗时逻辑,然后通过全局变量在不同的线程之间传递数据,这个全局变量通常会定义为队列。
在登录不同平台时,如果遇到验证码也需要通过 tkinter 显示并获取验证码正确的值,此时可以使用 tkinter 的弹窗机制,弹出一个新窗口来显示验证码并获取验证码的真实值,实现如下:
class PopUpCaptchWindow(object):
'''
弹出验证码窗口
'''
def __init__(self,master, imgpath):
'''
:param master: 父窗口
:param imgpath: 图像路径(验证码图片路径)
'''
top=self.top=Toplevel(master)
self.l=Label(top,text="请输入验证码:")
self.l.pack()
im = Image.open(imgpath)
img = ImageTk.PhotoImage(im)
panel = Label(top, image=img)
panel.image = img
panel.pack(expand="yes")
self.e=Entry(top)
self.e.pack()
self.b=Button(top,text='确定',command=self.cleanup)
self.b.pack()
def cleanup(self):
self.value=self.e.get()
self.top.destroy()
尾
AutoPublish 本质其实是与不同平台做对抗,如果平台登录规则变动或发送文章的规则变动,AutoPublish 的逻辑就会失去效果,这不只是 AutoPublish 会面临的问题,任何爬虫项目都会面对这样的问题。
希望感兴趣的朋友为 AutoPublish 点个星,此外也欢迎关注 HackPython
最后再提一下,项目地址:https://github.com/ayuLiao/AutoPublish
智能推荐
文章发布留存待写
Chinar blog :www.chinar.xin Linq 函数大全教程 本文提供全流程,中文翻译 助力查询学习 LinQ 查询语句的具体用法、可用于备忘 为初学者节省宝贵的时间,避免采坑! Chinar —— 心分享、心创新! 我们的初衷是将一种简单的生活方式带给世人 使有限时间 具备无限可能 Chinar 教程效果: 文章目录 一 1. Where —...
protobuf多平台编译
protobuf下载 下载地址:https://github.com/protocolbuffers/protobuf/releases 本文使用的是protobuf-3.9.1版本,目前最新版本为3.11.2 Mac下编译步骤 解压 protobuf 源码压缩包,创建目标生成目录(目录名称为build_protobuf)。 编译configure 编译 查看build_protobuf目录下是否...
electron-builder打包linux桌面程序(OIM-E多平台即时通讯软件)
1、OIM-E 开源主页 主页链接 2、打包Linux 开始踩了几个坑,我图简单就非想要在windows打包linux包。结果就是不行,梯子啥的都挂了,结果无效。报如下错误: 大概是需要远程服务支撑,build。。agent。。代理什么,或许是云打包(个人猜测,有点像,UNIAPP,windows打包安卓,有这样的打包方式。) 然后上网查了下,这个服务在去年停止了。再次上线遥遥无期。 那么第二种解...
Linux环境下配置和安装hadoop及hadoop集群搭建(VMware)
文章目录 一、安装准备 二、hadoop的配置 1.首先配置hadoop-env.sh 2.配置core-site.xml 3.配置hdfs-site.xml 4.配置mapred-site.xml 5.配置yarn-site.xml 6.配置slaves 7.配置hadoop环境变量 三、格式化HDFS 四、启动hadoop 五、集群搭建 1.克隆虚拟机 2.配置免密登录 3.修改主机器的配置文...
使用QProcess打开和关闭第三方应用,比如CMD
使用QProcess打开和关闭第三方应用,比如CMD 注意: 很多教程不一定是对的,但我这篇绝对是对的,因为我踩坑过啊。 为了节省时间,直接上图、上代码,so easy! 重要事情说3遍: 杀死进程,一定要加/F 和 /T 杀死进程,一定要加/F 和 /T 杀死进程,一定要加/F 和 /T 开始 验证下,打开任务管理器就能看到 总结 从上面看,是不是很简单,taskkill不知道是啥,是windo...
猜你喜欢
自定义View实现注销图案的加载动画
先看效果图: 有那味了。。。(懂得都懂^ ^ √) 我们先来分析一下怎么画,然后再研究怎么让他动起来 这个View是由内部的注销图案和外面一圈圆环构成。而内部的注销图案又是由一个基本满角度的圆弧和一根竖线组成 一、绘制内部注销图案 首先初始化画笔和圆弧的外切矩形: 圆弧的中心是View的中心,坐标为(getWidth()/2,getWidth()/2),半径设置为getWidth/4,...
vue3使用vue-count-to组件
项目场景: 数据可视化大屏开发的过程中,需要实现一种滚动数字的效果,在使用vue2时,使用vue-count-to完全没有问题,功能也比较完善(滚动时长,开始值,结束值,前缀,后缀,千分隔符,小数分隔符等等),但是在vue3中使用会出现问题。 展示的效果 问题描述: 出现的错误时 == Cannot read property ‘_c’ of undefined== 这是一...
包的安装
包的分类: 包的安装方式: 1. yum 安装 不需要手动解决依赖关系 本地yum源配置:不需要网络 网络源配置 yum : 2. 源码安装 2.1 安装准备: 2.2 分析安装平台环境 查看安装平台参数,下载合适的包 2.3 下载源码包 根据查到的参数下载源码包,建议下载到/usr/local/src目录下 2.4 安装源码包 示例: 此处以apache http示例:https://mirro...
李洪义机器学习课程(一)——Learning Map学习笔记
我们先一张一张PPT来分析讲解[1]。 总体框图 : 这张图表明了接下来的知识脉络体系,也可以看成目前学术界、工业界的几大研究方向。整体上分为: 监督学习、半监督学习、无监督学习、迁移学习、强化学习。 对于监督学习又分为:回归、分类、结构化学习[2] 对于分类问题,整体上分为线性模型和非线性模型,非线性模型包括深度学习、SVM、决策树、KNN等。 接下来一个一个说明。 李大大对回归有一个例子...
