Board logo

标题: [原创代码] 某电商平台订单信息批量获取、格式化输出、分类统计 [打印本页]

作者: 523066680    时间: 2019-7-13 08:47     标题: 某电商平台订单信息批量获取、格式化输出、分类统计

现在搞跨境电商,
  1. =info
  2.     Get Orders from Ali Platform
  3.     523066680/vicyang
  4.     2019-07
  5. =cut
  6. use utf8;
  7. use Encode;
  8. use Modern::Perl;
  9. use File::Slurp;
  10. use File::Basename;
  11. use Mojo::UserAgent;
  12. use Time::HiRes qw/time sleep/;
  13. use Date::Format;
  14. use Date::Parse;
  15. STDOUT->autoflush(1);
  16. my $ua = Mojo::UserAgent->new();
  17. $ua = $ua->request_timeout(5);
  18. my $data = get_online_data($ua);
  19. my $list = [];
  20. data_abstract($data, $list);
  21. my $time_a;
  22. my $begin = time2str("%Y-%m-%d", time() - 24*60*60 ) ." 17:00";
  23. my $end = time2str("%Y-%m-%d", time()) ." 17:00";
  24. # dumping
  25. my %calcu;
  26. my $count;
  27. my $slen = 0;
  28. for my $e ( @$list )
  29. {
  30.     next if ( $e->{'time'} gt $end or $e->{'time'} lt $begin );
  31.     printf "%s %s %s %6s %s %s %s %s %s %s\n",
  32.             $e->{'time'},
  33.             substr($e->{'ordernum'}, -5),
  34.             gbk("发货地:"),
  35.             $e->{'from'},
  36.             $e->{'model'},
  37.             $e->{'color'},
  38.             $e->{'count'},
  39.             $e->{'unit'},
  40.             $e->{'status'},
  41.             $e->{'to'},
  42.             ;
  43.     # 统计
  44.     $count = $e->{unit} eq gbk('台') ? $e->{count} : $e->{count}*2;
  45.     $slen = length($e->{model}) if length($e->{model}) > $slen;
  46.     if (exists $calcu{ $e->{model} }) {
  47.         $calcu{$e->{model}} += $count;
  48.     } else {
  49.         $calcu{$e->{model}} = $count;
  50.     }
  51. }
  52. say gbk("分类统计:");
  53. for my $model ( sort keys %calcu )
  54. {
  55.     printf "%-${slen}s %d pcs\n", $model, $calcu{$model};
  56. }
  57. sub data_abstract
  58. {
  59.     our ($COUNTRY, %country);
  60.     my ($data, $list) = @_;
  61.     say "Data processing ... ";
  62.     my $node = match( $data->{data}{modules}, "name", "orderTable", "dataSource" );
  63.     for my $e ( map { @{$_->{children}} } @$node )
  64.     {
  65.         #say $e->{'children'};
  66.         my $ordernum = match( $e->{orderInfo}, "label", "订单号", "content" );
  67.         my $time = match( $e->{orderInfo}, "label", "下单时间", "content" );
  68.         my $buyer = (match( $e->{orderInfo}, "label", "买家", "options" ))->[0]{content};
  69.         my $sku = match( $e->{productInfo}{elements}, "label", "商品属性", "content" );
  70.         my $model = match( $e->{productInfo}{elements}, "label", "商品编码", "content" );
  71.         my $status = $e->{orderStatus}[0]{content};
  72.         my ($quantity) = $e->{productInfo}{elements}[1]{content} =~ /x (\d+)/;
  73.         my $title = $e->{productInfo}{title};
  74.         my $seller;
  75.         next if $status =~ "等待买家付款";
  76.         next if $status =~ "资金处理中";
  77.         next if $status =~ "订单关闭";
  78.         $status = " 已发货 " if $status =~ "等待买家收货";
  79.         my $from;
  80.         if ( $sku =~ /([\w\s]+) \+/ ) { $from = $1 } else { $from = "China" }
  81.         my $color = $sku;
  82.         my $unit = "台";
  83.         if ($title=~/2 ?(pc|piece|unit)s?/i) {
  84.             $unit = "对";
  85.         }
  86.         my $CNtime = time2str( "%Y-%m-%d %R", str2time($time) + 15*3600 );
  87.         $CNtime=~s/T/ /;
  88.         $CNtime=~s/:00$//;
  89.         my $colorx = color_recognize( $color, $model );
  90.         $model = model_number($model);
  91.         #printf "%s %s %s %s %s\n", $orderID, $time, $model, gbk($colorx), $quantity;
  92.         my ($zipcode, $target) = get_detail( $ua, $ordernum );
  93.         $target = $COUNTRY->{$target}[0] if (exists $COUNTRY->{$target});
  94.         push @$list, {
  95.                 'time' => $CNtime,
  96.                 'ordernum' => $ordernum,
  97.                 'from' => gbk($country{$from}),
  98.                 'model' => $model,
  99.                 'color' => gbk($colorx),
  100.                 'count' => $quantity,
  101.                 'unit' => gbk($unit),
  102.                 'status' => gbk($status),
  103.                 'to' => gbk($target),
  104.             }
  105.     }
  106. }
  107. sub get_detail
  108. {
  109.     my ($ua, $id ) = @_;
  110.     my $link = "https://trade.aliexpress.com/order_detail.htm?orderId=" . $id;
  111.     my $res = $ua->get( $link )->result;
  112.     say "get detail false" unless $res->is_success();
  113.     my $dom = $res->dom;
  114.     my $zipcode;
  115.     my $address;
  116.     for my $e ($dom->find("span[i18entitle]")->each ) {
  117.         if ($e->attr("i18entitle") =~ /Zip Code/i) { $zipcode = $e->text; }
  118.     }
  119.     $address = $dom->find(".long .i18ncopy")->map("text")->join("");
  120.     # special: Croatia (local name: Hrvatska)
  121.     $address =~s/\(.*\)//g;
  122.     $address =~s/(\r|\n)//g;
  123.     $address =~s/\s+$//g;
  124.     ($address) = $address =~ /,\s+([^,]+)$/;
  125.     return ($zipcode, $address);
  126. }
  127. sub match
  128. {
  129.     my ( $arr, $key, $value, $item ) = @_;
  130.     for my $e ( @$arr ) {
  131.         return $e->{$item} if ( exists $e->{$key} and $e->{$key} =~ /$value/ );
  132.     }
  133.     return "NOT FOUND";
  134. }
  135. sub model_number
  136. {
  137.     my ($model) = @_;
  138.     my $actual = "";
  139.    
  140.     # 根据SKU选择项目或者标题,提取实际产品型号
  141.    
  142.     return $actual;
  143. }
  144. # 统一颜色标识
  145. sub color_recognize
  146. {
  147.     my ($color, $model) = @_;
  148.     my $colorx = "";
  149.     my %cmap = ('black'=>"黑色", 'beige'=>"米色", 'gray'=>"灰色" );
  150.     if ( $model =~/(Black|Gray|Grey|Beige)/i ) {
  151.         $colorx .= $1;
  152.     } else {
  153.         if ( $color =~/(Black|Gray|Grey|Beige)/i ) {
  154.             $colorx .= $1;
  155.         } else {
  156.             $colorx .= "Black";
  157.         }
  158.     }
  159.     $colorx=~s/Grey/Gray/i;
  160.     $colorx=~s/None/Black/i;
  161.     return $cmap{lc $colorx};
  162. }
  163. sub get_online_data
  164. {
  165.     my ($ua) = @_;
  166.     my $res;
  167.     my $dom;
  168.     my %headers = (
  169.         "User-Agent" => "Mozilla/5.0 Firefox/67.0",
  170.         "Upgrade-Insecure-Requests"=> "1",
  171.         "Connection" => "keep-alive",
  172.     );
  173.     my %args =(
  174.         "loginId" => '账号',
  175.         "password2" => "256位密钥,通过火狐调试模式获取",
  176.         "isMobile" => "false",
  177.         "mobile" => "false"
  178.     );
  179.     my $url = "https://passport.aliexpress.com/newlogin/login.do?appName=aebuyer&fromSite=13";
  180.     $res = $ua->post( $url, \%headers, form => \%args )->result;
  181.     say "false" unless $res->is_success();
  182.     # {"content":{"data":{"miniVsts":[],"st":"1ZNq0FM2sJ6ssd_O7n98drw", ...
  183.     my $st = $res->json->{'content'}{'data'}{'st'};
  184.     say "st: ", $st;
  185.     # step 2
  186.     # validateSTGroup is necessary
  187.     my $url2 = "https://login.aliexpress.com/validateSTGroup.htm";
  188.     %args = (
  189.             "st" => $st,
  190.             "join_from" => "aliexpress",
  191.             "pattern" => "common",
  192.             "passport" => '账号',
  193.             "scene" => "AE_MAIN_LOGIN",
  194.         );
  195.     $res = $ua->get( $url2, \%headers, form => \%args )->result;
  196.     # https://mojolicious.org/perldoc/Mojo/UserAgent/CookieJar
  197.     for my $e ( @{$ua->cookie_jar->all} ) {
  198.         if ($e->name eq "aep_usuc_f") { $e->value( $e->value . "&s_locale=zh_CN" ); }
  199.     }
  200.     $url = "https://gsp-gw.aliexpress.com/openapi/param2/1/gateway.seller/api.order.list.get";
  201.     %args = (
  202.         "_timezone" => "-8",
  203.         "lastSelectOrderStatus" => "all",
  204.         "orderTab" => "Null",
  205.         "refreshPage" => "false",
  206.         "orderStatus" => "all",
  207.         "filterCondition" => "OrderId",
  208.         "current" => "1",
  209.         "pageSize" => "50"  # 一页的项数 10 20 50 100
  210.     );
  211.     $res = $ua->post( $url, form => \%args )->result;
  212.     say "false" unless $res->is_success();
  213.     return $res->json;
  214. }
  215. sub gbk { encode('gbk', $_[0]) }
  216. BEGIN
  217. {
  218.     use Storable qw/retrieve/;
  219.     # ref->{'English Name'} = [ zhCN_Name, CountryCode ]
  220.     our $COUNTRY = retrieve("CountryName_EN2CN.perldb");
  221.     our %country = ( 'China' => '中国', 'Spain' => '西班牙', 'Russian Federation' => '俄罗斯' );
  222. }
复制代码
国家名称映射表,英文转中文
$COUNTRY->{'English Name'} = [ 中文名, 英文名国际缩写 ]

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

时间范围限定:
  1. my $begin = time2str("%Y-%m-%d 17:00", time() - 24*60*60 );
  2. my $end = time2str("%Y-%m-%d 17:00", time());
复制代码

作者: 523066680    时间: 2019-7-13 08:51

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




欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2