鍍金池/ 問答/PHP/ 公眾號有幾十萬粉絲,如何在對接的時(shí)候快速同步到本地?cái)?shù)據(jù)庫進(jìn)行運(yùn)營

公眾號有幾十萬粉絲,如何在對接的時(shí)候快速同步到本地?cái)?shù)據(jù)庫進(jìn)行運(yùn)營

我使用EasyWechat嘗試開發(fā)了一個(gè)第三方平臺,然后會幫助本地商戶或公眾號運(yùn)營一些活動(dòng),如何在公眾號授權(quán)對接后快速的將公眾號粉絲數(shù)據(jù)同步到本地?cái)?shù)據(jù)庫方便運(yùn)營?我先前的想法是用戶有交互的時(shí)候再觸發(fā)同步,目前是使用的手動(dòng)方式和命令行方式,手動(dòng)方式如下:

/**
     * 同步
     */
    public function sync()
    {
        $account = $this->request->param('account', 0, 'intval');
        $account = AccountService::getDataById($account);
        if (empty($account)) {
            $this->error('參數(shù)錯(cuò)誤');
        }
        //頁碼
        $page = $this->request->param('page', 0, 'intval');
        $page_size = 50;
        //微信實(shí)例
        $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);
                }
            }
            //設(shè)置緩存
            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.'出錯(cuò)<br/>';
                continue;
            }
        }
        //刪除緩存
        cache('wechat_fans_'.$account->id, null);
        return $this->success('同步完成', url($this->request->controller().'/index', ['account' => $account->id]));
    }

這種使用分頁同步在瀏覽器執(zhí)行的方式速度非常慢,大約幾萬粉絲都要跑很久,然后跟這個(gè)類似的我寫了一個(gè)命令行方式,執(zhí)行也很慢。

<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()
    {
        //設(shè)置命令名稱及描述
        $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("參數(shù)錯(cuò)誤");
            exit;
        }
        //微信實(shí)例
        $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);
                }
            }
            //設(shè)置緩存
            cache('wechat_fans_'.$account->id, $fans);
        }
        foreach ($fans as $k => $v) {
            try {
                UserService::syncDataByServer($account, $v);
            } catch (\Exception $e) {
                $output->writeln("同步{$k}出錯(cuò)");
                continue;
            }
        }
        //刪除緩存
        cache('wechat_fans_'.$account->id, null);
        $output->writeln("同步完成");
    }
}

求教各位大神有沒有比較好的方案。麻煩詳細(xì)些,本人不是專業(yè)的程序員,太簡略了看不懂。謝謝!

回答
編輯回答
傲嬌范

你是想把公眾號的粉絲拉到你本地?cái)?shù)據(jù)庫?如果單個(gè)進(jìn)城拉取慢,可以開啟多個(gè)進(jìn)程跑

2017年4月22日 19:53
編輯回答
未命名

在用戶進(jìn)行授權(quán)接入后,進(jìn)行粉絲數(shù)據(jù)同步主要有兩個(gè)部分,一個(gè)歷史粉絲數(shù)據(jù)同步,這個(gè)利用后臺程序在公眾號授權(quán)后就可以開始同步了,獲取用戶列表接口一次也只能獲取一萬個(gè)openid,一個(gè)公眾號一個(gè)線程也就夠了, 沒有必要立即跑完,本身微信公眾號接口就有頻率限制,如果你覺得速度實(shí)在是慢,也可以開幾個(gè)進(jìn)程來處理。 幾萬個(gè)粉絲的公眾號其實(shí)很快就能跑完了,放在后臺任務(wù)執(zhí)行也不用人工執(zhí)行。
二是新的粉絲數(shù)據(jù),在關(guān)注和取消關(guān)注事件里面,你可以在事件回調(diào)中處理粉絲數(shù)據(jù),這樣就不用重新拉取所有的粉絲數(shù)據(jù)了。
其實(shí)幾萬個(gè)粉絲數(shù)據(jù)很快就處理完了, 我跑過兩千多萬粉絲的數(shù)據(jù),也就幾天,而且接口調(diào)用頻率放的很慢了。

2018年3月4日 23:54
編輯回答
帥到炸

是不是UserService::syncDataByServer($account, $v);這個(gè)方法慢?改成批量同步試下?而且?guī)资f放到一個(gè)fans數(shù)組里內(nèi)存消耗很大吧。感覺可以結(jié)合微信的每1萬條數(shù)據(jù)獲取后接著批量處理一次。

2017年5月24日 14:58