ey-commerce-lib 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ey-commerce-lib might be problematic. Click here for more details.
- ey_commerce_lib/__init__.py +1 -0
- ey_commerce_lib/dxm/__init__.py +0 -0
- ey_commerce_lib/dxm/constant/__init__.py +0 -0
- ey_commerce_lib/dxm/constant/order.py +80 -0
- ey_commerce_lib/dxm/exception/__init__.py +0 -0
- ey_commerce_lib/dxm/exception/common.py +7 -0
- ey_commerce_lib/dxm/main.py +396 -0
- ey_commerce_lib/dxm/order.py +2 -0
- ey_commerce_lib/dxm/parser/__init__.py +0 -0
- ey_commerce_lib/dxm/parser/common.py +72 -0
- ey_commerce_lib/dxm/parser/order.py +337 -0
- ey_commerce_lib/dxm/parser/purchase.py +40 -0
- ey_commerce_lib/dxm/parser/warehouse.py +65 -0
- ey_commerce_lib/dxm/schemas/__init__.py +0 -0
- ey_commerce_lib/dxm/schemas/common.py +13 -0
- ey_commerce_lib/dxm/schemas/order.py +273 -0
- ey_commerce_lib/dxm/schemas/warehouse.py +161 -0
- ey_commerce_lib/py.typed +0 -0
- ey_commerce_lib/utils/__init__.py +0 -0
- ey_commerce_lib/utils/dxm.py +43 -0
- ey_commerce_lib/utils/list_util.py +23 -0
- ey_commerce_lib/utils/str.py +3 -0
- ey_commerce_lib-1.0.0.dist-info/METADATA +11 -0
- ey_commerce_lib-1.0.0.dist-info/RECORD +25 -0
- ey_commerce_lib-1.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from ey_commerce_lib.dxm.schemas.order import DxmOrderRule, DxmOrderRuleCond, DxmOrderReviewRule, DxmOrderLogisticsRule
|
|
4
|
+
from ey_commerce_lib.utils.dxm import get_remaining_ship_time, get_data_custom_mark_to_str
|
|
5
|
+
from ey_commerce_lib.utils.list_util import get_str_list_first_not_blank_or_none
|
|
6
|
+
from lxml import html
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_single_order_item_list(order_element: html.HtmlElement):
|
|
10
|
+
"""
|
|
11
|
+
获取单个订单项的订单列表
|
|
12
|
+
:return:
|
|
13
|
+
"""
|
|
14
|
+
sku_list = list()
|
|
15
|
+
sku_element_list = order_element.xpath('.//tr[contains(@class, "pairProInfo")]')
|
|
16
|
+
for sku_element in sku_element_list:
|
|
17
|
+
sku = sku_element.xpath('.//a[contains(@class, "pairProInfoSku")]/text()')[0]
|
|
18
|
+
img = get_str_list_first_not_blank_or_none(sku_element.xpath('.//img/@data-original'))
|
|
19
|
+
quantity = sku_element.xpath('.//p[@class="limingcentUrlpicson"]/span/text()')[0]
|
|
20
|
+
# 价格
|
|
21
|
+
currency, price = \
|
|
22
|
+
sku_element.xpath('.//p[@class="limingcentUrlpicson"]/following-sibling::p[1]/text()')[
|
|
23
|
+
0].split(' ')
|
|
24
|
+
# 变种
|
|
25
|
+
variants = sku_element.xpath(
|
|
26
|
+
'.//p[@class="pairProInfoName orderPairNameIsOverlength"]/span[@class="isOverLengThHide"]/text()')
|
|
27
|
+
variant_list = list()
|
|
28
|
+
for variant in variants:
|
|
29
|
+
variant_list.append({
|
|
30
|
+
'name': variant.split(':')[0].strip(),
|
|
31
|
+
'value': variant.split(':')[1].strip()
|
|
32
|
+
})
|
|
33
|
+
sku_list.append({
|
|
34
|
+
'sku': sku,
|
|
35
|
+
'quantity': int(quantity),
|
|
36
|
+
'price': float(price.replace(',', '')),
|
|
37
|
+
'currency': currency,
|
|
38
|
+
'img': img,
|
|
39
|
+
'variants': variant_list
|
|
40
|
+
})
|
|
41
|
+
# 订单金额
|
|
42
|
+
currency, price = order_element.xpath('./td[2]/text()')[0].strip().split(' ')
|
|
43
|
+
recipient = None
|
|
44
|
+
country = None
|
|
45
|
+
if order_element.xpath('.//td[3]/span/text()')[0] != '「」':
|
|
46
|
+
# 收件人
|
|
47
|
+
recipient = order_element.xpath('.//td[3]/span/text()')[0]
|
|
48
|
+
country = order_element.xpath('.//td[3]/span/text()')[1].replace('「', '').replace('」', '')
|
|
49
|
+
# 订单号
|
|
50
|
+
order_id = order_element.xpath('.//td[4]//a[contains(@class, "limingcentUrlpic")]/text()')[0]
|
|
51
|
+
# 备注
|
|
52
|
+
remark = get_str_list_first_not_blank_or_none(
|
|
53
|
+
order_element.xpath('.//td[4]//span[contains(@class, "buyerNotes")]/@data-content'))
|
|
54
|
+
# 下单时间等信息
|
|
55
|
+
time_element_list = order_element.xpath('.//td[5]/div')
|
|
56
|
+
time_dict = dict()
|
|
57
|
+
for time_element in time_element_list:
|
|
58
|
+
# 如果存在id,说明是剩余发货时间需要动态计算
|
|
59
|
+
if len(time_element.xpath('@id')) > 0:
|
|
60
|
+
script_str = time_element.xpath('./script/text()')[0].strip()
|
|
61
|
+
m = re.search(r'addTimer\(".*?",\s*(\d+),', script_str)
|
|
62
|
+
remaining_ship_time = None
|
|
63
|
+
if m:
|
|
64
|
+
# 剩余发货时间
|
|
65
|
+
remaining_ship_time = get_remaining_ship_time(int(m.group(1)))
|
|
66
|
+
# 如果是None就代表已到期
|
|
67
|
+
time_dict['remaining_ship_time'] = remaining_ship_time
|
|
68
|
+
|
|
69
|
+
else:
|
|
70
|
+
time_name, time_value = time_element.xpath('text()')[0].split(":")
|
|
71
|
+
if time_name == '下单':
|
|
72
|
+
time_dict['order_time'] = time_value
|
|
73
|
+
elif time_name == '付款':
|
|
74
|
+
time_dict['pay_time'] = time_value
|
|
75
|
+
elif time_name == '发货':
|
|
76
|
+
time_dict['ship_time'] = time_value
|
|
77
|
+
elif time_name == '提交':
|
|
78
|
+
time_dict['submit_time'] = time_value
|
|
79
|
+
else:
|
|
80
|
+
time_dict[time_name] = time_value
|
|
81
|
+
return [{
|
|
82
|
+
'sku_list': sku_list,
|
|
83
|
+
'currency': currency,
|
|
84
|
+
'price': float(price.replace(',', '')),
|
|
85
|
+
'recipient': recipient,
|
|
86
|
+
'country': country,
|
|
87
|
+
'order_id': order_id,
|
|
88
|
+
'remark': remark,
|
|
89
|
+
'time': time_dict
|
|
90
|
+
}]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_merge_order_item_list(order_element_list: list[html.HtmlElement]):
|
|
94
|
+
"""
|
|
95
|
+
解析获取合并单的订单项列表
|
|
96
|
+
:return:
|
|
97
|
+
"""
|
|
98
|
+
order_item_list = list()
|
|
99
|
+
for order_element in order_element_list:
|
|
100
|
+
order_item_list.extend(get_single_order_item_list(order_element))
|
|
101
|
+
return order_item_list
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_order_buyer_select_provider(good_element: html.HtmlElement):
|
|
105
|
+
"""
|
|
106
|
+
获取买家指定
|
|
107
|
+
:return:
|
|
108
|
+
"""
|
|
109
|
+
# 第一种情况
|
|
110
|
+
buyer_select_provider_list = good_element.xpath('.//span[contains(@class, "buyerSelectProvider")]/text()')
|
|
111
|
+
# 第二种情况
|
|
112
|
+
buyer_select_provider_2_list = good_element.xpath('./td[3]/text()')[0].strip().split(":")
|
|
113
|
+
if len(buyer_select_provider_list) > 0:
|
|
114
|
+
buyer_select_provider = buyer_select_provider_list[0]
|
|
115
|
+
elif len(buyer_select_provider_2_list) == 2:
|
|
116
|
+
buyer_select_provider = buyer_select_provider_2_list[1].strip()
|
|
117
|
+
else:
|
|
118
|
+
buyer_select_provider = None
|
|
119
|
+
return buyer_select_provider
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def list_order_base_by_html(html_str: str) -> list[dict]:
|
|
123
|
+
"""
|
|
124
|
+
获取基本的订单分页信息
|
|
125
|
+
有三种情况:
|
|
126
|
+
1. 合并单
|
|
127
|
+
2. 一单多件
|
|
128
|
+
3. 普通一单一件
|
|
129
|
+
:param html_str:
|
|
130
|
+
:return:
|
|
131
|
+
"""
|
|
132
|
+
tree = html.fromstring(html_str)
|
|
133
|
+
good_element_list = tree.xpath('//tbody[@class="xianshishujudate"]/tr[@class="goodsId"]')
|
|
134
|
+
order_list = list()
|
|
135
|
+
table_columns = tree.xpath('//table[@id="orderListTable"]/thead/tr/th/text()')
|
|
136
|
+
# 是否又物流方式
|
|
137
|
+
has_logistics = True if '物流方式' in table_columns else False
|
|
138
|
+
for good_element in good_element_list:
|
|
139
|
+
# 包裹号
|
|
140
|
+
package_number = good_element.xpath('.//a[@class="limingcentUrlpic"]/text()')[0]
|
|
141
|
+
# 包裹id
|
|
142
|
+
package_id = good_element.xpath('.//input[@class="input1"]/@value')[0]
|
|
143
|
+
# authid 物流方式的id
|
|
144
|
+
auth_id = good_element.xpath(f'.//input[@id="dxmAuthId{package_id}"]/@value')[0]
|
|
145
|
+
buyer_select_provider = get_order_buyer_select_provider(good_element)
|
|
146
|
+
order_form_source = good_element.xpath('.//span[contains(@class, "order-form-source")]/text()')[0]
|
|
147
|
+
platform, shop = order_form_source.replace('「', '').replace('」', '').split(':')
|
|
148
|
+
order_class = f"orderId_{package_id}"
|
|
149
|
+
order_element_list = tree.xpath(f'//tr[@class="{order_class}"]')
|
|
150
|
+
order_first_element = order_element_list[0]
|
|
151
|
+
# 订单备注
|
|
152
|
+
hover_prompt_content_list = good_element.xpath('.//span[contains(@class, "hoverPrompt")]/@data-content')
|
|
153
|
+
# 物流方式, 要先检查是否包含物流方式这一列
|
|
154
|
+
logistics_info = None
|
|
155
|
+
if has_logistics:
|
|
156
|
+
# 物流方式
|
|
157
|
+
logistics_list = order_first_element.xpath('.//td[6]/span/a/text()')
|
|
158
|
+
# 可能又不存在的物流方式情况发生
|
|
159
|
+
if len(logistics_list) > 0:
|
|
160
|
+
logistics_info = dict()
|
|
161
|
+
logistics = logistics_list[0].strip()
|
|
162
|
+
# 物流单号
|
|
163
|
+
logistics_info['track_number'] = get_str_list_first_not_blank_or_none(
|
|
164
|
+
order_first_element.xpath('.//td[6]//span[contains(@class, "limingcentUrlpicson")]/a/text()'))
|
|
165
|
+
logistics_info['logistics'] = logistics
|
|
166
|
+
# 状态
|
|
167
|
+
if has_logistics:
|
|
168
|
+
status = order_first_element.xpath('.//td[7]/text()')[0].strip()
|
|
169
|
+
else:
|
|
170
|
+
status = order_first_element.xpath('.//td[6]/text()')[0].strip()
|
|
171
|
+
# 整理订单
|
|
172
|
+
if len(order_element_list) > 1:
|
|
173
|
+
# 合并单
|
|
174
|
+
order_item_list = get_merge_order_item_list(order_element_list)
|
|
175
|
+
else:
|
|
176
|
+
# 普通单
|
|
177
|
+
order_item_list = get_single_order_item_list(order_element_list[0])
|
|
178
|
+
order_list.append({
|
|
179
|
+
'package_id': package_id,
|
|
180
|
+
'auth_id': auth_id,
|
|
181
|
+
'package_number': package_number,
|
|
182
|
+
'buyer_select_provider': buyer_select_provider,
|
|
183
|
+
'platform': platform,
|
|
184
|
+
'shop': shop,
|
|
185
|
+
'hover_prompt_content_list': hover_prompt_content_list,
|
|
186
|
+
'logistics_info': logistics_info,
|
|
187
|
+
'status': status,
|
|
188
|
+
'order_item_list': order_item_list
|
|
189
|
+
})
|
|
190
|
+
return order_list
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def list_order_rule(html_str: str):
|
|
194
|
+
"""
|
|
195
|
+
获取订单规则列表
|
|
196
|
+
:return:
|
|
197
|
+
"""
|
|
198
|
+
tree = html.fromstring(html_str)
|
|
199
|
+
rule_element_list = tree.xpath('//tbody[@id="ruleTbody"]/tr[@class="content rulesTr"]')
|
|
200
|
+
rule_list = list()
|
|
201
|
+
for rule_element in rule_element_list:
|
|
202
|
+
rule_id = rule_element.xpath('./td[1]/input/@data-id')[0]
|
|
203
|
+
rule_name = rule_element.xpath('./td[2]/text()')[0]
|
|
204
|
+
rule_list.append({
|
|
205
|
+
'rule_id': rule_id,
|
|
206
|
+
'rule_name': rule_name
|
|
207
|
+
})
|
|
208
|
+
return rule_list
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def get_rule_detail(html_str: str) -> DxmOrderRule:
|
|
212
|
+
"""
|
|
213
|
+
根据订单规则的html获取订单规则详情
|
|
214
|
+
:param html_str:
|
|
215
|
+
:return:
|
|
216
|
+
"""
|
|
217
|
+
tree = html.fromstring(html_str)
|
|
218
|
+
cond_element_list = tree.xpath('//ul[@id="chooseSelectUl"]/li')
|
|
219
|
+
cond_list = list()
|
|
220
|
+
# 获取规则的条件
|
|
221
|
+
for cond_element in cond_element_list:
|
|
222
|
+
cond_val = cond_element.xpath('./input[@name="condVal"]/@value')[0]
|
|
223
|
+
cond_id = cond_element.xpath('./input[@name="condId"]/@value')[0]
|
|
224
|
+
cond_name = cond_element.xpath('./input[@name="condName"]/@value')[0]
|
|
225
|
+
cond_unit = cond_element.xpath('./input[@name="condUnit"]/@value')[0]
|
|
226
|
+
cond_type = cond_element.xpath('./input[@name="condType"]/@value')[0]
|
|
227
|
+
cond_list.append(DxmOrderRuleCond(cond_val=cond_val,
|
|
228
|
+
cond_id=cond_id,
|
|
229
|
+
cond_name=cond_name,
|
|
230
|
+
cond_unit=cond_unit,
|
|
231
|
+
cond_type=cond_type))
|
|
232
|
+
# 判断是物流规则还是审核规则
|
|
233
|
+
modal_title = tree.xpath('//h4[@class="modal-title"]/text()')[0]
|
|
234
|
+
rule_id = tree.xpath('//input[@name="id"]/@value')[0]
|
|
235
|
+
rule_type = tree.xpath('//input[@name="type"]/@value')[0]
|
|
236
|
+
rule_name = tree.xpath('//input[@id="ruleName"]/@value')[0]
|
|
237
|
+
|
|
238
|
+
kfbz = get_str_list_first_not_blank_or_none(tree.xpath('//textarea[@name="kfbz"]/text()'))
|
|
239
|
+
jhbz = get_str_list_first_not_blank_or_none(tree.xpath('//textarea[@name="jhbz"]/@value'))
|
|
240
|
+
jh_color = tree.xpath('//a[contains(@class, "bgCommentFocus")]/@data-val')[0]
|
|
241
|
+
other_action_checked_list = tree.xpath('//input[@name="otherAction"]/@checked')
|
|
242
|
+
other_action = 'on' if len(other_action_checked_list) > 0 else ''
|
|
243
|
+
custom_mark = tree.xpath('//div[contains(@class, "customMarkRuleEl")]/@data-custom-mark')[0]
|
|
244
|
+
|
|
245
|
+
if modal_title.count('物流') > 0:
|
|
246
|
+
warehouse_element_list = tree.xpath('//select[@id="ruleWareIdSelect"]//option')
|
|
247
|
+
warehouse_id = ''
|
|
248
|
+
distribute_type = ''
|
|
249
|
+
for warehouse_element in warehouse_element_list:
|
|
250
|
+
if warehouse_element.get('selected') == 'selected':
|
|
251
|
+
warehouse_id = warehouse_element.get('value')
|
|
252
|
+
distribute_type_element_list = tree.xpath('//input[@name="distributeType"]')
|
|
253
|
+
for distribute_type_element in distribute_type_element_list:
|
|
254
|
+
if distribute_type_element.get('checked') == 'checked':
|
|
255
|
+
distribute_type = distribute_type_element.get('value')
|
|
256
|
+
auth_ids = tree.xpath('//input[@name="authIds"]/@value')[0]
|
|
257
|
+
pattern = re.compile(r"if\s*\(\s*'(\d+)'\s*===\s*item\.idStr")
|
|
258
|
+
auth_id = pattern.findall(html_str)[0]
|
|
259
|
+
|
|
260
|
+
# 物流规则
|
|
261
|
+
dxm_rule_order = DxmOrderLogisticsRule(dxm_cond_list=cond_list, id=rule_id, type=rule_type,
|
|
262
|
+
rule_name=rule_name, kfbz=kfbz, jhbz=jhbz,
|
|
263
|
+
jh_color=jh_color, other_action=other_action,
|
|
264
|
+
custom_mark=get_data_custom_mark_to_str(custom_mark),
|
|
265
|
+
ware_id=warehouse_id, auth_id=auth_id, distribute_type=distribute_type,
|
|
266
|
+
auth_ids=auth_ids
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
action = tree.xpath('//input[@name="action"]/@value')[0]
|
|
270
|
+
dxm_rule_order = DxmOrderReviewRule(dxm_cond_list=cond_list, id=rule_id, type=rule_type,
|
|
271
|
+
rule_name=rule_name, kfbz=kfbz, jhbz=jhbz,
|
|
272
|
+
jh_color=jh_color, other_action=other_action,
|
|
273
|
+
custom_mark=get_data_custom_mark_to_str(custom_mark),
|
|
274
|
+
action=action
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return dxm_rule_order
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def get_order_detail_by_html(html_str: str):
|
|
281
|
+
tree = html.fromstring(html_str)
|
|
282
|
+
recipient = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailContact1"]/@data-info'))
|
|
283
|
+
phone = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailPhone1"]/@data-info'))
|
|
284
|
+
mobile = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailMobile1"]/@data-info'))
|
|
285
|
+
country = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailCountry1"]/@data-country'))
|
|
286
|
+
province = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailProvince1"]/text()'))
|
|
287
|
+
city = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailCity1"]/text()'))
|
|
288
|
+
addr1 = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailAddr11"]/@data-info'))
|
|
289
|
+
addr2 = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailAddress21"]/@data-info'))
|
|
290
|
+
company = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="companyName1"]/text()'))
|
|
291
|
+
apartment = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="apartmentNumber1"]/text()'))
|
|
292
|
+
zip_code = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="detailZip1"]/text()'))
|
|
293
|
+
tax_number = get_str_list_first_not_blank_or_none(tree.xpath('//div[@id="taxNumber1"]/text()'))
|
|
294
|
+
|
|
295
|
+
pair_info_element_list = tree.xpath('//tr[@class="orderInfoCon pairProInfoBox"]')
|
|
296
|
+
ids = re.findall(r"var\s+storageId\s*=\s*['\"](\d+)['\"]", html_str)
|
|
297
|
+
# 有就取第一个,否则 None
|
|
298
|
+
storage_id = ids[0] if ids else None
|
|
299
|
+
pair_info_list = []
|
|
300
|
+
for pair_info_element in pair_info_element_list:
|
|
301
|
+
pair_info_sku = pair_info_element.xpath('.//span[@class="pairProInfoSku"]/text()')[0].split(' x')[0].strip()
|
|
302
|
+
pair_info_sku_quantity = int(pair_info_element.xpath('.//span[@class="pairProInfoSku"]/span/text()')[0].strip())
|
|
303
|
+
# warehouse_sku, warehouse_sku_quantity = pair_info_element.xpath(
|
|
304
|
+
# './/div[contains(@class, "normalDiv")]/p[1]/text()')[0].split(' x ')
|
|
305
|
+
warehouse_sku_info_list = pair_info_element.xpath('.//div[contains(@class, "normalDiv")]/p[1]/text()')
|
|
306
|
+
warehouse_sku, warehouse_sku_quantity = None, None
|
|
307
|
+
if len(warehouse_sku_info_list) > 0:
|
|
308
|
+
warehouse_sku_info = warehouse_sku_info_list[0]
|
|
309
|
+
warehouse_sku, warehouse_sku_quantity = warehouse_sku_info.split(' x ')
|
|
310
|
+
|
|
311
|
+
warehouse_available_quantity_element_list = pair_info_element.xpath(
|
|
312
|
+
'.//div[contains(@class, "normalDiv")]/p[2]/span[2]/text()')
|
|
313
|
+
warehouse_available_quantity = int(warehouse_available_quantity_element_list[0].strip()) if len(
|
|
314
|
+
warehouse_available_quantity_element_list) > 0 else None
|
|
315
|
+
pair_info_list.append({
|
|
316
|
+
'pair_info_sku': pair_info_sku,
|
|
317
|
+
'pair_info_sku_quantity': pair_info_sku_quantity,
|
|
318
|
+
'warehouse_sku': warehouse_sku,
|
|
319
|
+
'warehouse_sku_quantity': warehouse_sku_quantity,
|
|
320
|
+
'warehouse_available_quantity': warehouse_available_quantity
|
|
321
|
+
})
|
|
322
|
+
return {
|
|
323
|
+
'recipient': recipient,
|
|
324
|
+
'phone': phone,
|
|
325
|
+
'mobile': mobile,
|
|
326
|
+
'country': country,
|
|
327
|
+
'province': province,
|
|
328
|
+
'city': city,
|
|
329
|
+
'addr1': addr1,
|
|
330
|
+
'addr2': addr2,
|
|
331
|
+
'company': company,
|
|
332
|
+
'apartment': apartment,
|
|
333
|
+
'zip_code': zip_code,
|
|
334
|
+
'tax_number': tax_number,
|
|
335
|
+
'pair_info_list': pair_info_list,
|
|
336
|
+
'storage_id': storage_id
|
|
337
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from lxml import html
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def list_purchasing_all(html_str: str):
|
|
5
|
+
tree = html.fromstring(html_str)
|
|
6
|
+
good_element_list: list[html.HtmlElement] = tree.xpath('//tr[contains(@class, "goodsId")]')
|
|
7
|
+
for good_element in good_element_list:
|
|
8
|
+
purchase_id = good_element.xpath('@id')[0]
|
|
9
|
+
purchase_order_number = good_element.xpath('.//a[@class="limingcentUrlpic"]/text()')[0]
|
|
10
|
+
ghs_id = good_element.xpath('.//span[contains(@class, "ghsHoverPrompt")]/@data-ghsid')[0]
|
|
11
|
+
ghs_name = good_element.xpath('.//span[contains(@class, "ghsHoverPrompt")]/span/text()')[0].strip()
|
|
12
|
+
warehouse_name, purchase_info = good_element.xpath('.//td[4]/span/text()')[0].strip().split('|')
|
|
13
|
+
# 采购员
|
|
14
|
+
agent_name = purchase_info.split(':')[1]
|
|
15
|
+
#print(purchase_order_number, ghs_id, ghs_name, warehouse_name, agent_name)
|
|
16
|
+
# 获取兄弟元素
|
|
17
|
+
content_element = good_element.getnext()
|
|
18
|
+
# 获取商品信息
|
|
19
|
+
img = content_element.xpath('.//img/@data-original')[0]
|
|
20
|
+
content_number_info = content_element.xpath('./td[2]/text()')
|
|
21
|
+
product_zl_number = None
|
|
22
|
+
purchase_number = None
|
|
23
|
+
for content_number in content_number_info:
|
|
24
|
+
content_number = content_number.strip()
|
|
25
|
+
if content_number.split(':')[0] == '商品种类':
|
|
26
|
+
product_zl_number = content_number.split(':')[1].strip()
|
|
27
|
+
elif content_number.split(':')[0] == '采购数量':
|
|
28
|
+
purchase_number = content_number.split(':')[1].strip()
|
|
29
|
+
# 解析出货款
|
|
30
|
+
total_amount = content_element.xpath('./td[3]//input/@data-totalamount')[0]
|
|
31
|
+
# 运费
|
|
32
|
+
shipping_amount = content_element.xpath('./td[3]//input/@value')[0]
|
|
33
|
+
platform_list = content_element.xpath('./td[4]/div/span')
|
|
34
|
+
if len(platform_list) > 0:
|
|
35
|
+
source = platform_list[0].text.strip()
|
|
36
|
+
else:
|
|
37
|
+
source = content_element.xpath('./td[4]/span/span/text()')[0].strip()
|
|
38
|
+
source2 = content_element.xpath('./td[4]/span/span[@class="alibabaPurchaseOrder"]/text()')[0].strip()
|
|
39
|
+
source = source + source2
|
|
40
|
+
print(source)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from ey_commerce_lib.dxm.schemas.warehouse import WarehouseProduct
|
|
2
|
+
from lxml import html
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def __get_warehouse_product_by_xpath_element(warehouse_product_element: html.HtmlElement) -> WarehouseProduct:
|
|
6
|
+
sku = warehouse_product_element.xpath('.//span[contains(@class, "productSku")]/text()')[0].strip()
|
|
7
|
+
name_list = warehouse_product_element.xpath('.//p[contains(@class, "name")]/text()')
|
|
8
|
+
name = name_list[0].strip() if len(name_list) > 0 else ''
|
|
9
|
+
sku_code = warehouse_product_element.xpath('.//div[contains(@class, "skuCode")]/span/text()')[0].strip()
|
|
10
|
+
img = warehouse_product_element.xpath('.//img/@src')[0].strip()
|
|
11
|
+
shelf_position = warehouse_product_element.xpath('.//td[3]/text()')[0].strip()
|
|
12
|
+
# 库存详情元素
|
|
13
|
+
warehouse_product_stock_element = warehouse_product_element.xpath('.//td[4]//tbody/tr')[0]
|
|
14
|
+
# 安全库存
|
|
15
|
+
try:
|
|
16
|
+
safe_stock = int(warehouse_product_stock_element.xpath('./td[1]/span/text()')[0])
|
|
17
|
+
except:
|
|
18
|
+
safe_stock = None
|
|
19
|
+
try:
|
|
20
|
+
# # 在途库存
|
|
21
|
+
on_the_way_stock = int(warehouse_product_stock_element.xpath('./td[2]/span/text()')[0])
|
|
22
|
+
except:
|
|
23
|
+
on_the_way_stock = None
|
|
24
|
+
# 未发库存
|
|
25
|
+
try:
|
|
26
|
+
not_shipped_stock = int(warehouse_product_stock_element.xpath('./td[3]/span/text()')[0])
|
|
27
|
+
except:
|
|
28
|
+
not_shipped_stock = None
|
|
29
|
+
try:
|
|
30
|
+
# # 占用库存
|
|
31
|
+
occupy_stock = int(warehouse_product_stock_element.xpath('./td[4]/span/text()')[0])
|
|
32
|
+
except:
|
|
33
|
+
occupy_stock = None
|
|
34
|
+
# # 可用库存
|
|
35
|
+
try:
|
|
36
|
+
available_stock = int(warehouse_product_stock_element.xpath('./td[5]/span/text()')[0])
|
|
37
|
+
except:
|
|
38
|
+
available_stock = None
|
|
39
|
+
# 总量库存
|
|
40
|
+
try:
|
|
41
|
+
total_stock = int(warehouse_product_stock_element.xpath('./td[6]/span/text()')[0])
|
|
42
|
+
except:
|
|
43
|
+
total_stock = None
|
|
44
|
+
# 单价
|
|
45
|
+
price = float(warehouse_product_element.xpath('./td[5]/text()')[0])
|
|
46
|
+
# 总价
|
|
47
|
+
total_price = float(warehouse_product_element.xpath('./td[6]/text()')[0])
|
|
48
|
+
# 更新时间
|
|
49
|
+
update_time = warehouse_product_element.xpath('./td[7]/div[1]/text()')[0]
|
|
50
|
+
# 创建时间
|
|
51
|
+
create_time = warehouse_product_element.xpath('./td[7]/div[2]/text()')[0]
|
|
52
|
+
return WarehouseProduct(sku=sku, name=name, sku_code=sku_code, img=img, shelf_position=shelf_position,
|
|
53
|
+
safe_stock=safe_stock, on_the_way_stock=on_the_way_stock,
|
|
54
|
+
not_shipped_stock=not_shipped_stock, occupy_stock=occupy_stock,
|
|
55
|
+
available_stock=available_stock, total_stock=total_stock, price=price,
|
|
56
|
+
total_price=total_price, update_time=update_time, create_time=create_time)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def list_warehouse_product(html_content: str) -> list[WarehouseProduct]:
|
|
60
|
+
tree = html.fromstring(html_content)
|
|
61
|
+
warehouse_product_element_list = tree.xpath('//tbody/tr[@class="content"]')
|
|
62
|
+
warehouse_product_list = list()
|
|
63
|
+
for warehouse_product_element in warehouse_product_element_list:
|
|
64
|
+
warehouse_product_list.append(__get_warehouse_product_by_xpath_element(warehouse_product_element))
|
|
65
|
+
return warehouse_product_list
|
|
File without changes
|