让我们来用php编写一个抢购商品脚本

383 阅读3分钟

项目源码

== 还没上传呢

juejin.im/editor/draf…

环境

  • php7.2
  • guzzle
  • thinkphp5.1

说明

0. git clone xxxxxx
1. composer create-project topthink/think=5.1.* fxbox
2. cd fxbox
3. composer require guzzlehttp/guzzle:~6.0  安装 guzzle 
4. composer update

如何使用

如果是github那边下载源码的话,看这里

1. cd fxbox
2. php think fcbox:run
3. ....后面这里就可以脚本的安装提示进行下一步骤了

效果图

核心代码


<?php

namespace app\command;

use GuzzleHttp\Cookie\CookieJar;
use think\console\Command;
use think\console\Input;
use think\console\Output;

class Fcbox extends Command
{

    private $userInfo = [];
    private $cookies = '';
    private $skus = '';
    private $address = [];

    //数量
    private $count = 0;
    // 用户列表的下标
    private $current_address = 0;
    // sku列表的下标
    private $current_sku = 0;
    // 抢购开始时间
    private $start_time = 0;
    //生成订单的token
    private $orderToken = 0;


    public $client = null;
    public $jar = null;
    public $output = null;

    public function __construct($name = null)
    {

        parent::__construct($name);

        $this->client = new \GuzzleHttp\Client(); //初始化客户端
        $this->jar = new CookieJar();
        $this->output = new Output();


        //获取用户信息
        $this->cookies = $this->inputCookie();

        // 订单结束


    }

    protected function configure()
    {
        // 指令配置
        $this->setName('fcbox:run');
        // 设置参数

    }

    protected function execute(Input $input, Output $output)
    {

        $this->output->writeln("-------------正在获取个人信息中-------------");
        $this->userInfo = $this->getUserInfo(); // 用户信息
        $this->address = $this->getUserAddress(); // 用户地址
        $this->output->writeln("----------------------------------------------------------------------");


        // 获取产品sku信息 价格 描述  产品名称
        $this->skus = $this->getProduct(); // 产品信息
        $this->output->writeln("----------------------------------------------------------------------");

        // 选择sku信息
        $this->selectProductSku();
        $this->output->writeln("----------------------------------------------------------------------");

        // 选择数量
        $this->getInputCount();
        $this->output->writeln("----------------------------------------------------------------------");

        // 选择地址
        $this->selectUserAddress();
        $this->output->writeln("----------------------------------------------------------------------");


        // 抢购开始的时间
        $this->getInputStartTime();
        $this->output->writeln("----------------------------------------------------------------------");


        /**
         *
         * 这里需要循环进行下单
         *
         *
         */

        // 提交订单

        while (true) {
            sleep(5);
        }


        //生成提交订单的信息  认证token
        $this->getConfirmToken();
        $this->output->writeln("----------------------------------------------------------------------");

        //提交订单
        $this->submitOrder();
        $this->output->writeln("----------------------------------------------------------------------");


        // 脚本执行结束
        $this->output->writeln("----------------------------------------------------------------------");
        $this->output->writeln("------------------------------脚本执行完成------------------------------");
        $this->output->writeln("----------------------------------------------------------------------");

    }


    /**
     * 对用户输入的cookie进行处理
     * @return CookieJar
     */
    private function inputCookie()
    {
        try {
            fwrite(STDOUT, '请输入你的Cookies:');
            $cookies = trim(fgets(STDIN));
            $cookies = explode(';', $cookies);
            $base_url = 'mall.fcbox.com';
            $data = [];
            foreach ($cookies as $cookie) {
                if ($cookie == '') continue;
                [$name, $value] = explode('=', $cookie);
                $data[trim($name)] = trim($value);
            }
            $resp = $this->jar->fromArray($data, $base_url);
            return $resp;

        } catch (\Exception $e) {
            $this->output->writeln('验证用户Cookies发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }


    /**
     * 获取产品的信息
     * @return array
     */
    private function getProduct()
    {
        try {
            fwrite(STDOUT, '请输入你的产品的URL路径:');
            $url = trim(fgets(STDIN));
            $args = explode('/', $url);
            $product_id = array_pop($args);

            $sku = $this->getProductSku($product_id);
            $this->output->writeln("-------------获取产品SKU信息成功-------------");
            return $sku;

        } catch (\Exception $e) {
            $this->output->writeln('获取产品信息发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }

    /**
     * 获取产品的sku 列表
     * @param $product_id
     * @return array
     */
    private function getProductSku($product_id)
    {
        try {
            $skuInfoUrl = "https://mall.fcbox.com/item/skuInfo?itemCode={$product_id}&province=&city=&area=&latitude=&longitude=";

            $response = $this->client->request('GET', $skuInfoUrl, [
                'timeout' => 3.14,
                'verify' => false,
            ]);

            $content = $response->getBody()->getContents(); //获取响应体,对象
            $content = json_decode($content, JSON_UNESCAPED_UNICODE);

            $skus = [];
            foreach ($content['data']['skus'] as $sku) {

                $item['skuCode'] = $sku['skuCode'];
                $item['stock'] = $sku['stock'];
                $item['salePrice'] = $sku['salePrice'];
                $item['saleSiteId'] = $sku['saleSiteId'];
                $item['saleSiteType'] = $sku['saleSiteType'];
                $item['itemCode'] = $sku['itemCode'];
                $item['description'] = $sku['saleAttributes'];
                $item['activityPrice'] = $sku['activityPrice'];

                $skus[] = $item;
            }
            return $skus;

        } catch (\Exception $e) {
            $this->output->writeln('获取产品SKU发生错误,错误原因:' . $e->getMessage());
            exit;
        }

    }


    /**
     * 获取cookies 的账号信息以及个人地址
     * @param $cookies
     * @return mixed
     */
    public function getUserInfo()
    {
        try {
            // 个人中心
            $centerUrl = 'https://mall.fcbox.com/member/center?';
            $response = $this->client->request('GET', $centerUrl, [
                'timeout' => 3.14,
                'verify' => false,
                'cookies' => $this->cookies,
//            'debug' => true, //调试
            ]);

            $content = $response->getBody()->getContents(); //获取响应体,对象
            $content = json_decode($content, JSON_UNESCAPED_UNICODE);
            $this->output->writeln("-------获取用户信息成功-------");
            return $content['data'];

        } catch (\Exception $e) {
            $this->output->writeln('获取用户信息发生错误,错误原因:' . $e->getMessage());
            exit;
        }

    }


    /**
     * 获取用户地址
     */
    private function getUserAddress()
    {
        try {

            $url = 'https://mall.fcbox.com/addressBook/list';
            $response = $this->client->request('POST', $url, [
                'timeout' => 3.14,
                'verify' => false,
                'cookies' => $this->cookies,
//            'debug' => true, //调试
            ]);
            $content = $response->getBody()->getContents(); //获取响应体,对象
            $centerContent = json_decode($content, JSON_UNESCAPED_UNICODE);
            $this->output->writeln("-------获取用户地址成功-------");

            return $centerContent['data'];
        } catch (\Exception $e) {
            $this->output->writeln('获取用户地址列表发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }

    /**
     * 设置需要购买的数量
     * @return int
     */
    private function getInputCount()
    {
        try {
            $result = false;
            do {

                fwrite(STDOUT, '请输入你需要购买的数量:');
                $count = trim(fgets(STDIN));
                if (is_numeric($count) && $count != 0 && $count != '') {
                    $result = true;
                    $this->count = intval($count);
                    return intval($count);
                }
                $this->output->writeln('请输入一个正确的数字');

            } while ($result == false);

        } catch (\Exception $e) {
            $this->output->writeln('抢购数量发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }


    /**
     * 选择用户的地址
     * @return int|string
     */
    private function selectUserAddress()
    {
        try {
            $this->output->writeln('-------------用户地址列表-------------');

            foreach ($this->address as $key => $address) {
                $item = [];
                if ($address['isDefault'] == 1) $item[] = '《默认地址》';

                unset($address['id']);
                unset($address['latitude']);
                unset($address['longitude']);
                unset($address['source']);
                unset($address['uicUserId']);
                unset($address['is_default']);

                foreach ($address as $name => $value) {
                    $item[] = $value;
                }
                $item = implode(' ', $item);
                $this->output->writeln("地址-序号:{$key}  ->   {$item}");
            }

            // 验证输入的序号是否合法
            $result = false;
            do {

                fwrite(STDOUT, '请选择用户序号的地址:');
                $input = trim(fgets(STDIN));
                // 非法输入
                if ($input > count($this->address) || $input < 0) continue;

                $result = true;
                $this->current_address = $input;
                return $this->current_address;

            } while ($result == false);

        } catch (\Exception $e) {
            $this->output->writeln('选择用户地址发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }


    /**
     * 选择产品的sku
     * @return int|string
     */
    private function selectProductSku()
    {
        try {
            $this->output->writeln('-------------SKU列表-------------');

            $lists[] = [
                '序号', 'SKU', '库存', '价格', '描述',
            ];
            foreach ($this->skus as $key => $sku) {
                $item = [];
                $item['key'] = $key; //sku
                $item['skuCode'] = $sku['skuCode']; //sku
                $item['stock'] = $sku['stock']; // 库存
                $item['salePrice'] = $sku['salePrice'] / 100; // 价格
                foreach ($sku['description'] as $description) {
                    $item['description'] = implode(',', [$description['key'], $description['value']]);  // sku 描述
                }
                $lists[] = $item;
            }

            foreach ($lists as $rows) {
                foreach ($rows as $row) {
                    $this->output->write($row . "\t\t");
                }
                $this->output->write("\n");
            }

            // 验证输入的序号是否合法
            $result = false;
            do {

                fwrite(STDOUT, '请选择产品SKU序号的序号:');
                $input = trim(fgets(STDIN));
                // 非法输入
                if ($input > count($this->address) || $input < 0) continue;

                $result = true;
                $this->current_sku = $input;
                return $this->current_sku;

            } while ($result == false);

        } catch (\Exception $e) {
            $this->output->writeln('发生错误,程序即将退出,错误原因:' . $e->getMessage());
            exit;
        }

    }


    /**
     * 设置开始抢购的时间
     * @return false|int
     */
    private function getInputStartTime()
    {
        try {

            $result = false;
            do {
                fwrite(STDOUT, '请输入开始抢购的时间:');
                $time = trim(fgets(STDIN));
                $time = strtotime($time);
                if (time() < $time) {
                    $result = true;
                    $this->start_time = $time;
                    return $time;
                }
                $this->output->writeln('请输入一个正确的时间范围');

            } while ($result == false);

        } catch (\Exception $e) {
            $this->output->writeln('抢购开始时间发生错误,错误原因:' . $e->getMessage());
            exit;
        }

    }


    /**
     * 生成提交订单的order
     * @return mixed
     */
    private function getConfirmToken()
    {
//        addressId: 2891060
//itemReqStr: [{"count":1,"saleSiteId":403,"skuCode":"127025488939648"}]
        try {
            $this->output->writeln('-------------正在生成订单Token中-------------');

            $url = 'https://mall.fcbox.com/order/confirm';
            $response = $this->client->request('POST', $url, [
                'timeout' => 3.14,
                'verify' => false,
                'cookies' => $this->cookies,
                'form_params' => [
                    'addressId' => $this->address[$this->current_address]['id'],
                    'itemReqStr' => json_encode([[
                        'count' => $this->count,
                        'saleSiteId' => $this->skus[$this->current_sku]['saleSiteId'],
                        'skuCode' => $this->skus[$this->current_sku]['skuCode'],
                    ]]),
                ]

            ]);

            $content = $response->getBody()->getContents();
            $content = json_decode($content, JSON_UNESCAPED_UNICODE);
            $token = $content['data']['orderToken'];

            $this->orderToken = $token;
            $this->output->writeln("-------------订单Token生成成功,Token值为:{$token}-------------");

            return $token;

        } catch (\Exception $e) {
            $this->output->writeln('生成订单Token发生错误,错误原因:' . $e->getMessage());
            exit;
        }

    }

    /**
     * 提交订单信息
     */
    private function submitOrder()
    {
        try {

            $this->output->writeln('-------------提交订单中-------------');

            $url = 'https://mall.fcbox.com/order/submit';

            $data['token'] = $this->orderToken;
            $data['addressId'] = $this->address[$this->current_address]['id'];
            $data['deliveryRemark'] = $this->orderToken;
            $data['coupons'] = [];
            $data['orderFee'] = $this->skus[$this->current_sku]['activityPrice']; //价格
            $data['orderFrom'] = 1;
            $data['itemList'] = [
                [
                    'skuCode' => $this->skus[$this->current_sku]['skuCode'],
                    'siteId' => $this->skus[$this->current_sku]['saleSiteId'],
                    'count' => $this->count,
                    'remark' => '[]',
                ]
            ];
            $data['siteRemarks'] = [
                [
                    'siteId' => 13,
                    'remark' => '',
                ]
            ];

            $response = $this->client->request('POST', $url, [
                'timeout' => 3.14,
                'verify' => false,
                'cookies' => $this->cookies,
                'json' => $data,
            ]);

            $content = $response->getBody()->getContents();
            $content = json_decode($content, JSON_UNESCAPED_UNICODE);
            $this->output->writeln("-------------提交订单完成,当前订单状态:{$content['msg']}-------------");

        } catch (\Exception $e) {
            $this->output->writeln('提交订单发生错误,错误原因:' . $e->getMessage());
            exit;
        }
    }
}