python构建微信公众号文章发表控制台应用

使用Python构建控制台应用,简单一点.主目的是抓取某个网站图片然后上传到素材.

流程

获取access token

首先需要知道自己的开发者AppID和开发者密码AppSecret.

然后获取access token

https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数是否必须说明
grant_type获取access_token填写client_credential
appid第三方用户唯一凭证
secret第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,微信会返回下述 JSON 数据包给公众号:

1
{"access_token":"ACCESS_TOKEN","expires_in":7200}

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为 AppID 无效错误):

1
{"errcode":40013,"errmsg":"invalid appid"}

素材管理

新增永久素材

对于常用的素材,开发者可通过本接口上传到微信服务器,永久使用。新增的永久素材也可以在公众平台官网素材管理模块中查询管理。

通过 POST 表单来调用接口,表单 id 为media,包含需要上传的素材内容,有filename、filelength、content-type等信息。

请注意:图片素材将进入公众平台官网素材管理模块中的默认分组。也就是说现在还不支持上传素材时创建分组.不过问题不大,到时候写文章时手动

http请求方式: POST,需使用https https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE

参数是否必须说明
access_token调用接口凭证
type媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
mediaform-data中媒体文件标识,有filename、filelength、content-type等信息

新增永久视频素材需特别注意

在上传视频素材时需要 POST 另一个表单,id为description,包含素材的描述信息,内容格式为JSON,格式如下:

1
2
3
4
{
"title":VIDEO_TITLE,
"introduction":INTRODUCTION
}
参数是否必须说明
title视频素材的标题
introduction视频素材的描述

返回说明

1
2
3
4
{
"media_id":MEDIA_ID,
"url":URL
}

获取素材总数

永久素材的总数,也会计算公众平台官网素材管理中的素材 2.图片和图文消息素材(包括单图文和多图文)的总数上限为100000,其他素材的总数上限为1000 3.调用该接口需 https 协议

接口调用请求说明

http请求方式: GET https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN

使用库

requests发送http请求,lxml解析html,tqdm显示进度条.

主要功能 爬取某个网站的所有图片,将某个文件夹下的图片全部上传.

一天随便写了写,比较菜还请见谅.

用户类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import sys
import requests
class User:
def __init__(self):
self.access_token = None
self.__appId = input('请输入您的appid:')
self.__appSecret = input('请输入您的appsecret:')
self.logintime = 3
self.login()

def login(self):
while self.logintime:
try:
res = requests.get(
f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={self.__appId}&secret={self.__appSecret}", )
if res.status_code == 200:
self.access_token = res.json()['access_token']
else:
print('输入错误!请尝试再次输入,还剩' + self.logintime + '次机会')
except Exception as e:
print('错误', res.json(), e)
self.logintime = self.logintime - 1

def quit(self):
print('退出')
sys.exit(0)

这里就是注册 没什么好说的 可以增加一个错误机会.

获取图片类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os.path
import tqdm
import requests
from lxml import etree
import sys


class Article:
def __init__(self):
self.__url = None
self.title = None
self.__header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54'
}
self.filepathList = set()
self.getUpdated()

def getUpdated(self):
url = 'https://www.pixivision.net/zh/c/illustration'
res = requests.get(url,headers=self.__header)
selector = etree.HTML(res.text)
lastUpdatedNumber = selector.xpath("//li[@class='article-card-container'][1]/article/div[@class='arc__thumbnail-container']/a[1]/@href")[0]
lastUpdatedNumber = lastUpdatedNumber.split('/')[-1]
print('最新的图文号为',lastUpdatedNumber)

def getarticle(self):
self.__url = input('输入网站链接(仅限pixvision:https://www.pixivision.net/zh/a/number):')
if self.__url.isnumeric():
self.__url = 'https://www.pixivision.net/zh/a/' + self.__url
try:
res = requests.get(self.__url, headers=self.__header)
except requests.exceptions.ProxyError as e:
print('网络出现问题', e)
sys.exit(-1)
return
except Exception as e:
print('出错', e)
sys.exit(-1)
return
selector = etree.HTML(res.text)
imgLinks = selector.xpath(
"////div[@class='_feature-article-body']/div[@class='article-item _feature-article-body__pixiv_illust']//div[@class='am__work__main']//img/@src") # 返回为一列表
self.title = selector.xpath("//h1[@class='am__title']/text()")
self.download(imgLinks)

def download(self, imgLinks):
filepath = input('输入下载的目录路径(默认F:\公众号\图片):')

if not os.path.exists(filepath):
print('目录输入错误')
return
absfilepath = filepath + f'\\{self.title}'
if os.path.exists(absfilepath):
# 清空文件夹中的文件
print('清空文件夹中的文件')
del_list = os.listdir(absfilepath)
for f in del_list:
file_path = os.path.join(absfilepath, f)
if os.path.isfile(file_path):
os.remove(file_path)
else:
print('生成文件夹')
os.mkdir(absfilepath)
self.filepathList.add(absfilepath)
self.__header['Referer'] = 'https://www.pixiv.net/'
pbar = tqdm.tqdm(imgLinks)
total = len(imgLinks)
for index, link in enumerate(pbar):
filename = link.split('/')[-1]
pbar.set_description("正在下载%s," % filename)
pbar.set_postfix({'current': index + 1, 'total': total})
try:
res = requests.get(link, headers=self.__header)
with open(absfilepath + f'\\{filename}', 'wb+') as f:
f.write(res.content)
except Exception as e:
print('需要设置代理', e)

这里主要利用xpath解析获取到的网页.

上传素材类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import tqdm
import requests
import os


class upload:
def __init__(self, ACCESS_TOKEN, FILEPATHLIST):
self.url = f'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={ACCESS_TOKEN}&type' \
f'=image'
self.filepath = FILEPATHLIST
self.uploadPics()

def uploadPics(self):

if isinstance(self.filepath, str):
self.uploadPic(self.filepath)
else:
for f in self.filepath:
self.uploadPic(f)

def uploadPic(self, filepath):
if os.path.isdir(filepath):
filelist = os.listdir(filepath)
total = len(filelist)
pbar = tqdm.tqdm(filelist)
for index, f in enumerate(pbar):
file_path = os.path.join(filepath, f)
if os.path.isfile(file_path):
with open(file_path, 'rb') as file:
files = {
'media': file
}
res = requests.post(self.url, files=files)
pbar.set_description('正在上传' + res.json()['url'])
pbar.set_postfix({'current': index + 1, 'total': total})
else:
print('文件夹错误', filepath)

注意:requests上传FormData 需要利用files

主文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time
from user import User
from getpic import Article
from uploadpic import upload

if __name__ == "__main__":
uploadDownloadpic = '0'
if input('直接上传图片?0表示直接上传,1表示下载\n') == '1':
article = Article()
while True:
article.getarticle()
doContinue = input('是否继续下载图片?1表示继续,0表示退出\n')
if doContinue != '1':
break
uploadDownloadpic = input('是否上传刚才的图片?1表示是,0表示自己选择\n')
u = User()
if uploadDownloadpic == '1':
upload(u.access_token, article.filepathList)
else:
filepath = input('输入需要上传的文件目录(单个):\n')
upload(u.access_token, filepath)

总结

只是连续写了一会就累了,最近有点忙,利用这个工具上传素材到微信公众号方便水文章.最后可以利用pyinstaller打包

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道