批处理之家's Archiver

523066680 发表于 2019-7-13 08:47

某电商平台订单信息批量获取、格式化输出、分类统计

现在搞跨境电商,[code]=info
    Get Orders from Ali Platform
    523066680/vicyang
    2019-07
=cut

use utf8;
use Encode;
use Modern::Perl;
use File::Slurp;
use File::Basename;
use Mojo::UserAgent;
use Time::HiRes qw/time sleep/;
use Date::Format;
use Date::Parse;
STDOUT->autoflush(1);

my $ua = Mojo::UserAgent->new();
$ua = $ua->request_timeout(5);

my $data = get_online_data($ua);
my $list = [];
data_abstract($data, $list);

my $time_a;
my $begin = time2str("%Y-%m-%d", time() - 24*60*60 ) ." 17:00";
my $end = time2str("%Y-%m-%d", time()) ." 17:00";

# dumping
my %calcu;
my $count;
my $slen = 0;
for my $e ( @$list )
{
    next if ( $e->{'time'} gt $end or $e->{'time'} lt $begin );
    printf "%s %s %s %6s %s %s %s %s %s %s\n",
            $e->{'time'},
            substr($e->{'ordernum'}, -5),
            gbk("发货地:"),
            $e->{'from'},
            $e->{'model'},
            $e->{'color'},
            $e->{'count'},
            $e->{'unit'},
            $e->{'status'},
            $e->{'to'},
            ;
    # 统计
    $count = $e->{unit} eq gbk('台') ? $e->{count} : $e->{count}*2;
    $slen = length($e->{model}) if length($e->{model}) > $slen;
    if (exists $calcu{ $e->{model} }) {
        $calcu{$e->{model}} += $count;
    } else {
        $calcu{$e->{model}} = $count;
    }
}

say gbk("分类统计:");
for my $model ( sort keys %calcu )
{
    printf "%-${slen}s %d pcs\n", $model, $calcu{$model};
}

sub data_abstract
{
    our ($COUNTRY, %country);
    my ($data, $list) = @_;
    say "Data processing ... ";
    my $node = match( $data->{data}{modules}, "name", "orderTable", "dataSource" );

    for my $e ( map { @{$_->{children}} } @$node )
    {
        #say $e->{'children'};
        my $ordernum = match( $e->{orderInfo}, "label", "订单号", "content" );
        my $time = match( $e->{orderInfo}, "label", "下单时间", "content" );
        my $buyer = (match( $e->{orderInfo}, "label", "买家", "options" ))->[0]{content};
        my $sku = match( $e->{productInfo}{elements}, "label", "商品属性", "content" );
        my $model = match( $e->{productInfo}{elements}, "label", "商品编码", "content" );
        my $status = $e->{orderStatus}[0]{content};
        my ($quantity) = $e->{productInfo}{elements}[1]{content} =~ /x (\d+)/;
        my $title = $e->{productInfo}{title};
        my $seller;

        next if $status =~ "等待买家付款";
        next if $status =~ "资金处理中";
        next if $status =~ "订单关闭";
        $status = " 已发货 " if $status =~ "等待买家收货";
        my $from;
        if ( $sku =~ /([\w\s]+) \+/ ) { $from = $1 } else { $from = "China" }

        my $color = $sku;
        my $unit = "台";
        if ($title=~/2 ?(pc|piece|unit)s?/i) {
            $unit = "对";
        }

        my $CNtime = time2str( "%Y-%m-%d %R", str2time($time) + 15*3600 );
        $CNtime=~s/T/ /;
        $CNtime=~s/:00$//;

        my $colorx = color_recognize( $color, $model );
        $model = model_number($model);

        #printf "%s %s %s %s %s\n", $orderID, $time, $model, gbk($colorx), $quantity;
        my ($zipcode, $target) = get_detail( $ua, $ordernum );
        $target = $COUNTRY->{$target}[0] if (exists $COUNTRY->{$target});
        push @$list, {
                'time' => $CNtime,
                'ordernum' => $ordernum,
                'from' => gbk($country{$from}),
                'model' => $model,
                'color' => gbk($colorx),
                'count' => $quantity,
                'unit' => gbk($unit),
                'status' => gbk($status),
                'to' => gbk($target),
            }
    }
}

sub get_detail
{
    my ($ua, $id ) = @_;
    my $link = "https://trade.aliexpress.com/order_detail.htm?orderId=" . $id;

    my $res = $ua->get( $link )->result;
    say "get detail false" unless $res->is_success();
    my $dom = $res->dom;

    my $zipcode;
    my $address;
    for my $e ($dom->find("span[i18entitle]")->each ) {
        if ($e->attr("i18entitle") =~ /Zip Code/i) { $zipcode = $e->text; }
    }

    $address = $dom->find(".long .i18ncopy")->map("text")->join("");

    # special: Croatia (local name: Hrvatska)
    $address =~s/\(.*\)//g;
    $address =~s/(\r|\n)//g;
    $address =~s/\s+$//g;
    ($address) = $address =~ /,\s+([^,]+)$/;

    return ($zipcode, $address);
}

sub match
{
    my ( $arr, $key, $value, $item ) = @_;
    for my $e ( @$arr ) {
        return $e->{$item} if ( exists $e->{$key} and $e->{$key} =~ /$value/ );
    }
    return "NOT FOUND";
}

sub model_number
{
    my ($model) = @_;
    my $actual = "";
   
    # 根据SKU选择项目或者标题,提取实际产品型号
   
    return $actual;
}

# 统一颜色标识
sub color_recognize
{
    my ($color, $model) = @_;
    my $colorx = "";
    my %cmap = ('black'=>"黑色", 'beige'=>"米色", 'gray'=>"灰色" );

    if ( $model =~/(Black|Gray|Grey|Beige)/i ) {
        $colorx .= $1;
    } else {
        if ( $color =~/(Black|Gray|Grey|Beige)/i ) {
            $colorx .= $1;
        } else {
            $colorx .= "Black";
        }
    }
    $colorx=~s/Grey/Gray/i;
    $colorx=~s/None/Black/i;

    return $cmap{lc $colorx};
}

sub get_online_data
{
    my ($ua) = @_;
    my $res;
    my $dom;

    my %headers = (
        "User-Agent" => "Mozilla/5.0 Firefox/67.0",
        "Upgrade-Insecure-Requests"=> "1",
        "Connection" => "keep-alive",
    );

    my %args =(
        "loginId" => '账号',
        "password2" => "256位密钥,通过火狐调试模式获取",
        "isMobile" => "false",
        "mobile" => "false"
    );

    my $url = "https://passport.aliexpress.com/newlogin/login.do?appName=aebuyer&fromSite=13";
    $res = $ua->post( $url, \%headers, form => \%args )->result;
    say "false" unless $res->is_success();
    # {"content":{"data":{"miniVsts":[],"st":"1ZNq0FM2sJ6ssd_O7n98drw", ...

    my $st = $res->json->{'content'}{'data'}{'st'};
    say "st: ", $st;

    # step 2
    # validateSTGroup is necessary
    my $url2 = "https://login.aliexpress.com/validateSTGroup.htm";
    %args = (
            "st" => $st,
            "join_from" => "aliexpress",
            "pattern" => "common",
            "passport" => '账号',
            "scene" => "AE_MAIN_LOGIN",
        );

    $res = $ua->get( $url2, \%headers, form => \%args )->result;

    # https://mojolicious.org/perldoc/Mojo/UserAgent/CookieJar
    for my $e ( @{$ua->cookie_jar->all} ) {
        if ($e->name eq "aep_usuc_f") { $e->value( $e->value . "&s_locale=zh_CN" ); }
    }

    $url = "https://gsp-gw.aliexpress.com/openapi/param2/1/gateway.seller/api.order.list.get";
    %args = (
        "_timezone" => "-8",
        "lastSelectOrderStatus" => "all",
        "orderTab" => "Null",
        "refreshPage" => "false",
        "orderStatus" => "all",
        "filterCondition" => "OrderId",
        "current" => "1",
        "pageSize" => "50"  # 一页的项数 10 20 50 100
    );

    $res = $ua->post( $url, form => \%args )->result;
    say "false" unless $res->is_success();
    return $res->json;
}

sub gbk { encode('gbk', $_[0]) }

BEGIN
{
    use Storable qw/retrieve/;
    # ref->{'English Name'} = [ zhCN_Name, CountryCode ]
    our $COUNTRY = retrieve("CountryName_EN2CN.perldb");
    our %country = ( 'China' => '中国', 'Spain' => '西班牙', 'Russian Federation' => '俄罗斯' );
}[/code]国家名称映射表,英文转中文
$COUNTRY->{'English Name'} = [ 中文名, 英文名国际缩写 ]

输出结果(手动改了型号)[code]Data processing ...
2019-07-13 07:17 64820 发货地:   中国 R10001 黑色 1 台 等待您发货 巴西
2019-07-13 06:09 93991 发货地:   中国 R30001 黑色 2 台 等待您发货 法国
2019-07-13 05:39 36966 发货地:   中国 R30002 黑色 1 台 等待您发货 西班牙
2019-07-13 00:13 95071 发货地: 俄罗斯 R20001 黑色 1 台 等待您发货 俄罗斯
2019-07-12 23:39 65233 发货地: 俄罗斯 R30003 黑色 2 台 等待您发货 俄罗斯
2019-07-12 21:43 19126 发货地: 西班牙 R20001 灰色 1 对  已发货  西班牙
2019-07-12 17:55 35787 发货地: 西班牙 R30005 灰色 1 台 等待您发货 西班牙
分类统计:
R30002 1 pcs
R30001 2 pcs
R10001 1 pcs
R20001 3 pcs
R30003 2 pcs
R30005 1 pcs[/code]分类统计的时候会判断单位是台还是对,一对的项目数量*2

时间范围限定:[code]my $begin = time2str("%Y-%m-%d 17:00", time() - 24*60*60 );
my $end = time2str("%Y-%m-%d 17:00", time());[/code]

523066680 发表于 2019-7-13 08:51

时间原本是美国时间,通过 Data::Parse 和 Data::Format 模块,解析为时间戳+15小时,再格式化输出。[code]my $CNtime = time2str( "%Y-%m-%d %R", str2time($time) + 15*3600 );[/code]其实有时区转换的模块,但是一写发现还没这两个模块简洁

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.