微信文章自动采集软件(微信公众号爬取程序分享搞成java的难点在于)
优采云 发布时间: 2022-01-17 17:22微信文章自动采集软件(微信公众号爬取程序分享搞成java的难点在于)
最近需要爬取微信公众号的文章信息。我在网上搜索,发现爬取微信公众号的难点在于公众号文章的链接在PC端打不开,所以需要使用微信自带的浏览器(获取参数辅以微信客户端,只能在其他平台打开),给爬虫带来了很大的麻烦。后来在知乎上看到一个大牛用php写的微信公众号爬虫程序,直接按照大佬的思路做成了java。改造过程中遇到了很多细节和问题,就分享给大家。
系统的基本思路是在Android模拟器上运行微信,在模拟器上设置代理,通过代理服务器截取微信数据,将获取到的数据发送给自己的程序进行处理。
需要准备的环境:nodejs、anyproxy代理、安卓模拟器
Nodejs下载地址:我下载的是windows版本的,直接安装就好了。安装后直接运行 C:\Program Files\nodejs\npm.cmd 会自动配置环境。
anyproxy安装:按照上一步安装nodejs后,直接在cmd中运行npm install -g anyproxy即可安装
网上的安卓模拟器就好了,有很多。
首先安装代理服务器的证书。Anyproxy 默认不解析 https 链接。安装证书后,就可以解析了。在cmd中执行anyproxy --root安装证书,然后在模拟器中下载证书。
然后输入anyproxy -i 命令打开代理服务。(记得添加参数!)
记住这个ip和端口,那么安卓模拟器的代理就会用到这个。现在用浏览器打开网页::8002/ 这是anyproxy的网页界面,用来显示http传输的数据。
点击上方红框中的菜单,会出现一个二维码。用安卓模拟器扫码识别。模拟器(手机)会下载证书并安装。
现在准备为模拟器设置代理,代理模式设置为手动,代理ip为运行anyproxy的机器的ip,端口为8001
准备工作到这里基本完成。在模拟器上打开微信,打开一个公众号的文章,就可以从刚刚打开的web界面看到anyproxy抓取的数据:
上图红框是微信文章的链接,点击查看具体数据。如果响应正文中没有任何内容,则可能是证书安装有问题。
如果顶部清晰,您可以向下。
这里我们依靠代理服务来抓取微信数据,但是我们不能抓取一条数据自己操作微信,所以还是手动复制比较好。所以我们需要微信客户端自己跳转到页面。这时可以使用anyproxy拦截微信服务器返回的数据,将页面跳转代码注入其中,然后将处理后的数据返回给模拟器,实现微信客户端的自动跳转。
在anyproxy中打开一个名为rule_default.js的js文件,windows下的文件为:C:\Users\Administrator\AppData\Roaming\npm\node_modules\anyproxy\lib
文件中有一个方法叫做replaceServerResDataAsync: function(req,res,serverResData,callback)。该方法负责对anyproxy获取的数据进行各种操作。开头应该只有 callback(serverResData) ;该语句的意思是直接将服务器响应数据返回给客户端。直接把这条语句删掉,换成下面大牛写的代码。这里的代码我没有做任何改动,里面的注释也解释的很清楚。顺着逻辑去理解就好,问题不大。
replaceServerResDataAsync: function(req,res,serverResData,callback){
if(/mp\/getmasssendmsg/i.test(req.url)){//当链接地址为公众号历史消息页面时(第一种页面形式)
//console.log("开始第一种页面爬取");
if(serverResData.toString() !== ""){
6 try {//防止报错退出程序
var reg = /msgList = (.*?);/;//定义历史消息正则匹配规则
var ret = reg.exec(serverResData.toString());//转换变量为string
HttpPost(ret[1],req.url,"/InternetSpider/getData/showBiz");//这个函数是后文定义的,将匹配到的历史消息json发送到自己的服务器
var http = require('http');
http.get('http://xxx/getWxHis', function(res) {//这个地址是自己服务器上的一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxHis.php的原理。
res.on('data', function(chunk){
callback(chunk+serverResData);//将返回的代码插入到历史消息页面中,并返回显示出来
})
});
}catch(e){//如果上面的正则没有匹配到,那么这个页面内容可能是公众号历史消息页面向下翻动的第二页,因为历史消息第一页是html格式的,第二页就是json格式的。
//console.log("开始第一种页面爬取向下翻形式");
try {
var json = JSON.parse(serverResData.toString());
if (json.general_msg_list != []) {
HttpPost(json.general_msg_list,req.url,"/xxx/showBiz");//这个函数和上面的一样是后文定义的,将第二页历史消息的json发送到自己的服务器
}
}catch(e){
console.log(e);//错误捕捉
}
callback(serverResData);//直接返回第二页json内容
}
}
//console.log("开始第一种页面爬取 结束");
}else if(/mp\/profile_ext\?action=home/i.test(req.url)){//当链接地址为公众号历史消息页面时(第二种页面形式)
try {
var reg = /var msgList = \'(.*?)\';/;//定义历史消息正则匹配规则(和第一种页面形式的正则不同)
var ret = reg.exec(serverResData.toString());//转换变量为string
HttpPost(ret[1],req.url,"/xxx/showBiz");//这个函数是后文定义的,将匹配到的历史消息json发送到自己的服务器
var http = require('http');
http.get('xxx/getWxHis', function(res) {//这个地址是自己服务器上的一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxHis.php的原理。
res.on('data', function(chunk){
callback(chunk+serverResData);//将返回的代码插入到历史消息页面中,并返回显示出来
})
});
}catch(e){
//console.log(e);
callback(serverResData);
}
}else if(/mp\/profile_ext\?action=getmsg/i.test(req.url)){//第二种页面表现形式的向下翻页后的json
try {
var json = JSON.parse(serverResData.toString());
if (json.general_msg_list != []) {
HttpPost(json.general_msg_list,req.url,"/xxx/showBiz");//这个函数和上面的一样是后文定义的,将第二页历史消息的json发送到自己的服务器
}
}catch(e){
console.log(e);
}
callback(serverResData);
}else if(/mp\/getappmsgext/i.test(req.url)){//当链接地址为公众号文章阅读量和点赞量时
try {
HttpPost(serverResData,req.url,"/xxx/getMsgExt");//函数是后文定义的,功能是将文章阅读量点赞量的json发送到服务器
}catch(e){
}
callback(serverResData);
}else if(/s\?__biz/i.test(req.url) || /mp\/rumor/i.test(req.url)){//当链接地址为公众号文章时(rumor这个地址是公众号文章被辟谣了)
try {
var http = require('http');
http.get('http://xxx/getWxPost', function(res) {//这个地址是自己服务器上的另一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxPost.php的原理。
res.on('data', function(chunk){
callback(chunk+serverResData);
})
});
}catch(e){
callback(serverResData);
}
}else{
callback(serverResData);
}
//callback(serverResData);
},
这是一个简短的解释。微信公众号历史新闻页面的链接有两种形式:一种以/mp/getmasssendmsg开头,另一种以/mp/profile_ext开头。历史页面可以向下滚动。向下滚动会触发js事件发送请求获取json数据(下一页的内容)。还有公众号文章的链接,以及文章的阅读和点赞链接(返回json数据)。这些环节的形式是固定的,可以通过逻辑判断加以区分。这里有个问题,如果历史页面需要一路爬取怎么办。我的想法是通过js模拟鼠标向下滑动,从而触发请求提交下一部分列表的加载。或者直接使用anyproxy分析下载请求,直接向微信服务器发出这个请求。但是有一个问题是如何判断没有剩余数据。我正在抓取最新数据。我暂时没有这个要求,但以后可能需要。如果需要,您可以尝试一下。