公众号有几十万粉丝,如何在对接的时候快速同步到本地数据库进行运营

幽壑潜蛟
  • 53

我使用EasyWechat尝试开发了一个第三方平台,然后会帮助本地商户或公众号运营一些活动,如何在公众号授权对接后快速的将公众号粉丝数据同步到本地数据库方便运营?我先前的想法是用户有交互的时候再触发同步,目前是使用的手动方式和命令行方式,手动方式如下:

/**
     * 同步
     */
    public function sync()
    {
        $account = $this->request->param('account', 0, 'intval');
        $account = AccountService::getDataById($account);
        if (empty($account)) {
            $this->error('参数错误');
        }
        //页码
        $page = $this->request->param('page', 0, 'intval');
        $page_size = 50;
        //微信实例
        $wechat = WechatService::applicationInit($account);
        
        //先从缓存中读取
        $fans = cache('wechat_fans_'.$account->id);
        if (!$fans) {
            echo '从腾讯拉取';
            //从腾讯拉取第一页
            $datas = $wechat->user->lists();
            $total = ceil($datas['total'] / $datas['count']);
            $fans = $datas['data']['openid'];
            for ($i = 1; $i < $total; $i++) {
                $datas = $wechat->user->lists($datas['next_openid']);
                $lists = $datas['data']['openid'];
                foreach ($lists as $k => $v) {
                    array_push($fans, $v);
                }
            }
            //设置缓存
            cache('wechat_fans_'.$account->id, $fans);
        }
        foreach ($fans as $k => $v) {
            if ($k <= $page * $page_size) {
                continue;
            }
            if ($k > ($page + 1) * $page_size) {
                return $this->success('更新下一页', url($this->request->controller().'/sync', ['account' => $account->id, 'page' => $page + 1]));
            }
            echo '同步'.$k.'成功<br/>';
            try {
                UserService::syncDataByServer($account, $v);
            } catch (\Exception $e) {
                echo '同步'.$k.'出错<br/>';
                continue;
            }
        }
        //删除缓存
        cache('wechat_fans_'.$account->id, null);
        return $this->success('同步完成', url($this->request->controller().'/index', ['account' => $account->id]));
    }

这种使用分页同步在浏览器执行的方式速度非常慢,大约几万粉丝都要跑很久,然后跟这个类似的我写了一个命令行方式,执行也很慢。

<php
namespace app\wechat\command;
use app\wechat\service\AccountService;
use app\wechat\service\WechatService;
use app\wechat\service\UserService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\console\input\Option;

/**
 * 同步用户命令
 * Class SyncUser
 * @package app\wechat\command
 */
class SyncUser extends Command
{
    /**
     * 命令行配置
     */
    protected function configure()
    {
        //设置命令名称及描述
        $this->setName('Wechat:SyncUser')
            ->addOption('account', 0, Option::VALUE_REQUIRED, '账号ID.')
            ->setDescription('同步公众号用户');
    }

    /**
     * 命令
     * @return int|null|void
     */
    protected function execute(Input $input, Output $output)
    {
        ini_set('memory_limit', '1024M');
        if (!$input->hasOption('account')) {
            $output->writeln("请输入账号");
            return null;
        }
        $account = $input->getOption('account');
        $account = AccountService::getDataById($account);
        if (!$account) {
            $output->writeln("参数错误");
            exit;
        }
        //微信实例
        $wechat = WechatService::applicationInit($account);
        //先从缓存中读取
        $fans = cache('wechat_fans_'.$account->id);
        if (!$fans) {
            $output->writeln("从腾讯拉取粉丝");
            //从腾讯拉取第一页
            $datas = $wechat->user->lists();
            $total = ceil($datas['total'] / $datas['count']);
            $fans = $datas['data']['openid'];
            for ($i = 1; $i < $total; $i++) {
                $datas = $wechat->user->lists($datas['next_openid']);
                $lists = $datas['data']['openid'];
                foreach ($lists as $k => $v) {
                    array_push($fans, $v);
                }
            }
            //设置缓存
            cache('wechat_fans_'.$account->id, $fans);
        }
        foreach ($fans as $k => $v) {
            try {
                UserService::syncDataByServer($account, $v);
            } catch (\Exception $e) {
                $output->writeln("同步{$k}出错");
                continue;
            }
        }
        //删除缓存
        cache('wechat_fans_'.$account->id, null);
        $output->writeln("同步完成");
    }
}

求教各位大神有没有比较好的方案。麻烦详细些,本人不是专业的程序员,太简略了看不懂。谢谢!

回复
阅读 3.7k
3 个回答
✓ 已被采纳

在用户进行授权接入后,进行粉丝数据同步主要有两个部分,一个历史粉丝数据同步,这个利用后台程序在公众号授权后就可以开始同步了,获取用户列表接口一次也只能获取一万个openid,一个公众号一个线程也就够了, 没有必要立即跑完,本身微信公众号接口就有频率限制,如果你觉得速度实在是慢,也可以开几个进程来处理。 几万个粉丝的公众号其实很快就能跑完了,放在后台任务执行也不用人工执行。
二是新的粉丝数据,在关注和取消关注事件里面,你可以在事件回调中处理粉丝数据,这样就不用重新拉取所有的粉丝数据了。
其实几万个粉丝数据很快就处理完了, 我跑过两千多万粉丝的数据,也就几天,而且接口调用频率放的很慢了。

你是想把公众号的粉丝拉到你本地数据库?如果单个进城拉取慢,可以开启多个进程跑

是不是UserService::syncDataByServer($account, $v);这个方法慢?改成批量同步试下?而且几十万放到一个fans数组里内存消耗很大吧。感觉可以结合微信的每1万条数据获取后接着批量处理一次。

宣传栏