某电商平台订单信息批量获取、格式化输出、分类统计
现在搞跨境电商,[code]=infoGet 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] 时间原本是美国时间,通过 Data::Parse 和 Data::Format 模块,解析为时间戳+15小时,再格式化输出。[code]my $CNtime = time2str( "%Y-%m-%d %R", str2time($time) + 15*3600 );[/code]其实有时区转换的模块,但是一写发现还没这两个模块简洁
页:
[1]