现在搞跨境电商, | | | | | | | | | | | | | 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"; | | | | | | 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 ) | | { | | | | 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); | | | | | | 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(""); | | | | | | $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 = ""; | | | | | | | | 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(); | | | | | | my $st = $res->json->{'content'}{'data'}{'st'}; | | say "st: ", $st; | | | | | | | | 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; | | | | | | 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" | | ); | | | | $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/; | | | | our $COUNTRY = retrieve("CountryName_EN2CN.perldb"); | | our %country = ( 'China' => '中国', 'Spain' => '西班牙', 'Russian Federation' => '俄罗斯' ); | | }COPY |
国家名称映射表,英文转中文
$COUNTRY->{'English Name'} = [ 中文名, 英文名国际缩写 ]
输出结果(手动改了型号) | 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 pcsCOPY |
分类统计的时候会判断单位是台还是对,一对的项目数量*2
时间范围限定: | my $begin = time2str("%Y-%m-%d 17:00", time() - 24*60*60 ); | | my $end = time2str("%Y-%m-%d 17:00", time());COPY |
|