使用Selenium、Mitmproxy和Wechatarticles实现微信公众号文章爬取与自动采集

[id_1461198[id_1598245296]68]
python爬取微信公众号文章(包含文章内容和图片)
记一次微信公众号爬虫的经历(微信文章阅读点赞的获取)
微信公众号文章可以通过全自动采集的方式来获取。具体来说,是使用 mitmproxy 进行抓包,接着利用 pywinauto 来实现自动点击,从而获取微信 app_msg 的动态。
selenium
selenium 拥有一个官网,建议以官网的教程作为入门途径。开始入门主要包含两步(我使用的是 python),其一为安装 python 的包,其二是需要下载浏览器的驱动文件,同时要设置好环境变量。
mitmproxy
mitmproxy 拥有一个官网。在官网文档的“Getting Started”部分中有所记载,它会默认监听本地的 8080 端口。有了这个代理后,我们便能够获取网络传输过程中的数据包。要将其运用起来,就需要对代理进行设置。由于后面需要对微信客户端的数据包收发进行监听,所以我直接对系统的代理进行了设置。
在 windows 桌面的搜索栏中进行搜索,搜索的内容为“代理”,这样就能找到“代理服务器设置”,之后可以手动按照如图所示来设置代理。
具体实现流程
具体步骤分为两步:
文章链接获取
按照第一篇参考文章的方法来获取文章链接。需注意,具备微信和一个邮箱,便能注册一个订阅号。此邮箱绑定订阅号后,就不能再用于绑定其他事物,例如小程序。起初,我的微信用一个邮箱绑定了一个小程序,接着在微信登录时,始终只有小程序的选项。这个时候只需再去弄一个邮箱,接着注册一个订阅号便可以了。
公众号管理界面或许与上面文章中提及的有所不同,但实际上差异较小。依旧只需通过创建新的图文消息,便可进入公众号文章链接所引用的界面。
利用 login.py 这个文件来获取所有文章链接。首先通过 login.py 获取 cookies 。接着利用 get_article_link.py 获取文章链接。在使用过程中发现,此网页存在反爬机制,出现错误后需等待几个小时再继续。
我用的是 Edge 浏览器,这与参考的文章不同。并且,我在获取文章链接的同时,还获取了文章的发布时间。具体的参数需参考原文。
# -!- coding: utf-8 -!-
# login.py 用于保存微信帐号登录信息
# 以下代码中的微信登录帐号密码需要修改
from selenium import webdriver
import time
import json
driver = webdriver.Edge()
driver.get("https://mp.weixin.qq.com/") # 微信公众平台网址
driver.find_element_by_link_text("使用帐号登录").click() # 切换到用帐号密码登录
driver.[id_1007229423]("account").clear()
driver.find_element_by_name("account").send_keys("帐号") # 自己的微信公众号
time.sleep(2)
driver.find_element_by_name("password").clear()
driver.find_element_by_name("password").send_keys("密码") # 自己的微信公众号密码
driver.find_element_by_class_name("icon_checkbox").click()
time.sleep(2)
driver.find_element_by_class_name("btn_login").click()
time.sleep(15)
#此时会弹出扫码页面,需要微信扫码
cookies = driver.get_cookies() # 获取登录后的cookies
print(cookies)
cookie = {}
for items in cookies:
cookie[items.get("name")] = items.get("value")
把 cookies 写入到本地文件,以便后续程序在访问公众号时能够携带这些 cookies 作为身份识别的依据。
with open('cookies.txt', "w") as file:
# 写入转成字符串的字典
file.write(json.dumps(cookie))
# -*- coding:utf-8 -*-
# get_article_link.py
# 参考第一篇文章链接,需要对一些参数进行修改
# 在参考文章的基础上,增加了文章发布时间的条目
import requests
import json
import re
import time
with open("cookies.txt", "r") as file:
cookie = file.read()
cookies = json.loads(cookie)
url = "https://mp.weixin.qq.com"
response = requests.get(url, cookies=cookies)
print(response.url)
token = re.findall(r'token=(\d+)', str(response.url))[0] # 从url中获取token
headers = {
"User-Agent": Mozilla/5.0 表示这是 Mozilla 公司的产品。其运行在 Windows NT 10.0 系统上,且为 64 位的 Windows 系统(Win64),同时也是 x64 架构。浏览器的内核是 AppleWebKit/537.36,其具有 KHTML 风格且类似 Gecko。当前使用的浏览器是 Chrome,版本为 94.0.4606.81,同时还有 Safari/537.36 相关标识,而 Edg 的版本是 94.0.992.50。, # 需要根据需求修改
"Referer": https://mp.weixin.qq.com/cgi-bin/appmsg ,其后是 t=media/appmsg_edit_v2 ,接着是 action=edit ,还有 isNew=1 ,以及 type=77 ,最后是 createType=0 ,并且 token= 。+token+"&lang=zh_CN", # 需要根据需求修改
"Host": "mp.weixin.qq.com",
}
with open('article_link.txt', "w", encoding='utf-8') as file:
for j in range(1, 53, 1): # 循环次数根据实际情况进行设置
begin = (j-1)*5
requestUrl = 这是一个链接,其格式为“https://mp.weixin.qq.com/cgi-bin/appmsg?action=list_ex&begin=”,其中包含了微信公众平台的相关信息和操作指令。+str(begin)+count 为 5,fakeid 是 MzU4MjY2OTY2NQ==,type 是 9,query 为空,token 为空。+token+"&lang=zh_CN&f=json&ajax=1"
search_response = requests.get(requestUrl, cookies=cookies, headers=headers)
re_text = search_response.json()
list = re_text.get("app_msg_list")
for i in list:
timestr = i["create_time"]
timeArray = time.localtime(int(timestr))
otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray) # 文章发布时间
file.write(i["aid"]+"<=====>"+i["title"]+"<=====>"+i["link"] + "<=====>" + otherStyleTime + "\n")
print(i["aid"]+"<=====>"+i["title"]+"<=====>"+i["link"] + "<=====>" + otherStyleTime)
time.sleep(20)
可以将获得的文本文件导入 Excel 并做成表格。在 Excel 里选择从文本导入数据,将分隔符设置为“”。我在导入时遇到了一些问题,即有些地方 Excel 不识别这个分割符号。于是我把文本文件中的“”“”“”全部替换成分号,之后再用 Excel 导入就没有问题了。
获取文章信息
获取文章信息是以参考第二和第三篇文章为基础的。若要获取微信公众号文章的阅读量、点赞等信息,在浏览器中打开微信公众号文章是无法获取到的。只有通过微信打开,才能够拿到这些信息。因此,在第三篇文章中,原作者制作了一个自动控制微信的脚本,通过在文件传输助手中点击文章链接,从而产生带 cookie 和 appmsg_token 的包。如果文章数量较少,其实能够手动点击。经测试,每次获取到的 cookie 和 appmsg_token 至少能用以获取 100 篇文章的信息。
# -*- coding:utf-8 -*-
# write_cookies.py
import urllib
import sys
from mitmproxy import ctx
from mitmproxy import io, http
mitmdump 使用 write_cookies.py 脚本,将数据保存到 dat 文件中,目标是 mp.weixin.qq.com/mp/getappmsgext
class WriterCookie:
"""
mitmproxy 的监听脚本能够将 cookie 和 url 写入到文件中。
"""
def __init__(self,outfile: str) -> None:
self.f = open(outfile, "w")
def response(self, flow: http.HTTPFlow) -> None:
"""
完整的response响应
:param flow: flow实例,
"""
# 获取url
url = urllib.parse.unquote(flow.request.url)
# 将url和cookie写入文件
if "微信公众号的链接为 mp.weixin.qq.com/mp/getappmsgext" in url:
self.f.write(url + '\n')
self.f.write(str(flow.request.cookies))
self.f.close()
# 退出
exit()
# 第四个命令中的参数
addons = [WriterCookie(sys.argv[4])]
write_cookies.py 是 mitmproxy 的监听脚本。从下面的命令可以看出来,当它监听到“mp.weixin.qq.com/mp/getappmsgext”这种请求包时,就会把请求包的内容保存下来。这种请求就是每次微信打开公众号文章时发出的请求包。
使用 mitmdump 命令,指定 -s 参数为当前目录下的./cookie.txt 路径中的 write_cookies.py 文件,同时指定 -w 参数为指定的文件路径,这里是 mp.weixin.qq.com/mp/getappmsgext 这个网址对应的文件,执行 mitmdump 命令。
# -*- coding:utf-8 -*-
# get_Info.py
import re
import os
import threading
from wechatarticles import ArticlesInfo
import time
class ReadCookie(object):
"""
启动 write_cookie.py ,然后对 cookie 文件进行解析。
"""
def __init__(self,outfile):
self.outfile = outfile
print(self.outfile)
def parse_cookie(self):
"""
解析cookie
返回 appmsg_token、biz 和 cookie_str。
"""
with open(self.outfile) as f:
data = f.read()
appmsg_token_string = re.findall("appmsg_token.+?&", data)[0].split('=')[1]
cookies = re.findall(r"\['(.*?)'\]", data)
Wechat_cookies = {}
for cookie in cookies:
cookie = cookie.split("', '")
Wechat_cookies[cookie[0]] = cookie[1]
return appmsg_token_string,Wechat_cookies
def write_cookie(self):
"""
启动 write_cookies。py
:return:
"""
#当前文件路径
path = os.path.split(os.path.realpath(__file__))[0]
#path = os.getcwd()
print(path)
mitmdump 执行脚本,同时将结果保存到文件,这就是本命令的作用。
command = mitmdump 使用 -s 参数指定脚本路径为 {} 中的 write_cookies.py,同时使用 -w 参数指定输出文件路径为 {},目标地址为 mp.weixin.qq.com/mp/getappmsgext.format(
path,self.outfile)
os.system(command)
def get_cookie():
rc = ReadCookie('cookie.txt')
rc.write_cookie()
appmsg_token_string, cookies = rc.parse_cookie()
return appmsg_token_string, cookies
fp_src = open('links.txt', 'r')
fp_dst = open('articleInfo.txt', 'w')
count = 0
while True:
# 登录微信PC端获取文章信息
appmsg_token, cookies = get_cookie()
# print(appmsg_token_string)
cookie = ''
for ck in cookies.items():
if not cookie:
cookie = cookie + ck[0] + '=' + ck[1]
else:
cookie = cookie + '; ' + ck[0] + '=' + ck[1]
print(cookie)
for i in range(100):
url = fp_src.readline()
if not url:
break
article_url = url
test = ArticlesInfo(appmsg_token, cookie)
read_num, like_num, old_like_num = test.read_like_nums(article_url)
count = count + 1
print(str(count) + " read_like_num:", read_num, like_num, old_like_num)
fp_dst.write(str(read_num) + ';' + str(like_num) + ';' + str(old_like_num) + '\n')
time.sleep(3)
解析监听到的包后,能够获取所需的 cookie 和 appmsg_token。接着,利用这些获取微信公众号的文章信息。重复 100 次此操作后,再更新 cookie 和 appmsg_token。在此之前,已事先将所有文章的链接存储到文本文件“links.txt”中,每次从该文件中读取一行,即为一个文章链接。
每到 100 条记录之后,我会手动点击这个文件传输窗口中的链接。每当命令行提示下面的信息时,我就会点击上面文件传输助手中的链接来更新 cookie 和 appmsg_token。