分享文章:anyproxy批量自动采集微信公众号文章

优采云 发布时间: 2022-12-26 06:37

  分享文章:anyproxy批量自动采集微信公众号文章

  我从2014年开始做微信公众号内容的批量采集,最初的目的是做一个html5的垃圾网站。 当时垃圾站采集的微信公众号内容很容易在公众号传播。 那时候批量采集特别好做,采集入口就是公众号的历史新闻页。 这个入口现在还是一样,只是越来越难采集了。 采集方式也更新了多个版本。 后来2015年html5垃圾站下线,采集目标定位到本地新闻资讯公众号,前端展示做成app。 于是一个可以自动采集号内容的新闻APP就形成了。 我曾经担心有一天,微信技术升级后,我无法再采集内容,我的新闻应用程序将失效。 不过随着微信技术的不断升级,采集方式也升级了,这让我越来越有信心了。 只要公众号的历史新闻页面存在,就可以批量采集内容。 所以今天决定把采集的方法整理后记下来。 我的方法来自于很多同事的分享精神,所以我会延续这种精神,分享我的成果。

  文章会持续更新,保证您所见即所得。

  首先我们来看一个微信公众号历史新闻页面的链接地址:

  http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MjM5MzczNjY2NA==#wechat_webview_type=1&wechat_redirect

  =========2017年1月11日更新=========

  现在,根据不同的微信个人账号,会有两个不同的历史新闻页面地址。 以下是另一个历史新闻页面的地址。 首地址的链接在anyproxy中会显示302跳转:

  https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzA3NDk5MjYzNg==&scene=124#wechat_redirect

  第一个链接地址的页面样式:

  第二个链接地址的页面样式:

  根据目前掌握的信息,这两种页面格式不定期出现在不同的微信ID中。 有的微信号永远是第一页格式,有的永远是第二页格式。

  上面的链接是一个微信公众号历史新闻页面的真实链接,但是当我们在浏览器中输入这个链接时,会显示:请从微信客户端访问。 这是因为链接地址实际上需要几个参数才能正常显示内容。 我们来看看一个完整的可以正常显示内容的链接长什么样子:

  //第一种链接

http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MjM5NTM1NjczMw==&uin=NzM4MTk1ODgx&key=a226a081696afed0d9dfa0972fa431e116e5c4572ce52343178ad4e9a2b94aeaad6ac4dd87de3e56f72209a73a32e9cc2052f68aca4884e36cf726e99f2671630c741d8e4c29abe4a049d1a71eeb2be5&devicetype=android-17&version=2605033c&lang=zh_CN&nettype=WIFI&ascene=1&pass_ticket=zbA7PswOPKySRpyEYI5kDCjRiljxcpzdbTuVMauFGemgdp8R1DY1uQY49srehWab&wx_header=1

//第二种

http://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzA3NDk5MjYzNg==&scene=124&uin=NzM4MTk1ODgx&key=5134ab1cc362a0324183dbd55a2680d11ccbaa34cdb349ee9be58f5b666092ddb17adf8a88dc788831923f3c6087547d651f04209f72334d511c9e118a3800d7b05a324a38903f79cff940cf749ecd5a&devicetype=android-17&version=2605033c&lang=zh_CN&nettype=WIFI&a8scene=3&pass_ticket=Fo3zjtJcbPfijNHKUIQbV%2BeHsAqhbjJCwzTfV48u%2FCZRRGTmI8oqmHDxxfEL8ke%2B&wx_header=1

  该地址是通过微信客户端打开历史消息页面后,使用后面介绍的代理服务器软件获取的。 这里有几个参数:

  action=;__biz=;uin=;key=;devicetype=;version=;lang=;nettype=;scene=;pass_ticket=;wx_header=;

  重要的参数是:__biz;uin=;key=;pass_ticket=; 这四个参数。

  __biz是类似于公众号id的参数。 每个公众号都有一个微信业务。 目前公众号biz发生变化的概率很小;

  剩下的3个参数是指用户的id和token ticket。 这3个参数的值由微信客户端生成后自动添加到地址栏。 所以我们要采集公众号,就必须要用微信客户端。 在之前的微信版本中,这3个参数可以获取一次,在有效期内可以被多个公众号使用。 当前版本已经在每次访问公众号时更改参数值。

  我现在使用的方法只需要关注参数__biz。

  我的采集系统由以下部分组成:

  1、微信客户端:可以是安装了微信的手机,也可以是电脑上的安卓模拟器。 经过实测,ios版微信客户端在批量采集过程中崩溃率高于安卓系统。 为了降低成本,我使用了 Android 模拟器。

  2.一个微信个人号:要采集内容,不仅需要微信客户端,还需要一个采集专用的微信个人号,因为这个微信号不能做其他事情。

  3、本地代理服务器系统:目前采用的方式是通过Anyproxy代理服务器将公众号历史新闻页面的文章列表发送到自己的服务器。 具体的安装和设置方法后面会详细介绍。

  4.文章列表分析入库系统:本人使用php语言编写,后面的文章会详细介绍如何分析文章列表,建立采集队列,实现批量采集内容。

  步

  1.安装模拟器或使用手机安装微信客户端,申请微信个人账号并登录。 关于这一点我就不过多介绍了,大家会的。

  2.代理服务器系统安装

  目前我使用的是Anyproxy,AnyProxy。 本软件的特点是可以获取https链接的内容。 2016年初,微信公众号和微信文章开始使用https链接。 而Anyproxy可以通过修改规则配置在公众号页面插入脚本代码。 让我们开始安装和配置过程。

  1.安装Node.js

  2、在命令行或终端运行npm install -g anyproxy,mac系统需要sudo;

  3、生成RootCA,https需要这个证书:运行命令sudo anyproxy --root(windows可能不需要sudo);

  4.启动anyproxy,运行命令:sudo anyproxy -i; 参数-i表示解析HTTPS;

  5.安装证书,在手机或者安卓模拟器中安装证书:

  6.设置代理:安卓模拟器的代理服务器地址为wifi链接的网关。 可以通过dhcp设置为static查看网关地址。 看完之后别忘了设置成自动。 手机中的代理服务器地址是运行anyproxy的电脑ip地址。 代理服务器默认端口为8001;

  现在打开微信,点击任意公众号历史消息或文章,即可在终端看到相应的代码滚动。 如果没有出现,请检查手机的代理设置是否正确。

  现在打开浏览器地址localhost:8002就可以看到anyproxy的web界面了。 从微信点击打开一个历史消息页面,然后看浏览器的网页界面,历史消息页面的地址会滚动。

  /mp/getmasssendmsg开头的URL为微信历史消息页面。 左边的小锁表示这个页面是用https加密的。 现在我们点击这一行;

  =========2017年1月11日更新=========

  一些以/mp/getmasssendmsg开头的URL会有302重定向,跳转到以/mp/profile_ext?action=home开头的地址。 所以点击这个地址可以看到内容。

  如果右侧出现html文件的内容,则说明解密成功。 如果没有内容,请检查anyproxy的运行方式是否有参数i,CA证书是否生成,手机是否正确安装证书。

  现在我们手机里的一切都可以明文通过代理服务器。 接下来我们需要修改配置代理服务器,这样才能获取到公众号的内容。

  1、找到配置文件:

  配置文件在mac系统中的位置是/usr/local/lib/node_modules/anyproxy/lib/; 不懂windows系统请见谅。 根据mac-like文件夹地址应该可以找到这个目录。

  2.修改文件rule_default.js

  找到 replaceServerResDataAsync: function(req,res,serverResData,callback) 函数

  修改函数内容(请详细阅读注释,这里只是介绍原理,理解后根据自己的情况修改内容):

  =========2017年1月11日更新=========

  因为有两个页面表单,同一个页面表单总是显示在不同的微信ID中,但是为了兼容这两个页面表单,下面的代码会保留对两个页面表单的判断,你也可以使用你的自己的页面表单删除 li

  replaceServerResDataAsync: function(req,res,serverResData,callback){

if(/mp\/getmasssendmsg/i.test(req.url)){//当链接地址为公众号历史消息页面时(第一种页面形式)

if(serverResData.toString() !== ""){

try {//防止报错退出程序

var reg = /msgList = (.*?);/;//定义历史消息正则匹配规则

var ret = reg.exec(serverResData.toString());//转换变量为string

HttpPost(ret[1],req.url,"getMsgJson.php");//这个函数是后文定义的,将匹配到的历史消息json发送到自己的服务器

var http = require('http');

http.get('http://xxx.com/getWxHis.php', function(res) {//这个地址是自己服务器上的一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxHis.php的原理。

res.on('data', function(chunk){

callback(chunk+serverResData);//将返回的代码插入到历史消息页面中,并返回显示出来

})

});

}catch(e){//如果上面的正则没有匹配到,那么这个页面内容可能是公众号历史消息页面向下翻动的第二页,因为历史消息第一页是html格式的,第二页就是json格式的。

try {

var json = JSON.parse(serverResData.toString());

if (json.general_msg_list != []) {

HttpPost(json.general_msg_list,req.url,"getMsgJson.php");//这个函数和上面的一样是后文定义的,将第二页历史消息的json发送到自己的服务器

}

}catch(e){

console.log(e);//错误捕捉

}

callback(serverResData);//直接返回第二页json内容

}

}

}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,"getMsgJson.php");//这个函数是后文定义的,将匹配到的历史消息json发送到自己的服务器

var http = require('http');

http.get('http://xxx.com/getWxHis', function(res) {//这个地址是自己服务器上的一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxHis.php的原理。

res.on('data', function(chunk){

callback(chunk+serverResData);//将返回的代码插入到历史消息页面中,并返回显示出来

})

});

}catch(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,"getMsgJson.php");//这个函数和上面的一样是后文定义的,将第二页历史消息的json发送到自己的服务器

}

}catch(e){

console.log(e);

}

callback(serverResData);

}else if(/mp\/getappmsgext/i.test(req.url)){//当链接地址为公众号文章阅读量和点赞量时

try {

HttpPost(serverResData,req.url,"getMsgExt.php");//函数是后文定义的,功能是将文章阅读量点赞量的json发送到服务器

}catch(e){

<p>

}

callback(serverResData);

}else if(/s\?__biz/i.test(req.url) || /mp\/rumor/i.test(req.url)){//当链接地址为公众号文章时(rumor这个地址是公众号文章被辟谣了)

try {

var http = require(&#39;http&#39;);

http.get(&#39;http://xxx.com/getWxPost.php&#39;, function(res) {//这个地址是自己服务器上的另一个程序,目的是为了获取到下一个链接地址,将地址放在一个js脚本中,将页面自动跳转到下一页。后文将介绍getWxPost.php的原理。

res.on(&#39;data&#39;, function(chunk){

callback(chunk+serverResData);

})

});

}catch(e){

callback(serverResData);

}

}else{

callback(serverResData);

}

},

</p>

  上面的代码是使用anyproxy修改返回页面内容的功能,在页面中注入脚本,将页面内容发送给服务器。 利用这个原理批量采集公众号内容和阅读量。 该脚本中自定义了一个函数,下面详细介绍:

  在 rule_default.js 文件末尾添加以下代码:

  function HttpPost(str,url,path) {//将json发送到服务器,str为json内容,url为历史消息页面地址,path是接收程序的路径和文件名

var http = require(&#39;http&#39;);

var data = {

str: encodeURIComponent(str),

url: encodeURIComponent(url)

};

content = require(&#39;querystring&#39;).stringify(data);

var options = {

method: "POST",

host: "www.xxx.com",//注意没有http://,这是服务器的域名。

port: 80,

path: path,//接收程序的路径和文件名

headers: {

&#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded; charset=UTF-8&#39;,

"Content-Length": content.length

}

};

var req = http.request(options, function (res) {

res.setEncoding(&#39;utf8&#39;);

res.on(&#39;data&#39;, function (chunk) {

console.log(&#39;BODY: &#39; + chunk);

});

});

req.on(&#39;error&#39;, function (e) {

console.log(&#39;problem with request: &#39; + e.message);

});

req.write(content);

req.end();

}

  以上是规则修改的主要部分。 需要将json内容发送到自己的服务器,从服务器获取下一页的跳转地址。 这里涉及到四个php文件:getMsgJson.php、getMsgExt.php、getWxHis.php、getWxPost.php

  在详细介绍这4个php文件之前,为了提高采集系统的性能,降低崩溃率,我们还可以做一些修改:

  Android模拟器经常访问一些地址,会导致anyproxy崩溃,找到函数replaceRequestOption: function(req,option),修改函数内容:

  replaceRequestOption : function(req,option){

var newOption = option;

if(/google/i.test(newOption.headers.host)){

newOption.hostname = "www.baidu.com";

newOption.port = "80";

}

return newOption;

},

  以上是anyproxy规则文件的修改配置。 配置修改完成后,重启anyproxy。 mac系统下按control+c中断程序,然后输入命令sudo anyproxy -i启动; 如果启动时报错,可能是程序没有退出干净,端口被占用了。 此时输入命令ps -a查看占用的pid,然后输入命令“kill -9 pid”,其中pid替换为查询到的pid号。 杀掉进程后就可以启动anyproxy了。 不过还请原谅我对windows的命令不熟悉。

  接下来详细介绍服务端接收程序的设计原理:

  (以下代码不能直接使用,只是介绍原理,部分代码需要根据自己的服务器数据库框架来写)

  1、getMsgJson.php:该程序负责接收历史消息的json,解析后存入数据库

<p>

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线