From 16a31f92c5fb9a98446e5681bd4186141d9c9639 Mon Sep 17 00:00:00 2001 From: va1is Date: Mon, 28 Jul 2025 16:20:11 +0300 Subject: [PATCH] commit --- .gitignore | 2 +- Parsing ZARAHOME/add_depend_stock.py | 36 + .../__pycache__/categories.cpython-311.pyc | Bin 0 -> 763 bytes .../__pycache__/categories.cpython-312.pyc | Bin 0 -> 720 bytes .../__pycache__/categories.cpython-313.pyc | Bin 0 -> 723 bytes .../src/__pycache__/extractor.cpython-311.pyc | Bin 0 -> 35355 bytes .../src/__pycache__/extractor.cpython-312.pyc | Bin 0 -> 17443 bytes .../src/__pycache__/extractor.cpython-313.pyc | Bin 0 -> 11515 bytes .../src/__pycache__/requester.cpython-311.pyc | Bin 0 -> 3078 bytes .../src/__pycache__/requester.cpython-312.pyc | Bin 0 -> 2699 bytes .../src/__pycache__/requester.cpython-313.pyc | Bin 0 -> 2769 bytes .../__pycache__/xlsx_recorder.cpython-311.pyc | Bin 0 -> 1494 bytes .../__pycache__/xlsx_recorder.cpython-312.pyc | Bin 0 -> 1277 bytes .../__pycache__/xlsx_recorder.cpython-313.pyc | Bin 0 -> 1342 bytes Parsing ZARAHOME/src/categories-old1.xlsx | Bin 0 -> 14178 bytes Parsing ZARAHOME/src/categories.py | 17 + Parsing ZARAHOME/src/categories.xlsx | Bin 0 -> 54452 bytes Parsing ZARAHOME/src/extractor copy 2.py | 344 + Parsing ZARAHOME/src/extractor copy 3.py | 317 + .../src/extractor copy 4 -delthesame1.py | 379 + Parsing ZARAHOME/src/extractor copy.py | 940 ++ ...tor автономный для сбора категорий copy.py | 11 + ...xtractor автономный для сбора категорий.py | 71 + ...extractor автономный для списка товаров.py | 173 + ...r вывод всего содержимого json в файлах.py | 996 ++ Parsing ZARAHOME/src/extractor.py | 341 + Parsing ZARAHOME/src/links.xlsx | Bin 0 -> 11317 bytes Parsing ZARAHOME/src/main.py | 24 + Parsing ZARAHOME/src/parse_settings.json | 4 + Parsing ZARAHOME/src/records_folder.zip | Bin 0 -> 3009496 bytes .../src/records_folder/Allfile-old.xlsx | Bin 0 -> 2595022 bytes .../src/records_folder/Allfile-output.json | 11258 ++++++++++++++++ .../src/records_folder/AllfileFORjson1.xlsx | Bin 0 -> 204522 bytes ...at-home-with-vincent-van-duysen-n5361.xlsx | Bin 0 -> 37128 bytes .../records_folder/baby-bed-linen-n3948.xlsx | Bin 0 -> 12374 bytes .../records_folder/baby-blankets-n4264.xlsx | Bin 0 -> 9311 bytes .../baby-clothing-footwear-all-n4823.xlsx | Bin 0 -> 32761 bytes .../baby-n1153?celement=1020585785.xlsx | Bin 0 -> 10441 bytes .../src/records_folder/baby-new-in-n4215.xlsx | Bin 0 -> 64338 bytes .../records_folder/baby-soft-toys-n3949.xlsx | Bin 0 -> 8501 bytes .../bathroom-accessories-n2470.xlsx | Bin 0 -> 33247 bytes .../bathroom-basic-towels-n1817.xlsx | Bin 0 -> 33306 bytes .../bathroom-baskets-laundry-n3891.xlsx | Bin 0 -> 10033 bytes .../bathroom-bathmats-n1052.xlsx | Bin 0 -> 18655 bytes .../bathroom-bathrobes-n1053.xlsx | Bin 0 -> 39760 bytes .../bathroom-bestsellers-n4187.xlsx | Bin 0 -> 5208 bytes .../records_folder/bathroom-bins-n3827.xlsx | Bin 0 -> 9544 bytes .../records_folder/bathroom-boxes-n3886.xlsx | Bin 0 -> 10801 bytes ...soap-dishes-n5077?celement=1020463438.xlsx | Bin 0 -> 14471 bytes .../bathroom-doorknobs-n4615.xlsx | Bin 0 -> 8628 bytes .../bathroom-mirrors-n2468.xlsx | Bin 0 -> 8457 bytes .../bathroom-self-care-n1418.xlsx | Bin 0 -> 16558 bytes .../bathroom-shower-curtains-n1414.xlsx | Bin 0 -> 6922 bytes .../bathroom-toiletry-wash-bags-n4748.xlsx | Bin 0 -> 12441 bytes .../bathroom-toothbrush-tumblers-n3883.xlsx | Bin 0 -> 10372 bytes .../records_folder/bathroom-towels-n1051.xlsx | Bin 0 -> 71646 bytes .../records_folder/bathroom-trays-n3885.xlsx | Bin 0 -> 8723 bytes .../src/records_folder/beachwear-n2487.xlsx | Bin 0 -> 19828 bytes .../beachwear-n2487?celement=1020662514.xlsx | Bin 0 -> 27580 bytes .../records_folder/bedroom-bedding-n945.xlsx | Bin 0 -> 155684 bytes ...room-bedding-n945?celement=1020583753.xlsx | Bin 0 -> 161193 bytes .../bedroom-bedspreads-n951.xlsx | Bin 0 -> 35686 bytes ...m-bedspreads-n951?celement=1020319878.xlsx | Bin 0 -> 15621 bytes .../bedroom-bestsellers-n4182.xlsx | Bin 0 -> 5208 bytes .../bedroom-cushion-inserts-n958.xlsx | Bin 0 -> 9702 bytes .../records_folder/bedroom-cushions-n964.xlsx | Bin 0 -> 48950 bytes ...oom-cushions-n964?celement=1020319562.xlsx | Bin 0 -> 35162 bytes ...bedroom-duvet-cover-cotton-n5107-json.xlsx | Bin 0 -> 62583 bytes .../bedroom-duvet-cover-cotton-n5107.json | 7785 +++++++++++ .../bedroom-duvet-cover-cotton-n5107.xlsx | Bin 0 -> 45099 bytes ...room-duvet-cover-cotton-n5107with_dub.xlsx | Bin 0 -> 45946 bytes .../bedroom-duvet-cover-sateen-n5065.xlsx | Bin 0 -> 43177 bytes .../bedroom-duvet-covers-n946.xlsx | Bin 0 -> 97740 bytes ...duvet-covers-n946?celement=1020319529.xlsx | Bin 0 -> 91136 bytes .../records_folder/bedroom-duvets-n956.xlsx | Bin 0 -> 12345 bytes .../bedroom-fillings-all-n1384.xlsx | Bin 0 -> 30528 bytes .../bedroom-fitted-sheets-n948.xlsx | Bin 0 -> 70805 bytes ...itted-sheets-n948?celement=1020319530.xlsx | Bin 0 -> 50002 bytes .../bedroom-flat-sheets-n947.xlsx | Bin 0 -> 69784 bytes ...-flat-sheets-n947?celement=1020319532.xlsx | Bin 0 -> 43310 bytes .../bedroom-headboards-n960.xlsx | Bin 0 -> 10127 bytes .../bedroom-jewellery-boxes-n971.xlsx | Bin 0 -> 9416 bytes .../bedroom-linen-duvet-covers-n5108.xlsx | Bin 0 -> 19067 bytes .../bedroom-pillowcases-n949.xlsx | Bin 0 -> 68129 bytes ...-pillowcases-n949?celement=1020319531.xlsx | Bin 0 -> 78182 bytes .../records_folder/bedroom-pillows-n957.xlsx | Bin 0 -> 9630 bytes .../bedroom-protectors-n953.xlsx | Bin 0 -> 14182 bytes .../bedroom-throws-blankets-n963.xlsx | Bin 0 -> 17023 bytes ...ows-blankets-n963?celement=1020319561.xlsx | Bin 0 -> 18738 bytes .../records_folder/candle-holders-n1003.xlsx | Bin 0 -> 12571 bytes .../src/records_folder/careers-n5110.xlsx | Bin 0 -> 5209 bytes .../cleaning-products-n1835.xlsx | Bin 0 -> 39613 bytes .../clothing-baby-size-n3905.xlsx | Bin 0 -> 31504 bytes .../collagerie-collection-n5017.xlsx | Bin 0 -> 21464 bytes .../collagerie-editorial-n5018.xlsx | Bin 0 -> 20659 bytes .../contact-shopping-online.html.xlsx | Bin 0 -> 5208 bytes ...ary-stories-n5364?celement=1020694130.xlsx | Bin 0 -> 5208 bytes ...ng-cleaning-n2485?celement=1020480055.xlsx | Bin 0 -> 20040 bytes .../decorative-candles-n1002.xlsx | Bin 0 -> 15270 bytes .../src/records_folder/desks-n5104.xlsx | Bin 0 -> 8586 bytes .../dining-accessories-all-n4138.xlsx | Bin 0 -> 34725 bytes .../dining-accessories-cake-dish-n4864.xlsx | Bin 0 -> 6382 bytes ...accessories-n1041?celement=1020319647.xlsx | Bin 0 -> 12620 bytes .../dining-basket-bread-n4225.xlsx | Bin 0 -> 7236 bytes .../dining-bestsellers-n4186.xlsx | Bin 0 -> 5208 bytes .../records_folder/dining-bowls-n1810.xlsx | Bin 0 -> 16759 bytes .../records_folder/dining-coasters-n1044.xlsx | Bin 0 -> 7825 bytes .../dining-cruets-shakers-n1412.xlsx | Bin 0 -> 8007 bytes ...ets-shakers-n1412?celement=1020695630.xlsx | Bin 0 -> 8720 bytes .../dining-cutlery-dessert-n3918.xlsx | Bin 0 -> 10698 bytes .../dining-cutlery-fork-n3916.xlsx | Bin 0 -> 8011 bytes .../dining-cutlery-knife-n3917.xlsx | Bin 0 -> 8219 bytes .../dining-cutlery-see-all-n4649.xlsx | Bin 0 -> 23120 bytes ...ery-see-all-n4649?celement=1020319646.xlsx | Bin 0 -> 10230 bytes .../dining-cutlery-serving-n1816.xlsx | Bin 0 -> 9027 bytes .../dining-cutlery-spoon-n3915.xlsx | Bin 0 -> 7048 bytes .../dining-dessert-plates-n2475.xlsx | Bin 0 -> 19852 bytes .../dining-dinner-plates-n2473.xlsx | Bin 0 -> 11431 bytes .../dining-glassware-all-n4136.xlsx | Bin 0 -> 44501 bytes ...g-glassware-n1027?celement=1020319645.xlsx | Bin 0 -> 13622 bytes .../src/records_folder/dining-jugs-n1031.xlsx | Bin 0 -> 15438 bytes .../dining-mugs-cups-n1811.xlsx | Bin 0 -> 23749 bytes .../dining-napkin-rings-n1043.xlsx | Bin 0 -> 8221 bytes .../records_folder/dining-napkins-n1037.xlsx | Bin 0 -> 22200 bytes .../dining-other-accessories-n1048.xlsx | Bin 0 -> 8894 bytes .../dining-placemats-n1038.xlsx | Bin 0 -> 21639 bytes ...ning-serving-dishes-salad-bowls-n1025.xlsx | Bin 0 -> 14383 bytes .../dining-sets-cutlery-n1815.xlsx | Bin 0 -> 9582 bytes .../dining-table-linen-n1034.xlsx | Bin 0 -> 71500 bytes ...table-linen-n1034?celement=1020319663.xlsx | Bin 0 -> 25968 bytes .../dining-table-runners-n1039.xlsx | Bin 0 -> 9550 bytes .../dining-tablecloths-n1036.xlsx | Bin 0 -> 35600 bytes .../records_folder/dining-tables-n4743.xlsx | Bin 0 -> 8011 bytes .../dining-tableware-complete-n2472.xlsx | Bin 0 -> 47687 bytes ...re-complete-n2472?celement=1020319643.xlsx | Bin 0 -> 12644 bytes .../records_folder/dining-trays-n1040.xlsx | Bin 0 -> 16667 bytes ...ining-trays-n1040?celement=1020695633.xlsx | Bin 0 -> 11241 bytes .../records_folder/dining-tumblers-n1029.xlsx | Bin 0 -> 21879 bytes .../dining-wine-glasses-n1030.xlsx | Bin 0 -> 19632 bytes .../dinner-deep-soup-plate-n2474.xlsx | Bin 0 -> 9467 bytes .../door-knobs-handles-n1005.xlsx | Bin 0 -> 11833 bytes .../src/records_folder/doormats-n4979.xlsx | Bin 0 -> 6082 bytes .../records_folder/dressing-room-n2463.xlsx | Bin 0 -> 21498 bytes .../records_folder/edited-bathroom-n1416.xlsx | Bin 0 -> 45166 bytes .../records_folder/edited-bedroom-n2496.xlsx | Bin 0 -> 45128 bytes .../records_folder/edited-dining-n2498.xlsx | Bin 0 -> 8401 bytes .../records_folder/edited-homewear-n3937.xlsx | Bin 0 -> 11351 bytes .../src/records_folder/edited-kids-n2499.xlsx | Bin 0 -> 14461 bytes .../records_folder/edited-living-n2497.xlsx | Bin 0 -> 6054 bytes .../records_folder/editorials-all-n4316.xlsx | Bin 0 -> 5208 bytes .../src/records_folder/egg-cups-n5036.xlsx | Bin 0 -> 6794 bytes .../footwear-man-bathroom-slippers-n5287.xlsx | Bin 0 -> 14970 bytes .../footwear-man-clogs-n5282.xlsx | Bin 0 -> 14743 bytes .../footwear-man-house-slippers-n5284.xlsx | Bin 0 -> 17364 bytes .../records_folder/footwear-man-n1392.xlsx | Bin 0 -> 37525 bytes ...ootwear-man-n1392?celement=1020319599.xlsx | Bin 0 -> 18079 bytes .../footwear-man-sandals-n5283.xlsx | Bin 0 -> 8077 bytes .../footwear-woman-ballerinas-n5280.xlsx | Bin 0 -> 10485 bytes ...ootwear-woman-bathroom-slippers-n5286.xlsx | Bin 0 -> 18803 bytes .../footwear-woman-house-slippers-n5281.xlsx | Bin 0 -> 18821 bytes .../records_folder/footwear-woman-n4150.xlsx | Bin 0 -> 56637 bytes ...twear-woman-n4150?celement=1020319596.xlsx | Bin 0 -> 29696 bytes ...twear-woman-n4150?celement=1020319600.xlsx | Bin 0 -> 18191 bytes .../footwear-woman-sandals-n5279.xlsx | Bin 0 -> 20265 bytes .../fragrances-car-air-freshener-n1067.xlsx | Bin 0 -> 8710 bytes .../fragrances-creams-n1063.xlsx | Bin 0 -> 5208 bytes .../fragrances-essences-n4980.xlsx | Bin 0 -> 8033 bytes .../fragrances-home-spray-n1061.xlsx | Bin 0 -> 15105 bytes ...-home-spray-n1061?celement=1020319784.xlsx | Bin 0 -> 6939 bytes .../fragrances-n1057?celement=1020319800.xlsx | Bin 0 -> 12455 bytes .../fragrances-reed-diffusers-n1059.xlsx | Bin 0 -> 37276 bytes ...d-diffusers-n1059?celement=1020319782.xlsx | Bin 0 -> 7167 bytes .../fragrances-scented-candles-n1060.xlsx | Bin 0 -> 30755 bytes ...ted-candles-n1060?celement=1020319781.xlsx | Bin 0 -> 7869 bytes .../records_folder/fragrances-soap-n1420.xlsx | Bin 0 -> 17573 bytes .../fragrances-soaps-creams-n5045.xlsx | Bin 0 -> 20844 bytes ...oaps-creams-n5045?celement=1020464942.xlsx | Bin 0 -> 20826 bytes ...agrances-wardrobe-air-freshener-n1065.xlsx | Bin 0 -> 12627 bytes .../furniture-armchairs-n4106.xlsx | Bin 0 -> 10930 bytes .../furniture-bedside-tables-n4110.xlsx | Bin 0 -> 9253 bytes .../furniture-benches-n4891.xlsx | Bin 0 -> 8070 bytes .../furniture-bestsellers-n5190.xlsx | Bin 0 -> 5208 bytes .../furniture-cabinets-n4899.xlsx | Bin 0 -> 11153 bytes .../furniture-chairs-n4105.xlsx | Bin 0 -> 12697 bytes .../furniture-couches-armchairs-n4113.xlsx | Bin 0 -> 27861 bytes .../src/records_folder/furniture-n4104.xlsx | Bin 0 -> 93609 bytes .../furniture-n4104?celement=1020628420.xlsx | Bin 0 -> 9096 bytes .../furniture-outdoor-n4250.xlsx | Bin 0 -> 9110 bytes .../furniture-pouffes-n4843.xlsx | Bin 0 -> 7006 bytes .../furniture-shelvings-n4898.xlsx | Bin 0 -> 8951 bytes .../furniture-sides-table-n4895.xlsx | Bin 0 -> 13390 bytes .../furniture-stools-n4892.xlsx | Bin 0 -> 12534 bytes .../furniture-storage-n4111.xlsx | Bin 0 -> 9107 bytes .../gift-card-activate.html.xlsx | Bin 0 -> 5208 bytes .../gift-card-balance.html.xlsx | Bin 0 -> 5208 bytes ...ift-ideas-special-occasion-baby-n4355.xlsx | Bin 0 -> 52386 bytes .../src/records_folder/guest-orders.html.xlsx | Bin 0 -> 5208 bytes ...me-decor-accessories-decorative-n1009.xlsx | Bin 0 -> 21760 bytes ...-decorative-n1009?celement=1020660052.xlsx | Bin 0 -> 21619 bytes .../home-decor-baskets-n997.xlsx | Bin 0 -> 20185 bytes ...ecor-baskets-n997?celement=1020319732.xlsx | Bin 0 -> 10866 bytes .../home-decor-bestsellers-n4184.xlsx | Bin 0 -> 5208 bytes .../home-decor-books-books-n3960.xlsx | Bin 0 -> 42585 bytes ...books-books-n3960?celement=1020637429.xlsx | Bin 0 -> 42237 bytes .../home-decor-books-magazines-n3961.xlsx | Bin 0 -> 9061 bytes ...s-magazines-n3961?celement=1020637430.xlsx | Bin 0 -> 9061 bytes .../home-decor-books-n3796.xlsx | Bin 0 -> 48998 bytes ...decor-books-n3796?celement=1020637431.xlsx | Bin 0 -> 48659 bytes .../home-decor-curtains-blinds-n996.xlsx | Bin 0 -> 11654 bytes ...decor-cushions-couch-living-room-n994.xlsx | Bin 0 -> 41786 bytes ...-living-room-n994?celement=1020319721.xlsx | Bin 0 -> 32908 bytes .../home-decor-fillings-n2493.xlsx | Bin 0 -> 7694 bytes .../home-decor-mirrors-living-room-n993.xlsx | Bin 0 -> 14346 bytes .../home-decor-photo-frames-n1000.xlsx | Bin 0 -> 19285 bytes .../home-decor-rugs-living-room-n992.xlsx | Bin 0 -> 29095 bytes ...-living-room-n992?celement=1020319722.xlsx | Bin 0 -> 9527 bytes ...e-decor-throws-living-room-couch-n995.xlsx | Bin 0 -> 17089 bytes ...g-room-couch-n995?celement=1020319720.xlsx | Bin 0 -> 18738 bytes .../homewear-bestsellers-n4183.xlsx | Bin 0 -> 5208 bytes .../src/records_folder/hooks-n4857.xlsx | Bin 0 -> 8206 bytes ...eam-recipes-n5363?celement=1020703134.xlsx | Bin 0 -> 5208 bytes .../src/records_folder/join-life-n3760.xlsx | Bin 0 -> 5208 bytes .../records_folder/kids-bathroom-n1138.xlsx | Bin 0 -> 27573 bytes ...ds-bathroom-n1138?celement=1020319857.xlsx | Bin 0 -> 12111 bytes .../records_folder/kids-bed-linen-n1097.xlsx | Bin 0 -> 60362 bytes ...s-bed-linen-n1097?celement=1020319856.xlsx | Bin 0 -> 40770 bytes .../kids-bedroom-lamps-n1117.xlsx | Bin 0 -> 8846 bytes .../records_folder/kids-bedspreads-n2500.xlsx | Bin 0 -> 12203 bytes .../kids-bestsellers-n4189.xlsx | Bin 0 -> 5208 bytes .../records_folder/kids-blankets-n1115.xlsx | Bin 0 -> 9046 bytes .../kids-books-stationery-n1436.xlsx | Bin 0 -> 18103 bytes ...-stationery-n1436?celement=1020455465.xlsx | Bin 0 -> 18103 bytes .../kids-clothing-footwear-all-n1439.xlsx | Bin 0 -> 5208 bytes .../kids-clothing-kids-size-n3906.xlsx | Bin 0 -> 12345 bytes .../records_folder/kids-curtains-n1118.xlsx | Bin 0 -> 6905 bytes .../kids-cushions-throw-pillows-n1116.xlsx | Bin 0 -> 13160 bytes .../records_folder/kids-decoration-n1123.xlsx | Bin 0 -> 24366 bytes ...-decoration-n1123?celement=1020319870.xlsx | Bin 0 -> 12623 bytes .../records_folder/kids-door-knobs-n1820.xlsx | Bin 0 -> 7321 bytes .../kids-duvet-covers-n1098.xlsx | Bin 0 -> 16988 bytes .../kids-fitted-sheets-n1100.xlsx | Bin 0 -> 15943 bytes .../kids-flat-sheets-n1099.xlsx | Bin 0 -> 11834 bytes .../records_folder/kids-footwear-n1156.xlsx | Bin 0 -> 22747 bytes ...-fragrances-n1440?celement=1020447606.xlsx | Bin 0 -> 6569 bytes .../records_folder/kids-furniture-n1122.xlsx | Bin 0 -> 14852 bytes ...s-furniture-n1122?celement=1020576160.xlsx | Bin 0 -> 16515 bytes .../records_folder/kids-hangers-n1131.xlsx | Bin 0 -> 8209 bytes .../records_folder/kids-mealtime-n1132.xlsx | Bin 0 -> 16274 bytes ...ds-mealtime-n1132?celement=1020319858.xlsx | Bin 0 -> 10779 bytes .../src/records_folder/kids-new-in-n1095.xlsx | Bin 0 -> 106734 bytes .../records_folder/kids-peanuts-n5223.xlsx | Bin 0 -> 23584 bytes .../kids-pillowcases-n1101.xlsx | Bin 0 -> 19381 bytes .../kids-plushies-soft-toys-n1128.xlsx | Bin 0 -> 13707 bytes .../src/records_folder/kids-rugs-n1124.xlsx | Bin 0 -> 7799 bytes .../records_folder/kids-storage-n3831.xlsx | Bin 0 -> 12541 bytes .../src/records_folder/kids-stroll-n1438.xlsx | Bin 0 -> 30779 bytes .../records_folder/kids-toy-story-n5366.xlsx | Bin 0 -> 20216 bytes .../src/records_folder/kids-toys-n1822.xlsx | Bin 0 -> 30649 bytes .../kids-toys-n1822?celement=1020319859.xlsx | Bin 0 -> 9834 bytes .../kitchen-accessories-n1407.xlsx | Bin 0 -> 9352 bytes .../kitchen-appliances-n1016.xlsx | Bin 0 -> 9952 bytes .../records_folder/kitchen-bins-n2464.xlsx | Bin 0 -> 6848 bytes .../kitchen-chopping-boards-n3939.xlsx | Bin 0 -> 7384 bytes .../records_folder/kitchen-coffee-n1019.xlsx | Bin 0 -> 16054 bytes .../kitchen-cookware-n1014.xlsx | Bin 0 -> 11139 bytes .../kitchen-ice-cream-cups-n5351.xlsx | Bin 0 -> 7667 bytes .../kitchen-ice-cream-n5360.xlsx | Bin 0 -> 17118 bytes .../records_folder/kitchen-storage-n3835.xlsx | Bin 0 -> 16346 bytes ...hen-storage-n3835?celement=1020319619.xlsx | Bin 0 -> 11116 bytes .../kitchen-textiles-n1406.xlsx | Bin 0 -> 18340 bytes .../kitchen-utensils-n3870.xlsx | Bin 0 -> 18756 bytes .../records_folder/laundry-care-n1399.xlsx | Bin 0 -> 12282 bytes ...aundry-care-n1399?celement=1020286015.xlsx | Bin 0 -> 22019 bytes .../src/records_folder/lifestyle-n1802.xlsx | Bin 0 -> 62029 bytes .../lifestyle-n1802?celement=1020319841.xlsx | Bin 0 -> 17577 bytes .../lighting-ceiling-lamps-n4884.xlsx | Bin 0 -> 10301 bytes .../lighting-lamps-cordless-n5192.xlsx | Bin 0 -> 10559 bytes .../lighting-lamps-floor-n4882.xlsx | Bin 0 -> 8390 bytes .../records_folder/lighting-lamps-n4847.xlsx | Bin 0 -> 30650 bytes ...hting-lamps-n4847?celement=1020319968.xlsx | Bin 0 -> 8766 bytes .../lighting-lamps-table-n4881.xlsx | Bin 0 -> 19298 bytes .../lighting-lamps-wall-lights-n5339.xlsx | Bin 0 -> 8200 bytes .../loungewear-footwear-bags-n1395.xlsx | Bin 0 -> 18863 bytes ...otwear-bags-n1395?celement=1020319603.xlsx | Bin 0 -> 8428 bytes .../loungewear-footwear-hangers-n1398.xlsx | Bin 0 -> 14944 bytes .../records_folder/loungewear-man-n1389.xlsx | Bin 0 -> 9922 bytes ...ngewear-man-n1389?celement=1020319606.xlsx | Bin 0 -> 7877 bytes .../loungewear-woman-gowns-n1493.xlsx | Bin 0 -> 8282 bytes .../loungewear-woman-n1388.xlsx | Bin 0 -> 46786 bytes ...ewear-woman-n1388?celement=1020319607.xlsx | Bin 0 -> 16334 bytes .../loungewear-woman-nightdresses-n1492.xlsx | Bin 0 -> 14184 bytes .../loungewear-woman-pyjamas-n1494.xlsx | Bin 0 -> 33353 bytes .../new-in-collection-n942.xlsx | Bin 0 -> 108007 bytes .../src/records_folder/newsletter.html.xlsx | Bin 0 -> 5209 bytes .../src/records_folder/outdoor-n2462.xlsx | Bin 0 -> 9097 bytes .../personalisation-baby-n4252.xlsx | Bin 0 -> 12734 bytes .../records_folder/pets-collection-n1561.xlsx | Bin 0 -> 20918 bytes .../picnic-collection-n1812.xlsx | Bin 0 -> 40675 bytes ...ewear-beach-n4485?celement=1020473529.xlsx | Bin 0 -> 20242 bytes .../promo-kids-homewear-n4680.xlsx | Bin 0 -> 37962 bytes .../recipe-18-n4014?celement=1020694129.xlsx | Bin 0 -> 9258 bytes .../recipe-26-n4022?celement=1020694133.xlsx | Bin 0 -> 6417 bytes .../recipe-46-n4042?celement=1020694128.xlsx | Bin 0 -> 6830 bytes .../recipe-47-n4043?celement=1020694132.xlsx | Bin 0 -> 7668 bytes .../recipe-48-n4044?celement=1020694131.xlsx | Bin 0 -> 8524 bytes .../recipe-49-n4045?celement=1020694127.xlsx | Bin 0 -> 8147 bytes .../recipe-93-n4089?celement=1020703138.xlsx | Bin 0 -> 8674 bytes .../recipe-94-n4257?celement=1020703137.xlsx | Bin 0 -> 8745 bytes .../recipe-98-n4261?celement=1020703139.xlsx | Bin 0 -> 8810 bytes .../records_folder/rugs-faux-fur-n5030.xlsx | Bin 0 -> 6375 bytes .../src/records_folder/rugs-jute-n4978.xlsx | Bin 0 -> 9847 bytes .../records_folder/rugs-vintage-n4975.xlsx | Bin 0 -> 10445 bytes .../src/records_folder/rugs-wool-n5034.xlsx | Bin 0 -> 14751 bytes .../src/records_folder/shop-guide.html.xlsx | Bin 0 -> 5209 bytes .../src/records_folder/silk-n4924.xlsx | Bin 0 -> 7856 bytes .../src/records_folder/space-camp-n5357.xlsx | Bin 0 -> 30395 bytes .../records_folder/special-prices-n1170.xlsx | Bin 0 -> 5209 bytes .../src/records_folder/sports-n4936.xlsx | Bin 0 -> 24931 bytes .../records_folder/store-locator.html.xlsx | Bin 0 -> 5209 bytes ...mer-recipes-n5338?celement=1020703133.xlsx | Bin 0 -> 5207 bytes .../records_folder/tiles-todobarro-n5342.xlsx | Bin 0 -> 6432 bytes .../vases-decorative-n1010.xlsx | Bin 0 -> 18359 bytes .../src/records_folder/virtual-card.html.xlsx | Bin 0 -> 5208 bytes .../records_folder/vvd-2-object-n3880.xlsx | Bin 0 -> 25429 bytes .../records_folder/vvd-2-textile-n3881.xlsx | Bin 0 -> 35493 bytes .../src/records_folder/vvd-about-n3878.xlsx | Bin 0 -> 5209 bytes .../records_folder/vvd-campaign-01-n3876.xlsx | Bin 0 -> 5208 bytes .../records_folder/vvd-campaign-02-n3877.xlsx | Bin 0 -> 5207 bytes .../records_folder/vvd-campaign-04-n5350.xlsx | Bin 0 -> 5208 bytes .../records_folder/vvd-campaign03-n4989.xlsx | Bin 0 -> 5208 bytes .../records_folder/vvd-furniture-n3879.xlsx | Bin 0 -> 63346 bytes ...d-furniture-n3879?celement=1020452439.xlsx | Bin 0 -> 46298 bytes .../withdrawn-from-sale-n5187.xlsx | Bin 0 -> 5208 bytes .../zarahomeplus-collection-all-n4214.xlsx | Bin 0 -> 104423 bytes Parsing ZARAHOME/src/request_settings.json | 6 + Parsing ZARAHOME/src/requester.py | 49 + Parsing ZARAHOME/src/result.xlsx | Bin 0 -> 5082 bytes .../src/state_dump_1748005445.json | 1 + Parsing ZARAHOME/src/xlsx_recorder.py | 23 + Parsing ZARAHOME/src/~$categories.xlsx | Bin 0 -> 165 bytes 340 files changed, 22776 insertions(+), 1 deletion(-) create mode 100644 Parsing ZARAHOME/add_depend_stock.py create mode 100644 Parsing ZARAHOME/src/__pycache__/categories.cpython-311.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/categories.cpython-312.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/categories.cpython-313.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/extractor.cpython-311.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/extractor.cpython-312.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/extractor.cpython-313.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/requester.cpython-311.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/requester.cpython-312.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/requester.cpython-313.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-311.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-312.pyc create mode 100644 Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-313.pyc create mode 100644 Parsing ZARAHOME/src/categories-old1.xlsx create mode 100644 Parsing ZARAHOME/src/categories.py create mode 100644 Parsing ZARAHOME/src/categories.xlsx create mode 100644 Parsing ZARAHOME/src/extractor copy 2.py create mode 100644 Parsing ZARAHOME/src/extractor copy 3.py create mode 100644 Parsing ZARAHOME/src/extractor copy 4 -delthesame1.py create mode 100644 Parsing ZARAHOME/src/extractor copy.py create mode 100644 Parsing ZARAHOME/src/extractor автономный для сбора категорий copy.py create mode 100644 Parsing ZARAHOME/src/extractor автономный для сбора категорий.py create mode 100644 Parsing ZARAHOME/src/extractor автономный для списка товаров.py create mode 100644 Parsing ZARAHOME/src/extractor вывод всего содержимого json в файлах.py create mode 100644 Parsing ZARAHOME/src/extractor.py create mode 100644 Parsing ZARAHOME/src/links.xlsx create mode 100644 Parsing ZARAHOME/src/main.py create mode 100644 Parsing ZARAHOME/src/parse_settings.json create mode 100644 Parsing ZARAHOME/src/records_folder.zip create mode 100644 Parsing ZARAHOME/src/records_folder/Allfile-old.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/Allfile-output.json create mode 100644 Parsing ZARAHOME/src/records_folder/AllfileFORjson1.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/at-home-with-vincent-van-duysen-n5361.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-bed-linen-n3948.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-blankets-n4264.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-clothing-footwear-all-n4823.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-n1153?celement=1020585785.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-new-in-n4215.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/baby-soft-toys-n3949.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-accessories-n2470.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-basic-towels-n1817.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-baskets-laundry-n3891.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-bathmats-n1052.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-bathrobes-n1053.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-bestsellers-n4187.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-bins-n3827.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-boxes-n3886.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-dispensers-soap-dishes-n5077?celement=1020463438.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-doorknobs-n4615.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-mirrors-n2468.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-self-care-n1418.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-shower-curtains-n1414.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-toiletry-wash-bags-n4748.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-toothbrush-tumblers-n3883.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-towels-n1051.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bathroom-trays-n3885.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/beachwear-n2487.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/beachwear-n2487?celement=1020662514.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-bedding-n945.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-bedding-n945?celement=1020583753.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-bedspreads-n951.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-bedspreads-n951?celement=1020319878.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-bestsellers-n4182.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-cushion-inserts-n958.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-cushions-n964.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-cushions-n964?celement=1020319562.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-cover-cotton-n5107-json.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-cover-cotton-n5107.json create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-cover-cotton-n5107.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-cover-cotton-n5107with_dub.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-cover-sateen-n5065.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-covers-n946.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvet-covers-n946?celement=1020319529.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-duvets-n956.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-fillings-all-n1384.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-fitted-sheets-n948.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-fitted-sheets-n948?celement=1020319530.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-flat-sheets-n947.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-flat-sheets-n947?celement=1020319532.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-headboards-n960.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-jewellery-boxes-n971.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-linen-duvet-covers-n5108.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-pillowcases-n949.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-pillowcases-n949?celement=1020319531.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-pillows-n957.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-protectors-n953.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-throws-blankets-n963.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/bedroom-throws-blankets-n963?celement=1020319561.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/candle-holders-n1003.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/careers-n5110.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/cleaning-products-n1835.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/clothing-baby-size-n3905.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/collagerie-collection-n5017.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/collagerie-editorial-n5018.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/contact-shopping-online.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/culinary-stories-n5364?celement=1020694130.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/daily-living-cleaning-n2485?celement=1020480055.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/decorative-candles-n1002.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/desks-n5104.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-accessories-all-n4138.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-accessories-cake-dish-n4864.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-accessories-n1041?celement=1020319647.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-basket-bread-n4225.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-bestsellers-n4186.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-bowls-n1810.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-coasters-n1044.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cruets-shakers-n1412.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cruets-shakers-n1412?celement=1020695630.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-dessert-n3918.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-fork-n3916.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-knife-n3917.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-see-all-n4649.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-see-all-n4649?celement=1020319646.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-serving-n1816.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-cutlery-spoon-n3915.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-dessert-plates-n2475.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-dinner-plates-n2473.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-glassware-all-n4136.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-glassware-n1027?celement=1020319645.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-jugs-n1031.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-mugs-cups-n1811.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-napkin-rings-n1043.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-napkins-n1037.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-other-accessories-n1048.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-placemats-n1038.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-serving-dishes-salad-bowls-n1025.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-sets-cutlery-n1815.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-table-linen-n1034.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-table-linen-n1034?celement=1020319663.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-table-runners-n1039.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-tablecloths-n1036.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-tables-n4743.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-tableware-complete-n2472.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-tableware-complete-n2472?celement=1020319643.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-trays-n1040.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-trays-n1040?celement=1020695633.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-tumblers-n1029.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dining-wine-glasses-n1030.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dinner-deep-soup-plate-n2474.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/door-knobs-handles-n1005.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/doormats-n4979.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/dressing-room-n2463.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-bathroom-n1416.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-bedroom-n2496.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-dining-n2498.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-homewear-n3937.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-kids-n2499.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/edited-living-n2497.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/editorials-all-n4316.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/egg-cups-n5036.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-bathroom-slippers-n5287.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-clogs-n5282.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-house-slippers-n5284.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-n1392.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-n1392?celement=1020319599.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-man-sandals-n5283.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-ballerinas-n5280.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-bathroom-slippers-n5286.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-house-slippers-n5281.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-n4150.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-n4150?celement=1020319596.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-n4150?celement=1020319600.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/footwear-woman-sandals-n5279.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-car-air-freshener-n1067.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-creams-n1063.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-essences-n4980.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-home-spray-n1061.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-home-spray-n1061?celement=1020319784.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-n1057?celement=1020319800.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-reed-diffusers-n1059.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-reed-diffusers-n1059?celement=1020319782.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-scented-candles-n1060.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-scented-candles-n1060?celement=1020319781.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-soap-n1420.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-soaps-creams-n5045.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-soaps-creams-n5045?celement=1020464942.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/fragrances-wardrobe-air-freshener-n1065.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-armchairs-n4106.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-bedside-tables-n4110.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-benches-n4891.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-bestsellers-n5190.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-cabinets-n4899.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-chairs-n4105.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-couches-armchairs-n4113.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-n4104.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-n4104?celement=1020628420.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-outdoor-n4250.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-pouffes-n4843.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-shelvings-n4898.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-sides-table-n4895.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-stools-n4892.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/furniture-storage-n4111.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/gift-card-activate.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/gift-card-balance.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/gift-ideas-special-occasion-baby-n4355.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/guest-orders.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-accessories-decorative-n1009.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-accessories-decorative-n1009?celement=1020660052.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-baskets-n997.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-baskets-n997?celement=1020319732.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-bestsellers-n4184.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-books-n3960.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-books-n3960?celement=1020637429.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-magazines-n3961.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-magazines-n3961?celement=1020637430.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-n3796.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-books-n3796?celement=1020637431.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-curtains-blinds-n996.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-cushions-couch-living-room-n994.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-cushions-couch-living-room-n994?celement=1020319721.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-fillings-n2493.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-mirrors-living-room-n993.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-photo-frames-n1000.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-rugs-living-room-n992.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-rugs-living-room-n992?celement=1020319722.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-throws-living-room-couch-n995.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/home-decor-throws-living-room-couch-n995?celement=1020319720.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/homewear-bestsellers-n4183.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/hooks-n4857.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/ice-cream-recipes-n5363?celement=1020703134.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/join-life-n3760.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bathroom-n1138.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bathroom-n1138?celement=1020319857.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bed-linen-n1097.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bed-linen-n1097?celement=1020319856.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bedroom-lamps-n1117.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bedspreads-n2500.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-bestsellers-n4189.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-blankets-n1115.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-books-stationery-n1436.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-books-stationery-n1436?celement=1020455465.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-clothing-footwear-all-n1439.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-clothing-kids-size-n3906.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-curtains-n1118.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-cushions-throw-pillows-n1116.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-decoration-n1123.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-decoration-n1123?celement=1020319870.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-door-knobs-n1820.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-duvet-covers-n1098.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-fitted-sheets-n1100.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-flat-sheets-n1099.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-footwear-n1156.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-fragrances-n1440?celement=1020447606.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-furniture-n1122.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-furniture-n1122?celement=1020576160.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-hangers-n1131.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-mealtime-n1132.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-mealtime-n1132?celement=1020319858.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-new-in-n1095.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-peanuts-n5223.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-pillowcases-n1101.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-plushies-soft-toys-n1128.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-rugs-n1124.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-storage-n3831.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-stroll-n1438.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-toy-story-n5366.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-toys-n1822.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kids-toys-n1822?celement=1020319859.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-accessories-n1407.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-appliances-n1016.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-bins-n2464.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-chopping-boards-n3939.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-coffee-n1019.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-cookware-n1014.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-ice-cream-cups-n5351.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-ice-cream-n5360.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-storage-n3835.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-storage-n3835?celement=1020319619.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-textiles-n1406.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/kitchen-utensils-n3870.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/laundry-care-n1399.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/laundry-care-n1399?celement=1020286015.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lifestyle-n1802.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lifestyle-n1802?celement=1020319841.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-ceiling-lamps-n4884.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-cordless-n5192.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-floor-n4882.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-n4847.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-n4847?celement=1020319968.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-table-n4881.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/lighting-lamps-wall-lights-n5339.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-footwear-bags-n1395.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-footwear-bags-n1395?celement=1020319603.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-footwear-hangers-n1398.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-man-n1389.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-man-n1389?celement=1020319606.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-woman-gowns-n1493.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-woman-n1388.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-woman-n1388?celement=1020319607.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-woman-nightdresses-n1492.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/loungewear-woman-pyjamas-n1494.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/new-in-collection-n942.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/newsletter.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/outdoor-n2462.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/personalisation-baby-n4252.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/pets-collection-n1561.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/picnic-collection-n1812.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/promo-homewear-beach-n4485?celement=1020473529.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/promo-kids-homewear-n4680.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-18-n4014?celement=1020694129.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-26-n4022?celement=1020694133.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-46-n4042?celement=1020694128.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-47-n4043?celement=1020694132.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-48-n4044?celement=1020694131.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-49-n4045?celement=1020694127.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-93-n4089?celement=1020703138.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-94-n4257?celement=1020703137.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/recipe-98-n4261?celement=1020703139.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/rugs-faux-fur-n5030.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/rugs-jute-n4978.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/rugs-vintage-n4975.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/rugs-wool-n5034.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/shop-guide.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/silk-n4924.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/space-camp-n5357.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/special-prices-n1170.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/sports-n4936.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/store-locator.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/summer-recipes-n5338?celement=1020703133.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/tiles-todobarro-n5342.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vases-decorative-n1010.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/virtual-card.html.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-2-object-n3880.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-2-textile-n3881.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-about-n3878.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-campaign-01-n3876.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-campaign-02-n3877.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-campaign-04-n5350.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-campaign03-n4989.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-furniture-n3879.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/vvd-furniture-n3879?celement=1020452439.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/withdrawn-from-sale-n5187.xlsx create mode 100644 Parsing ZARAHOME/src/records_folder/zarahomeplus-collection-all-n4214.xlsx create mode 100644 Parsing ZARAHOME/src/request_settings.json create mode 100644 Parsing ZARAHOME/src/requester.py create mode 100644 Parsing ZARAHOME/src/result.xlsx create mode 100644 Parsing ZARAHOME/src/state_dump_1748005445.json create mode 100644 Parsing ZARAHOME/src/xlsx_recorder.py create mode 100644 Parsing ZARAHOME/src/~$categories.xlsx diff --git a/.gitignore b/.gitignore index 5c9228a..53353ef 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,4 @@ Temporary Items .apdisk __pycache__/* -records_folder/** +records_folder/* diff --git a/Parsing ZARAHOME/add_depend_stock.py b/Parsing ZARAHOME/add_depend_stock.py new file mode 100644 index 0000000..2b57554 --- /dev/null +++ b/Parsing ZARAHOME/add_depend_stock.py @@ -0,0 +1,36 @@ +import pandas as pd + +def add_depend_stock_column(file_path: str, output_path: str): + # Загружаем Excel-файл + df = pd.read_excel(file_path) + + # Проверка наличия нужных колонок + required_columns = ['Артикул', 'PartNumber', 'Наличие на сайте'] + for col in required_columns: + if col not in df.columns: + raise ValueError(f"Колонка '{col}' не найдена в файле.") + + # Создаем словарь для быстрого поиска по (Артикул, последние 11 символов PartNumber) + lookup = { + (row['Артикул'], str(row['PartNumber'])[-11:]): row['Наличие на сайте'] + for _, row in df.iterrows() + } + + # Функция поиска соответствия + def get_depend_stock(row): + part = str(row['PartNumber'])[-11:] + key = (row['Артикул'], part) + return lookup.get(key, 'Нет данных') + + # Добавляем колонку + df['DependStock'] = df.apply(get_depend_stock, axis=1) + + # Сохраняем в новый файл + df.to_excel(output_path, index=False) + print(f"Готово! Результат сохранён в: {output_path}") + +# Пример использования +if __name__ == "__main__": + input_file = "/Users/valis/Yandex.Disk.localized/Python3/Parsing ZARAHOME/src_2024-09-05/records_folder/lighting-ceiling-lamps-n4884.xlsx" # <-- ваш входной файл + output_file = "/Users/valis/Yandex.Disk.localized/Python3/Parsing ZARAHOME/src_2024-09-05/records_folder/result_with_depend_stock.xlsx" # <-- имя выходного файла + add_depend_stock_column(input_file, output_file) diff --git a/Parsing ZARAHOME/src/__pycache__/categories.cpython-311.pyc b/Parsing ZARAHOME/src/__pycache__/categories.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31abcd2d114251f4770e5ca421d31645a523ed80 GIT binary patch literal 763 zcmZWn&1(}u6o0cHO>8&al$xMuKqP_Yl0y+&iV;6@P{Ce`2q79a*&$z>Oqkg=Y1u#y z9)k4HL!llNJSplwlSsg2PXY1ZEs%@!cP_vL6IoD4S%icySyElj%G{UVKvpr814ydB#g!!TLKZR1e2dUpfsh(c z1dIY}8g{uj<@6Voqs-^zD~AiPc>^=EMSf}~`owp>&3Bih4mePqwF(_nf{x@MQ@TF8 z4jFhA@5qi^opW{+M=_!1$28(dAC>vxe;h|yu7uz;;Yj?M^8SflG;CZVw1QcxZLzk8 z9wt>P2&v%mR*a%uIl`WLWLSrohs`E#m`T+Owzwcd6z__Vhm|q5z10PqhblD48JG~~ zmaxkQkN0vf7^WGvGthU3`fm4$8@_g~cb|?nHoMP8q39VqeLV(Q zP5975Zg}H7&{N&D@LA?$M8S+HU0wlaw9WNcW~7vCZ@TLMLQlU zWM#q+Cj2TdqE{Sq2Yd34Zf#>0w%fR6WMwb5%c$UVcvGAhTEp1!;^8z8nIy(0P)^G{ zmy1{03yKNV*eH`~n|jN@om|nRjhtmy7`BHEZKLbd?A9%9LnqX1Rp(2EXN9$=PabNN zRLV>FrRBx^y~X@(EnJjqcfIK-_~l9F&S`q(RK43@8z!#| z)FZY3=zM0j|M)zSI;8L3`~gwU?4x0FW)MA!?#shV$;0CN)uEF5p`^bl=@0n3a$^)_ zMWZ+sxlc=acr9@3(m%YHiVu z)onFIK_DszGC$+5TphwDAOBxAMRX!Hw0s#2tOq7kl^`El4;kP|CaOuI?JSgT19-A2 zS0iCffIP)iYVf!RVDl$dt^t@*bt=e))>MM2S*Y9rn1(E`T!5UszN6KFjIFdcN=rJ)4`sdQ(3IXDG{`=DM1izVccc$up2`TiSZ6p zydx`wy*5mW2{m{thZ=7z&&K`yszcj(*KhFHF1C%0LAT|5ca05;P{(U#-xjOI(u>M7 zgOWylsjzf!vG8cIuxx~b@|^)oHgUHehKSB*in;V9S3~%v&mF%yxpn_E^Wao}I4q4) z*N^lAefa!*W_DOUPo($hhj)8ul$tq;9z^%l(R6Bm_2bG&OaIU^-?Ypp{9Rl46NTj5 zMI5yBiE?$!`@*`Q!RLH*27PzJ8H@TfFFweGyvZ70fTVaWNpi(vPu~0Xwu_&VE8G=d Wf{NsYj1W45`7^jVj%X-7x$zIhIHJb@ literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/extractor.cpython-311.pyc b/Parsing ZARAHOME/src/__pycache__/extractor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5793247666f564c08d1b79d92fcb7f54e6812b0d GIT binary patch literal 35355 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 literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/extractor.cpython-312.pyc b/Parsing ZARAHOME/src/__pycache__/extractor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5300edc0944843b339c1f9b6d7a0b87cff7d37f GIT binary patch literal 17443 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 literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/extractor.cpython-313.pyc b/Parsing ZARAHOME/src/__pycache__/extractor.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1984458a515c47b8e65e90da0ba38cecaea29828 GIT binary patch literal 11515 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 M$A}8{-(XPx1A-Z}umAu6 literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/requester.cpython-311.pyc b/Parsing ZARAHOME/src/__pycache__/requester.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86ab771ef5537d4e075906080ca92fb1ffd1f89c GIT binary patch literal 3078 zcmb6bOKcm*b#}SSpGlDlMTv@Ja}~)oX;Z6@Wm~Z82(m3(Xkx>tBorak5^L^AqD1a8 zvnxm@sMZG`bZ`qcNZ_<~QJ&ls_CY9eXn`E!AO|0p#vX_b1Oy0t$c=$=FmmdfU6L}L zq(En8-^_b&-kX^>@4cOW1cQDA<#+R+t^CJ}&^Hum6|OlrNW~w1 zw%|&;?6E7)75Fq?aHrii&gDG?Z`#Ws7F|O!e;3K_M=U~*;d4sbCwuOqv|sivprr3x zN=z~qmscejdS1(8Tuic-YZdDjS5!3}s2=H-R+RL$Y*UBbwKN_K0(u`|lxAdniVAY{Y|Xt85!rL+g7NB5?sWRu30^u1ZP^wzXT>4on6I>Ui#B@wUo=} zrLi;OxR7`^r)+Lt5M~vbs5x1f7AM5<3&M3(SA}arVk(&wW{br<{tdqMPEH>?bNZZk z`mB(6XMXYeyD1@`+rYv#oZV29!sRuh7Vy}_FEF&l;9wOf+f(4d+)Z-@2wM8ClXLjT%=F zewev@ewm(4TV9az>UC9FzM^g^)Z?^ejbt;E;*>agua(nZbB<@_F#M5j@`DQEaH%XZ9tHo>O%go-ku4 zjcBUDyJG$ZY6CY)i470(1@8qw$*~jFKbS|)?Q*8~&3ZgxB+r}i3ltlykBl1P6?0^c zVnbgCVhw}_HrR%Xjrn)Edx2f32e21pxvtGETAYrz^=#W|fKGQy-Rd9!mbs7gwp)VB zqV+cR2u6?F7=v^kWSRx$wH>o_-WBv)YlripGKAoU?bhU|?rX`>pa9vnCK$V0yeI4< z(D}HncZXL7b$ZRs@_$LDhLKLaqgh4}iSM}eNDGH>a+Tc=kj#~t2k38H=NTCE9t78p z`}gj9t4_bgY@uz}duWR(^XqoPq?%;DdBWpmNHxu|4`v)`t&?RL2+}fN4YVk)_KyI0 z+$K14JND>#b+w=0?W?n7Z*w28vJ!pmZiB7GUO(@>ubRn((BzY33AGe?13)SCYbT2c zbA+hmyijrpqr$h(DF02$KYB}&1%kDrs%SVRXu70tYC=|(u`v3!koyokDA`4*|JgBX z@kCNqu@kz~4-S_i)D+;$ch^_;5E#FkTZ>xiQ>Lv`9~S{w~-JMfbp(nFmx}X6`e!HwnsIGoRIhdkwtolh zdxN{O*(KDxLlAO?cWA%6x1yVUr)u3Pvpdy5QQxQyc4r%$C)i()^nbkc!AxalKmJzr z^d9$V;B)!Qyb)ih#TU%@LS?=({~|tIy}Z}+>EP%3mt`ZqSc@;3@x{vg%a{9+!3JW3 z{fA&b95s5+eZm8Pwm0nbweYkVo;JeM^>D1>b?Qqf4IYGP??vI585*u?&qF7T(8+q_ zSoIgrBMBpts1FQ3ylC_!oc8s=@ZT@~_2OS<9?lp&C!O|!F1fh3W}f{O^w6GZPG1Wz znc*cPyi|`2n2{5ooPHh=jfhz9>95Sa2y|CQ%r{Qe0x2_)GVE3lMRs+q4{Z5lW;Vq> zP5CcH`KM>2m%{uPVIIaez}u+P**6Or9uhF`7@bD2JiP15=L_)KS4e0f1=K$Pk*9Pn7A=$P;EXMaV(9ZxzCsmh)uU)8n((H8b1VCrr z)Z1ALvI5f?T{0`Xo^YMH?F`!K$fr8paKpMBjI(drb zFb1j}*ZhrAwDq&su&(EnRZXNZWHF?~Z|W+yMt=%|6F7c&pk?fEA!HKBWAJGo0Dz$J1^>8e^p4iLM6*lWbNzeO@LjF>uA089 z4aD$oJsa5%ML&{1p8E6phwHV_kQo|kxPWdm55aeI?)MZN(tc`0J^p{r(&$5>Iymcd zJ@s+3LC@1L1Mo)j2pIwfp(li&Wv+njWJQyP{d&@fou%yDgbs9Q>~5$jLz0@A7{Xie+<5(wC@iY OHyM@z1O6D;+x{;+EW)t> literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/requester.cpython-312.pyc b/Parsing ZARAHOME/src/__pycache__/requester.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c63f366d51ca7953ba0bd9182fdec85746ce85b GIT binary patch literal 2699 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 literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-311.pyc b/Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9398767ee5170853829f69118cd7e01f783f9b2 GIT binary patch literal 1494 zcma)6-D@0G6hC)9b|-N*o7RmV?XIR(v18H=6m21x_>hA7Uf>pHY&2`k&``;#0 z=IN}A;vu+T69%@zbf)YRTV?7#*c#I?MlLo!b?ZK7E{}_KCvd;;`8I7kT)3>Bxsg6~ z99TA-{eW-?0l}$Hfz}aJi^0IiCNC->TjAH(Q?X zFi{h{PH$A-t=_n{<8WuyZ@QM$)wVpbMN`)vDRGjGn8M%IHUU=|!cK*OT z)Au0T4jp~Cw**zCWYctozms_O=^ z%Kc3t&t)LNbSYI7(I{3B_Tcoz%iqr4pFJ>6O6B`^4n}%8D7_||bTxs4 zg%fk)H?#b!S$??GHLpbGl`!GQ#`rgduL=)K(W_J8OLNFSuck9%*O-rt`7mQXj-eJU z!bfnnba{PbQIy7`ls0{K4=bawN$HpO951zSnIgZ8@CziLCk1hNxf00ZLfk^w8~l2T zrr+wpFpL@c2R(QeQlHY@qGiN}j}2&VZ+U5B^1i6b|Dh+(D^`4wJh3!`*JT>As3fa% z77XW=iY`};YDB&mM@!T3-D@0G6hC)9b|-N+YwV`9G0|8nGA7vx)hdc<8?3Z1O-hRtN8~b@d)sU>yR+Uq zNwZ-KeaJ%uLBv7|;!7VSk{ACEU$&&7<&r*GD87~MgAn@Ab7yvwBI1EP_k7)R&pE$2 z`)9G(4@fV5o95Fdz+YPFk<}GC=TO)L28={dBR(NoHX@^D`ex1YtyDK7yO#5F1Pr(U z%vuL#ZyQ+#Ki|x``Mbz*O*lUA}vkQ>v4nyx|Y!675WX4L#B#ZK+kU|OY-Qt z(C|pz&DhxfH{Ms03+b%{QB`_h2X)3*E9a|nsS?E@+SWMpE;o~fxc;GcIS{g1zcJ>| zT$#Bzcj-${ijba~I`z@y)TfhEr@hrkuF~vDE-HAZ+IBKJnJlT8B0kN(-$&S)=CF3WQGzt zMCe(kOhX~{aMqz?SoSBK0mnX@ z1?ret*HKQ4<7_lnqioFiSXT5u!r_)EBbMo=WNF{lxpmd)Q~S>6S!HL$yJ*w9ERP|> Z_6d0mqfg<)V<`WVd!3wp4#?7*F9Do_8@~Vm literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-313.pyc b/Parsing ZARAHOME/src/__pycache__/xlsx_recorder.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..370a23bb5f5479d6c14e653c31bfdc2daca4252d GIT binary patch literal 1342 zcmaJ>UvC>l5TE<&OKQi2I#p^CWU3;1q;aAagQ#dr1V~k)I+agWMPq4oIbWP3&YhXP zqzMnGPbfSgL?ikE5DG7dkK!n8Q?1e`kWk+W2Jy=5ot;z_Vx*hhnc11yncvR!a=Bq3 z`r+Zvt*aWquTmJ0-rw{-q|Gik;3x|)ub@(rdv!sb*HD|+QBP!T!I(GEEWtRO14l1{ zV^q{M0%lsKop~k&TM^dn2-lXQXw6oI5%6Y!BI7RejvKF%)mUF6jh8y6ydMR6=Skj$ z2B6{qs*Zx1V>)UPK2uP4v?8G4=xDYKJ0q-`??u@3@mYqPyg>*V(4db>h2EFMc40}O zC7~s$O~_FyeeGbq(6=-T0827LLjUJcg8#DCp?#dC1-4ohBbeNjvz4e#_qC~?6dPp@ zG>M5^dSGBzh0gu<3Z5bxmvxm&qUK#`)VYtmvFWx0-uToFoBr0v0bgs}+KyMF@N(mp zi#!Nhr8{%Axf_c&KWT9E*rnM^?@Z6WKRsJ%Y_<6oOEdXc?raN-u^D8Lm*s)V zlDTJy-Gkrqh5NU=lhX%d<-`2UetzaCJ9_`EZt?AdSEn9kFCI;v@4i_%n0$9fe`FPV zRRnZ_);~5dR;vYHwccc#-P65Kok za0*I5vE+MriRw_36}?0w^xo?VarLr(5{W?5szRCh!YIp@*#^q%3)A)DVAH3y)A7S5 zVdQT5m?e{KVosj0Jif_7cik7mvAf*%S<{VOVcqQygBX%KzUuq2&@j5oWoJqW;YgAp z1xMtM(MT0}GV&_1dvJ96wePO%SWgNQ-!FcX)g1g8~d#Y zw^@f?lHZgw#*%vIg$y&c9yK?pC?>LueZJwgWu+wL8CwaE$L%2W!-z4I*To59VvI2! zyK&$#H;yq_-iUq9*iVpTPHIMpO2Q;)Tz2y-_)FD|_x>KSjO*z^d8TSx!iuQzo$al5 z3P>j6W%)}vnI@q|JejC8to)grq!QK#X$9Bt0vY7=^KoL&HAPXL!sPF8?kN=hF<()x K{|Uqr&wl|#cO-QH literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/categories-old1.xlsx b/Parsing ZARAHOME/src/categories-old1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8550a3839d27c0663eb288ba3b0b3abead699ec5 GIT binary patch literal 14178 zcmeHuWmFwY)9%LI-6etG?(S~E1Hs)PxJw8mXz&2RgS!));KAK3NN{((d+(g{o%7~B z_s9Kr*E-)`YtQslS3O-_T{Yd)Q==je1&s}W1;7IU01ANdVVb2r1OV_68UVloz(eYa zJJ`FJ*}E91dpepq>oIxQ*^*~NL(*gdAc6e<`}-GLpd@}ksgng=@=E4je1lPLu}TD< z^B|}flkTNZdskdfk%?})mDN-FhdXq!EF5d@O3aZ(Z?=;m%PM=jx}f(xO{&P@fqm^7 z`b6B!-M#x%ZFmH+Z**QAWnvSFuo4&;M4G1pJ~`EQs&YuIiOQ7_TH@de1+1sd_iAFS z^n67w(kbBWTj*F-(p<*i`Cd4IzCMOEX>CR8t$()8C<`4<>Ai^Srk|@qp{+)1torrM zZIXPeGfe~gl%WaaGE2zE7SyHT71*X$Zc;@K!m7fs^CF#|k2dseKCgYe+GwJ}&sA<4 zxo|8E74 z_ue1f)O~w+lDOl~_6Q3AJUu}HRQ@9@Yc*J&odbPM0T^{iz_2uUV`l5j%mh0AZ#e#o zWAJZXFNsxD?qop@Ig+^#?Yo*<`iL$j?=C9SM4|2%AiIcG8=3Q*XsPW5F}gb8TPSJ& z7Qg%N3rhl#yL}XwKR8OlF|qld)w!33B;7i>!qHK`NtALbS?j`Zo4S~~OqQ1Oq;YGB zrYmkJ$dd10c_uY+B2kGx!lXrrfR#%ef-9IDsMDkPYT5X@3}Q-5?VvQIqMkc*H*O@= zem{DK1xpmQ``14iPSc%2OmbI z&wZ+t9GKT^BhtN8nHT;#H5?}cX`Wr&2%W`!$NfR!WChE>8S1}-B*dvrP!S4f65v#Z z20VG#GP^sxu`zaVumR0mUo@8N7r3xn$tv8@J($%dGZ-o4)`YVlVy7J^OqUefWojfP zFa=}7(r{X|4RV;PdM#HhL#s9?FIYSZ4dW=$Zcg}r`h@a%*A~j{#mII`rjd_3f9&2> z*l5BJC1q!d%#vL%dF^Hm33k(Y6| zbp=CkNkK@~YvbD3h^-<+1uZH!k{4Y#o1F8MU8mT{mDUzP%Xq$j-=uFdQ#s=79Qg(Q0<@8~TKY4dCi?^_1XXv31MAs=7S zk7R5)1{bu>4*;$TB(;tkU zzl<~%B*=}Imci)JZ(lcFyKQ|DqDierRV7z+&hay46JfVgrDU!n*j6(qB*~CUX&V_` zXl1~Y+6eHKEHR}&#hMGZ7Pj!9;HjiUXWxlJq-*-~!pjJa z#>u<>x9(aNY}D>#oqbeeH1PX|_k6Y%c>FN< z+t4>351&ooEVX=m@57Va9f*m@MC zrMxtI<%3_QyT>@<8bdxpHSBlDxjq0%)-9d@hV&FxivTdOa%-X{E*A6_q{mPe_f$6=j5!x(%6*MJH2D4++68I~cE9r# zBDzLB?P+;tD2EWwqoH26D^AoOP*@io^aWv<&|X-!NBl4jLuW%!@WuzFq(Ra!SeW~} zd&LJxs431^Uxi}(7}BwMwytTY2tsr6C?(Fnj)!nq53{(kSv!xCd&a7S%{QOEiZ5KkW(0YXjhzu7$O@o%0>-u{Dd?{|BroAloA1pPJ%?>Na&D0~ ziHqe)i#P>+LR`p0`=rVIX=9x?vy+=Nj@Den?!MEuEu1n8oFAEQ^!HA!07v@2Z`SZ# z`ik;c0Dw3#1OOk%@yE^D+0x9+#hDp=Vg=o`KgY>C7Ti?qIgO{vnwR<%=; zT+p35T(=!WFS+iRr$#HiY&ycn#H39sfJct7@H->(7VuxBC$Q__Gjb7)wNjuQT~rq< zM>;+0wLVRd7-rXFwc^0u07MBe3HhfSMJzSIwoA*5mXSwZ*(nvSqtI;S<-tU<*H(sk z-q+gf>L8WuzK#E4MQowYn$<7Tcfg3OHWSoYy_N=f0QVlIUtrfg(sJoT-Zdjn_kNzu zi^T$5jNFgk$h>GiV2>C~&ueSSm3U_i;zwWN9${xRsiiFYCCDP!0~^SoOh!#9AMnpa zi$95R(R)(-WGcmID>>WFPWSNX%Z8t6uEp#UoY5RS(tz2Sk~+){5m`AxYaC10&oz## zXofA{jOO|7MHhWUlya^&Y2Q%z1p+ymf((mEQ5=kyt_?H8c}dpk0vRzAsj5`)Hgsc| zu@neCdu13vx*h)DKP~ZrLs*2`Rgl5fY34A;A~qPshSO*f4`4g&#!VzQ6HSjL2)mj1 ziLjCrh3+-(lI$==hQv^4ikc|(h@0TRLOZQ4I>fib9I?YOVD6N-93AIienk?Jja73x z?3p8l#N@U;-OMNOcHKik_O1Sp_vh!QCldqtXh;5cr$^jvzE2f` z&7O}l`34!${G#?1;TFlT(n`KvE`d+k^; z)_J#zM&nb-ZM~Y$gL3PG`0V_T9i1J&uxqz4>&xAlY{t5}r{Pi`->dq%)ke)m|5H1R z#9nT+PkOy%t1}KJc5^ikBuZB+hPZ(ZX=gjLbjM3)#3~E-i;KQji^CY*^J(nXx`Io* z@!Cz!bc`z~!?eNk2kx{r@9!Rnc}td-iboXg@3=FZ>nhybi+R}}TbFnxw3~9qBhHg^ zuMUQ9I_60d%$o>OfaU&<`7{IXI!V66pN=+eJ%@HNFM({5Vh4W~ zBJ27JpDA+o3;j~%a%w{MK0bwmAA!Sx{eX${sX+6dS4Q1x}`NzMjB-3t-_;=I2IVk z<>r5Y;cH^+u0btRmVP;i{F4$~2%;E$VKgclx2>1Kx03$^5~`A%ugaxcn(yBYePcIA z`7;Ug)t9ikTse&t<$4($JNX0U6*8)oqG`y#ibX^s;#~T~ct{ZVS1L z=w-R)os!FTNp&&}i76;}AL{ky^*O=BEg&%|(x!0EF~$qXsShGf(N@Xpw%cm#PP1se z=wq_OsMY}1yF%`bv(svd957j7}L<%XEM>7b5= z-)6VHanP{ldTq9P(Y`e^ab2-?bM)-%_x2{|3}6xExfX$k`xX{gv;2DvSp8^cE??Or zOyh*WNDHyzNjs}3hn(>0rpR94Md3OfOnqHaOsQNNUzu@5l*{G)xlNNWiPx)5!VD(i?ta_nZuf~sk-=pUmyOT~hy!Q>;2TB?s zMl)1lbuT{Ik?4r@a1yekrw8@>LJ^WdQa}JM zBJoPHHbmnG*B&%QmHbO^u_{VYgu7CytrB6IdK!U~3u38@PcnqMz}ct-04&1vP-muU z=hw_ayI}1h@I8>f9T#u`;DS(md6;tS|P1Qx}`Y$1WD!J#0isJRLdR2CtJXqvwf z46sOm14fnp271VahHf}xT{uqHhbHG!xk=7u0tC^#?_O#ldLl~hp$dj!}5gNFsM zk^vulY&Hj#4b8FI6&K~>`k}pdSm*)VPRuQ4AWFEz9JC|W6{S2E#9~*A3#Ot9Wj_c3 z(G(DKz~Ml?itXO^qF8L#W)aCnJS1$71#jeGcRZmlqJX@ zC40eOrp;(D(`F0;EN7x!~nEL6+^hoG<$*&0-xd8G|f=?HweY(g-p4cpSoR`6$S58JjNNa0^t ze=vhv{~t!LXpl1Jqys>Oe=!3ufwljysJ~PIYSaU2{=ZNq3o79`akF|T&q>2oOfbBn zL4=lG%1Q0uWfKf*2C>LLIIgsV3B!T<0twrKAORo;;XjKU{Q>zW2N>m-(63hh2KyJz z{})6WPTbs{>`Co-!f;iSm(~n&k&=a#|32bN6IN>msmShvN_!lB%%sUq>8p%j$chK1;gn<9G9DG*N$Hw|jE+Gl{wF{`mY%dB*?d zcxyyaNYL+U-GD43oh-vo@Ue4XVO_f8NT}KW>i%YDXLCJ2Ntx^syz2*k5Vwu%k6K_s zm+ zX%iT^8X8TzT*$0XUEA?mbO;@hUbOc^R$j^5NurUiWgzL&UNdG6Ei_f=$&vGWiKc?0U>JMgjC zcDj}eHL~^WhXzU`agobJ=y>01y(X7P$~4!);TP?xkmHDCyR*dYGVGU_Fl2piO+39i z#`+20mhron`ksWX)u2QZxwX1fHWMTEi}rMapb^v{6l#s(AnPS*U}ab0_KE!d{^)-yRf^zWR4B#_6&DGL1|AgZ7?>$>}OB8#&M*5FaH zTGuagVQtZu7y0L2ukYD(TF--~Zwj5ipaJPsW!ry$Q zYy5fPdEcYZnY-M*o+ROa+<-GD{`@QhIIbU1L2vrO8*na`W_D)G;3IhNZBVP<9yr!5 zc-zA8jofv{1C^0HqCdK}vm^r>B}XD87!f29o>xEkhKe(Oq2eBb?RsH#&*M{ljN=g_xY=vk3=hvXUb}xBfYw{^_cGDCz5wtfYs6cK^2WME53*u?a+OEAvm0Rc6Kp)5lz1CKi{dG zXL08E<68P-N2u>p>RdOE<1swj^(!>tv^0Yf3sh23f`J=FG!kf|2K||B+}Qa2y@_K~ zm?;N-X@{8j*9Ut!L9dgHp#UhR5}S)^(Kw1S&@G4FqkNjJQa-FDil!ds3HaK-WtXpCD+dOKJvOD2AZS_(9*!)&$ZN#e&G6>GA2H6Y=A9sWL2A>m4_7;f7(9;Pd;?Wy~uDC(1 z7f|#u@<5ATS8U*t)00IKV=pnXDPj`RHti?Ey@j3Puh7aC4}vhDd=5nQs@me!#@aM&LC@<>uUA;v3v*4TcPCYzDOhh20% z{w*{gt>em`s7Jys#NBS;-Fd(lm^>$sRi!p{`AO#c&eN3Ij`895BXw99323#!Z6Gesjrdne1A-#GO2F=GE>hr z#_aMY#Pnq*8ukOs5ZOg+Y){Id0;w8NMIZfgr}N=km;0K{!LO7>d8*H8cur!(C76)t zE)i}IDV>x03OR9M%vC=^lgLD-=P9>_+4vf6+{dCH0D=p!Tnb%lFPr(=o)gc!sG@{i zj#qUmF)F&$*P{&zpXYJfde_=^%##Os0dJG;j|$(rtD*Mw>juuWi!{L$T=+ZU^zw|O zcj_L!0oFu=PKPxeV(*lSdlXA9hJ`+F$xT;Hz6jXsulmCKRo;EGRNymN4B*B|Ms(w5 zjq#w=>-qSi+D2H)c@_s#?r3e?fYdhhP(T4f$8Ew#;rD~hLC9#u;|-5vU%w$U2%V1e zBq`8IAGjlYXIt@$cx9+`YnC5oY_7o7_BKZCeI2Wp`A@&6yBJPvn2qNifSRt)RpM=G z9&i<`3(Ml}(6xw%Szd4#CX1!Pgd8e8_Qv=rj)4@BS+g83Dc^ozk6=c{k-;3r6EtZ$ z#45f*Bnx6m;qh?mnX3H%a^@IFf$SkEjp759VL#=hV0$!2YHRg`)<|0E$(e`7)h($ zbyUG1DU2Jp4QHjmFqh_&li&AkeMe(Dg6&tKNpjY)Hs0!UpS{&wTc$q@5(FO)nDN=& z$hLHJdPyIpSMD@s?UG?Mkq%r&Xdup0BeWz8r;708p^yEi9{9CAZr*BLw;nzo zKJG4ed@$^Wc+wM3&if{#HxFf45{I#BclCICapABeyn6q08$S6HkKacqa;=(Px@w17 z-f+8zrBRrOp!f!(+aFtIK~d`tGNMGNRGcMVvgKdu&=L5e3_h8|ubo&Qc!K!T1K!) zXpPSQQCN5$lOy^3{D2iulfS67_Dwhva%ITeZ*>^YV}}W^x^F0(e35A@wVEcJdND_O znWz;H`T@nXPufP2*GN6$DZno~(~cAO(nS+vF^G$TX(Q3fL!R0M;^}a3N z$#=#2gDK5zJ9^aVPfRw+aRT9?4GM9-6U}xHy$f6cnE|LX%4_WQVmfR~qt;YP%n5AV z!=K-?*mUyJZROi=y0o#Sv~+O1DwxbNGR> zYrgrkm|y(FRF&VzH&`ciZkdp|fjh=+6Ezu!O4$O_3S%uX^S5d3rCcnBHMDPlDy2!Rf}{V86pfv$g@>I63nS)_$=zY= z#!fOpKG#G@)Prmq-2Q!k3|}}pD3(pS$~Z`dm17&yW5f8H^{Y&{IZi4~I6p`?^N)Mv z^Z}tmtn1{L!`cM1u>R3Axg#HFKAc@cGuEQ0qb$KC_yl*9PrrSF-<&bj?Ztdy?cdcQ z*RSkID)=Q+Id?9#HF^Yv$Ai^xqtLgHI6b7==Pjqa^_=0tzJOxO#-p{QTTMy0>7cW1 z;qY2)Ko9v?HFOTiSO73&Mdwo&z~vIE(gO(ZiksaWwwhtZlBAe z^f{OG4P&{%Pp@Sw@-Jf1JFuic^AhZ%Ttj2oJ`Z z)DJVZN(O9Mnac%U1g5`_e}e8V*GKRk`HVgX(0F-Y%t&mezQn8_%R!Z*kGEr_K1rYu zq9EVvQ!(PDbyT5_ANXjVReNv=P0s{JJtZi=u^}hIBf@AX(!zypKe*W=k`oXIJs>GT)fd2%W#a6Io+1Au}=z&7(K8 z5kEzwU#m`KoO`*2Ek8++82o@*GQ_601-<9~lcGP)+=(qf|CO*4H)>ZKq$nxFn92u_ zn6;!qqFIBqNC+&gl1iD;Ykx5vMdx!7_m}{f0p?@g4u%)(?+;&MY*q3<3toMIhGsi| zC5GsegF5pGR+Wd$0Uwa1wNI*`uK-nuWJ^z2O`!W&VKs%0l;}d6x=sj*USW)d;a4#_ zE6bJLMZi4g=s{phh3bwlp(e9m(@w~ypye@hJZi!ow2>{Hi9h;!1wm5T6e9;q!E-Jb z0g>{RqzVU10je1iwXoC$w$8x3w_9~dw90iBr$W=tgE!2|)VFiU+EZ*5VuJBY z!U|2!(!!t@8bP%J)3_1jaRu$`rF%pMxd#JE<}28|b=)Cr!y$SG`=e*?NErGn^{UWT zdbYU2;&J@?Q>J0pui7W=*21al5YyE0GELdJNp!EtkjZ|%#{NB}lR1C;C;|9_TMM{e zd-iLd0A8d&10JTdCQnq*#&1r zmo+BRKfF5k=H!~?3BU;HyFp~;D@NCoRD#eUz% z2#~@VeER^ai!WpQb&42yMPw6wLH!T`Td^nt4$sFrOtxg7@-zx(>dFgoHDWYk1(sk1 zPofygGi5o1U{jKz9BN2S*tSy6MnHf6J&r2?|Dqoi4_c3*QN6o{sJnuU%Qjex?E*!_ zHgZkvrAz1gNkPj~YySoSc3c#f!lACP;@<2+#|LMDM}~ab2Nl247-!(*R`Ydp0ShXR2j+!~!cN*i_RNK;d@RJ%#_&?c4e)jn=z?T0>cU(Eh)-dR zq4rybs-rd9LPQwThz8WazIYkb)`DBZ@`PIRJzdSQN%JvJZ_$@4N4L_s9Qi21RZrTr zEpqMb#kHH4(^NX)n>iOr2pmOWDpt4M;?K^8`Fr04o4Buj=r8rOG!6Btg*Y8Vv~thI%K;iQmL`=^V2v%_^0)zy#c~} z9MId4fc}X7caJl2bo^h31A5vYzt6ElN<^&KK!@`Ujk)T=(xJfijG(jZhLrdMeOaH* zPf#2sc-j(y>E^N^y(;N}d@AK(F7c^G&(+;ODoU74H_c(1$%Zu+r4@ZbmWl10I)1tw z(W(C4&xe}L_?W6;wGv(Txl@@iNueh)id3D#0dx|G#H&zCH4+2s~|^JCqB*8Am^>;+-=s$w(I!X5n7-)Hs-cg zQo|zRSa2Jb{1kD$v@;o{X`-F$R*U zt17FjZf9kdGqbvHkBziDwpJr7kT45cgs^z9WF!Qvw6>Usg$EE4ezSRiC;YNM78tZb z@{1)N_)bJ-#>uKY-5uF|jexyZ-5r&c87EG}i7!q>d~x#WTc3R8vwOwA-}=O_ef+yW zwzo$=KZT1g!tPg+AWXX#adI|^pV!(WgH!~o&8?B6-3i`wv0}X z+V7n_?u^>4H1ngGAI4E|)V>VT_G`zVdiC(#AoMdllrEO*w1r%v^r*eavh}@gH=Qnm zm7ng%>mb56^Eg@g89pYb-L*eG^G}1W+v^RxD1phNeO$@2_2%rToxC}7+O3nzH6&l3 zcRZgjr@_N`x>*HLRwF{`pDuzRL#BRm8e~UpsuFc6?W#Wx)lIuwUl{i;3zMOe0#gw6 zv8#SxSqASe%aCT5AzHMo4gLA5D(K&-cxsC$LFUi=%r~W2Sw?{ueu8n=WDw|ume^2G5?fag86Dyo0{snr^D%1wJ@|RJ&75OWe@E4VVwoX*T zA0OtKKMG+7QI^t$X_!2t&J$FgK-ci^&CVS9lU}9|!lZTXhp^pcG>b1zf)}vo&`&db zan$aqe`LYk@}V#jo@LKHR{!$n@&{&Tu9BIYPD-K9#x5)80TftnW~#~vcGfx zs5k82cPsa+oAmvIo%{Q*-+%C6Sh-)_r0*Z@-2eDsJnUERS2r!fWpuW4H#O+v$9eAM zE%P{hqxSX@ZXfmX+s$3DhSIu7#5|5N$<|i>^Ei2o8|X&D=%|$egy;SgR{X$UO_HTg z0{nY{&%V)@rs>WllGRG5$#MxbX@)^|Vro$r45ufF@M zzxv$||E12W^57eObjlz6)-p=f3N;V z^dNKN5B|Zo{^)nU^@DHzo&WmJzEN}g{luT}+fSCOAZ@)9T(sVeSI|vWOts{}B(Zzq zWZ^F>PxuSuU6b{rY*D%Kol8HgyYKa&T6ym$0FSyGKfifiDeJREvdNY;lHXdaDmOlf zyCqY=L#?Skk%wN@IdE&#{VGZ-PpDpSN`Rp>8 z^7|g88Cv=@2;cw>+&B$ruQI zvq@@-_4y#K*zdE;aP9{RWdP|Fq+Ttft6)1^0=Kn8Z=Ld6Q81{+XU_4rm^tkt6l9C-F>Q_ULjk-6*qBr8-q}+Cq>=8QfHucaUca-I@q< zs8BbS=BT16P^?HRRi-Ld^Kw*qsTwYpwF%Fr1%C*&JjBu#iH0-ghXEF`iaBu6EL5vS z`i`3@*IFyG@MnQ;qRM4fn~rL`!i0A8BlWb6*wtoPYpAsA3!%(Hwx1hTa*;t%v8s`_ zds7(kz7d^E7t7}x->Z>ZY=19ZW zwA6k2x*x6=evX#3I#cvGeY-N%vJC1ID;{*KExS_AUKQ%`cclt9&0^VIKjBDumjeD6By@62nQhNP^%gU`biuHJLg2(4(^q^Nf^5vErs{UF=D49)u@^fkVRJc54AsS7?&M zfVywn{;Hqz9yB>6ABFd~3X+vWr|tuP){cwr%us5}mmvEs>c1?as;#QyqMuif7h@z> zguXCdQoraGmBDX3&P6pW!c7KXHr8sy+R@k@6oo@8?rMySr9ZRAI#7##Vf^>}oKme7gY_MIL8aWS%BGUt zq`fUGyL6(e;wpXdE-O2);YwZWYhqQSWw*O1F3pR1h-w(M(Z%mL~^h2!rZ$iC0 zm9Ftg^@H`(L|NA)o?Yh2Fx3ODwmO=_(4ArQZZK~xXD^ERM_CiP3+Ww_!bMhh(_>_4 z<%3?`q@ns?em^~`N6YeI_xgv+CzNDBcKNVcP^-%T`(rt9)6@?4Ymn7iQ|BsbDvWMZ zWj82%eU;VDd~RB0dZKt`Lp7+f?8Vhpme&+2Z`bg!!kF(Gg8AW zo<2?Db^87ZHsw;-XS7*8US(-(8gC-xN)4zlwe%n2QVfRemS$o+h-X+1_}njT;_R<~ z@8iGq{lEQD_j@1zI{viuwZ%gJ{lP!{P$yO^{rCGHeO)KgRR8^>-~NsK8Pyx|VjLe* zr>K;ME*u}GALvf+sIAp$9L7mYwP8LYUXJ1AL$ zmZ1J%)q(J!ECBT)x^R4mQ3$Sn^cWv#aHBL;;ZZvRxkag<@4M!1j9Zrurj1Ij%D78U zK<*??W+2n>hR~Oe55r(iW(%)wL4UJ&jo*_v%idsknY zSMq)_XAO+;mnwnUnvy6`p49p250pR8P3L{K*Nex1^Jfr4#RAzT) za0Gv%85(V~xMtW6kBCp!N`g7IS)6JdV@WWtY*p0-M^JCH=1q1Ek;$r^;KcP+YV1J4pwhp^N)b+CtUFlq4 zRkU-yjEIfWIrpQ^Y;&0gQ70OBL+7x2PMril5LQYgCqzpG0qf=xC;sHJGYMuLED(|a zZ``lXzhCCxx6dD2+GjzQcA~yJ6!IUG`D3}uvi#F92FoBi?abpiy9oTGnLAMtI$3;)Mu$y}>nq10KQQknfIk}%Sa^uzRfl}WG>wyGkmil3Es#RB)A4HkZhz%{DNxB8;yqbP45~&K(dJltjU8`o>FC{vA^!%^MYg!dItwp zVCoOOz9#^aYw!ZeM&*dX9FO7&wb@V_KU{+rNH!6(S|&+MhT-;yk}d`)+-5)lX1*US zvGobBjattWP!@BZ0%d8}tigB!JD+!^egb@OVCsUA7<_P>;X}Frye6ILCdt6RM(shE z;260ECXj5RQx-47AOpT$V7IO_@lVMl4*HUE1~1%Zc#**iTTGG-gk_j$Y1}}U69CFJ zxPfFd1@p10HxPyo&maeqFG+@h4zC$>lw&URs6vJEVFbwX3{)U_Tiq<=8tm|zVFwn? zlz%vqoM+D<2a-0b1^#rQW&*$^X~6OfS|EAnxf_u1>_DPg_G*I+hweZ^3eO+~l2-c6 zlrM{UARVmgMB~0N-|!4LAbCp>Rm}z???CclJOdF(HWQn#c0xG`B>DyjB;1}czjAZH3tr!g2~R*;Z;J01wbNZ+6XlFdbt3~9}vZ{PvR z+sfE!uE9{MMgtsuOW@EQZMHcNvd%Qd!AAVX5-Tn3I6cAb#YvpPt3k4Xnp_;5s6eeG z^@c(p?;99F@^<2=_4>lN)i+pz;bX_Rb*mqKqC7)(L3LCw;J3I^|d8O-rU!h8bz zYz3OomYc;KDbV0`V?hQ-u)N+#5O%<39ktS~I-W4p3=EJUc_)H)Ekl}e;@Dc z79v%sfs|n*NYNT9c$DnlfXT2Cn5;o@1YJliRgI;2#?T-Mk`3yR7BVl=&ZOM%8V`k4 zkD+Y7Q*A~PxDM#6H~>it=h8atfdK_1U#1{~ z3kO!XFa_bopVIgquh(RDaYTd1{vrd}t9Bp%z~BOsHacyPvyb7AHn?azl*j`8Dk2QW zeVnPO7mSb$g(HKch2WVF{uB5E;47SVz{J)4i`Lx+Rq1^YUk8G9jtp2JX(K(DVm~ii zp2Ip7G-*r{e3_BK4J56^q-P3|dV*U$GFXA6P0mY&M|B(7fn zM5L3^AbC68FgEpT*3tWdi!m~2f~37@y}{g>5UCO>x~^pE z224g)V3OA<_IoSavBHFMWPk+82I|BY`ToBE7-It%NZJdS#s~?N`w)GhSB(uUAlX1h zvLW6Pjvkz8Nqt8^hOt2gB=1I275;|f!B7IKpfQ9c6KwV{>u7={E0QqXtVzts z5yco7!2(r-I*k1F891nj#-$bNi#BKw!|64F3@u65n&6^gJ;2l&()NZ9W(v9#cT34j z6dY~GVQ_)8y*TvUDMF2EBA~?ea&X?H1VE(i#bC@=D4TQ5QiSrFVHs3Aa6QQpbwCg` za+|xt=5G9spxwb) zT03;W7d6${1U$6xWJ3dt?s39~pTp^+cKlJUr&_Agf~0{3oKd4w6Z}v*K?bO85=Jos zDbAud=x9oY8YgjRV+~dvJX5#;!kofkY*I?wcWhgE3`p!~qr9;!^kV>G#~-~$-fmxz z+mu0z9li7p%fL{_j(A#>K{Men6bX}U2Sn4dd)SdqcSTfdSItYs9>b8vj(%E*Eg7J2 z!6c9Y(bOo{#7jY>;h>|OSaQlSK8V%GP{xjJ3Vp~Mp9R4h#O}>n`{k zYE-cDMQE!4G=cI&4sofaL52}Z9Xm#8Atfh4K$Wp5grR{Qu{0NwcO8-;d8VM0n(DHe zpyV>>oS`PjdSg#=w;7|e#VIgHvpqsCnF=Cr-N=Llow11105|NQ8biog@vH>$TowbtQhZ!|0-v zws2o6LgD<;+;QNJBtMCfMIAe~XhqN>-lRdNqM8KFj5_MraYri>Bb+uAm0~bpM-#od z2!;Z7)X-fKRi^-}BLlJ1GKQ#QM-i=vP1S2Vv}H*C2P26(b}Z3S)CC1ShvgGF2s@-& zp5z~ZAzI?99b0rqUVf;pVvf>~!MLM{_1LJVX*J8fCQ;2DMjxeglTNKg)$}%L6^hYD z9XsCWR;}Xr;XrCSkV4C*vm=Pw2w}4gJ0_@&5QZFfWY9VxH62?tLxv}IGp?wEv`yE;k!8fQ$60p-Yp8Djj;if@03SkJ9b+s~ z$BsrizoP=MiHaSWlobHSGdun=>C7>?SRl$_LNmUhmhztXopBpOj-Q zUZEwecY(laq*?9qG?K?o{T z`B$N7=#FII2ZhztnVt7iS~!Bs(>?@@&J}0(jLz!V@mY;->v)5}`^vb*?L@|EMOSOq zV-vhYmZTu4wg7jG*Xr02Ta7lD`-H^$(4AG@vR+b_}UNn~W(p*MrrS$FPRCT1a08i-mE@Qb;x}of?Zt;8^HtZT=O ztrt^Mky2|io~&!flfAuYLwR%UxU)=j8HaCzGn6V!f!LUgGwa#~SgpuYVU)1eLGzR1 z?4;(%jHL+7E+f%Wx>=veBREN-tBp=@?23)fK+7&BE31hzm9mC0N$;w;8K1>PF~ID{)9%m-Y?vZZvhrcLNXz?OQ_SjyP8 zu3fZNrk;&JM!j|IsJBf8nyn_+j(dBZz?wcHRdXebYg2crwwi4UVK&BHJC-i1i9E6e zH!lrda2AF6pbI)~*>CNrxi=MDQwvfT)LU37ur?C z(RpDz)8*k{?FhNcDUQg~+IlC!91bsLQ4s>RLfK>c7{o}ykzq7l*Df~f^B8A{LVb|) zKy-t7Bv?CguHqRo1}MT`2|6%Nu4~81t&y=~esa4pimq!%(baOX<)p(7VHgo-XN;)p z+7Wf@gw$v!xwwqI>)Hi_y{%vdF?NLBLa=fKLVu+W(&1!{WH-#)u_N^sg317-SmcyI ziqU#qyQs0blqxqwTDf4nUe}J-tHqSzjj(tofj)J7UwG4%XX{KU+Q&cbPK1%FZ zm&J#rw1xY0g{-Ri_XmT%6fx6fBbcE_h*~iSu_FX4 ziN&fU9dXBzQOWsW(PDAj!rB&ZDuqpt>?pvsx>Wlbrkx|{MJfm@WSmMnMzEG_PS)VS zs>El&WRyvG7M!BV^_adwefx*ey}K+ zA%z_QSW7N)Mfh>x5Lb8ypNlFcpv&1Yc9HR%^dXFb>2a8XcLtBSlwm zSx8t)+YZPf%pE}v&z2e30~DLvla5HajMGbLTS=?H$6EvO$~V$RYAHtBb?s=os=}%= zstrX@D}``(S>#tr+v*nOFBn5NmYhUJ&UNj`xk|H}NMMT}cC=h2VU2Kh8{)$Zuyi8W zGvnjp^>)_PR0;12WR=!i85P&HqvC2!LWBWawIkjtX==@i&_`NJ zU{qVzE~2Z-pS{IP1OY~@b?u0?xrhYuDAl|}tR&_o*s*Ap1iT(kMQg<52C*8Y!GKX` zT|4S*A%w7UB#r}&7VFy4VsDr~n>yIBV7KzGK`zNXV5C>qj`Uh!eladPlO01G zi?0}Eky%|ka_g30b$Ep6$0O0^nM+|uXx$QZL96`g8d;(zI!Y`St82$^4dV^gO4QzU zxwW9*|B1L2!hq~CS}Ub(4CP93JFPjC-W=gEHY=rXSp>6SkWAs!?-@3hQM4QbI&yJpY zd#%mlhi6Am-4#t9lM1M&CmfRJ0s>FDzE0`e)b#rDxxb>2ISx*z)-Qj0jFw7i3vv1K zEq|+wcm~#EkzFZmCniOxP8|Qg;uHxYd$C%x!jtm&8kSZBZ_;BCTPbZ(dWzB&M}Anm z{yaZ$gUvOmJs6bOaY@%IoG*LF5BA0cF9@>&R$W&69_!^aT23qP62jS7NgKu+_3U_~ zc*D~w#*3;-@*Z9Z4aaWxwKNCbKsp%Vu?Vh|wrMvdUM*pkWr+GiDXNFZsG^j%kfiB+ z9cKjXutZe_MtbFstQ|uNJ7#Du(;bpb*WH!r3A-g8BZX4hUeCUg*{_i)ZDx3k`$_2r zG7m`4{uWtMy-rCqT!trhB+$HW`>H+rHSHB)$ro*i+tkV)-{ebgE~r3nKg zje2&ZQMLaz_ct#(IP;3xr5F*{W1LY++t>`9H+YU!L+FJNKEiOssG*)6HB{+<6V4gl zKBq)TGgcPW)w3gkDiIerajdFH@^HZSEC>sp9ru&o`_?(#;Oy*Gt_Nd%dUmW&tP0~L zJpHk>%?jQEE4mdTq-(so0Ed`Y2>gPONn*EP-i95`vp7n;POu$8E+zs4NjAis4Lg2k zx{lR*>T$S8njACore{aqq>YE56UI{?iK`lz(KS6gx@Njrtq|Z$Lx^4`+70;Th=VPQ z;Og1YHub(n7SG~|pCmEafE1p_V{}bQTR_OUdZ}%}ImA2sXp>E{0>;?%>=>Kp%Ou<2 z)H)r>zp|ZJN4H~W-dFTPzgDH`qn33`Rrct?{9o{?`t1@a&M1* zK8=en!tN@_{27X}{{nB@eGR`_=U7ZZ)Dp;7h8+Yj$QeYf3OEu&|fH91?s z?ESKmp*rm#P2=^YYTh-y@$-Hdnh)>$A)>sf&+v0jkt10F2vON%gpAWhfmfsQf$GX1Fg$FS_r6|*R;ca%X8~tS*BvYO5Gzh~dunD@}Rr;1Dq7+t_<{JuI zN4HTmZ>hOmBa<^-HK-hz@Y`uteAE|On`C*^{^iMRG8s*0)6U#?f(~9Bfv9*mDcJF* z-rVa=@m`dv_cv7oP&L!P!xuCEUfw+Ssd=6zu(Kosf3r1zsGCh`H%HBc{yGg{Q9Z3x zoGfX^UL$tkWhty{x9=>u&ono^Hq#be1lV5{cx^ z8QJuq#$P?yf}DGMoCr*jkuzQI;;Ro^;FT{?ZRV``!QsM?ZfV zMpxEvu1s^wW4L(Z;kl}nw!YfBS2^B0he2FF=GSFfsQJDcUC{UM6V(^11%QL&XVizk z@a(Y5FCM;umxse6c}f9Oj}OnYd*_($#Yu~fOdhpi|A^5Q=mtLb5zacwkS*P&Kd5xL zPP62g;6%d+oWks$zNnJ?UY=g|k7>S_-9w^!BVE)5!57sco-A=vCjH|4sgHG*-4eqb zO^H<*ba{1gN=Vx&qS6||wzBV<_TDnF|MVNb@|iDV6rrEba1*0We!H<`y1qx57}2>O zH(lSvFe*S)_>#NOqit|LKZ`hry zWyW!n-#VM>FUz}Mr0`jCgTJ`A*uU^pG2qKN-7h_P`T-0bCeor3U!)jWu2a_BY*jPI zhYtfR!G~Gv5h1&tc+gvr?Bn@|m;(d51Oa-|B5HoU zgcZD{@Ml#v^(stO>#ZtUA~symrR()itWnx(W9TR7di@g!g<1OqU9W#4Sk*uAqC?-* zKXV~IL*LXt^L$;e%ky<0DWkrs)BlQRGNA%+T`HOSs!q%m&#Y(LwZ^*%eOq4(3H;ct z2I3FaSXqwGrn)yx;o7uYLTxxI#Za1wW$t z4`tLdS3VC>v)Ju?dY}I2><@otZ;yV+A2I*_2XaO}+eW;d!Fzx5$~V6J3Oq~ve9AnH z)cO-Aqio1Jye?T5El zSj@w({@bz$#d^#3!`q7m=HXxYca^1s?FY9feCEOb`R{k9f7?%Q`|{@LlmEb;E05v9&(lq>;{PwhDE`WSq)-1FFV6QC literal 0 HcmV?d00001 diff --git a/Parsing ZARAHOME/src/extractor copy 2.py b/Parsing ZARAHOME/src/extractor copy 2.py new file mode 100644 index 0000000..2d74bfd --- /dev/null +++ b/Parsing ZARAHOME/src/extractor copy 2.py @@ -0,0 +1,344 @@ +# extractor.py · обновлён 2025-07-23 +from json import load, loads +from os.path import abspath +from bs4 import BeautifulSoup +from lxml import etree +from re import split, search, sub +# ───────────────────────────────────────────────────────────────────────────── +def extract_components_zarahome(parts): + composition = [] + for part in parts: + if part.get("areas") and part.get("description"): + if len(parts) != 1: + composition.append(part["description"]) + for area in part["areas"]: + area_name = area["description"] + percentage_area = area["percentageArea"] + + composition.append(f"{area_name} ({percentage_area})") + for component in area["components"]: + material = component["material"] + percentage = component["percentage"] + + composition.append(f"{percentage} {material}") + elif part.get("components") and part.get("description"): + if len(parts) != 1: + composition.append(part["description"]) + for component in part["components"]: + material = component["material"] + percentage = component["percentage"] + + composition.append(f"{percentage} {material}") + + return composition +# ───────────────────────────────────────────────────────────────────────────── + + +class Extractor: + # ---------------------------------------------------------------- + def __init__(self, json_data): + + self.methods = { + "": (self.default_extract_method, []), + + "zarahome": (self.zarahome_extract_method, [ + "Краткое описание", + "Артикул", + "SKU", + "PartNumber", + "Название товара или услуги", + "Полное описание", + "Образец цвета", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Свойство: Вес(г)", + "Наличие на сайте", + "Изображения", + "Изображения варианта", + "Параметр: Состав", + "Параметр: Уход", + "Параметр: Происхождение", + "Размещение на сайте", + "Свойство: Бренд" + ]), + + # заглушки для старых магазинов + "zara": (self.zara_extract_method, []), + "eobuwie": (self.eobuwie_extract_method, []), + "decathlon": (self.decathlon_extract_method, []), + "chanel": (self.chanel_extract_method, []), + } + + self.method = json_data["method"] + self.tags = json_data["tags"] + self.headers = self.methods[self.method][1].copy() + + for tag in self.tags: + self.headers.insert(tag["column_number"], tag["column_name"]) + + # ---------------------------------------------------------------- + # общие утилиты + def extract(self, parser, recorder, categories): + self.methods[self.method][0](parser, recorder, categories) + + def default_extract_method(self, *a, **kw): + print("Default extractor → nothing to do.") + + def tags_extract(self, soup, row): + dom = etree.HTML(str(soup)) + for tag in self.tags: + res = dom.xpath(tag["xpath"]) + col = "" + if res: + for el in res: + col += ''.join(el.itertext()).strip() + "\n" + row.insert(tag["column_number"], col) + + # ---------------------------------------------------------------- + # заглушки для других методов + def zara_extract_method(self, *_, **__): print("ZARA extractor disabled.") + def eobuwie_extract_method(self, *_, **__): print("Eobuwie extractor disabled.") + def decathlon_extract_method(self, *_, **__): print("Decathlon extractor disabled.") + def chanel_extract_method(self, *_, **__): print("Chanel extractor disabled.") + + # ---------------------------------------------------------------- + # Z A R A H O M E + # ---------------------------------------------------------------- + def zarahome_extract_method(self, parser, recorder, categories): + + BASE_API = "https://www.zarahome.com/itxrest/3/catalog/store/85009924/80290000" + USER_BRAND = "ZARAHOME" + + for i, category in enumerate(categories): + table = [self.headers] + print(f"Categories: {i + 1} / {len(categories)} {category}") + + # ── HTML категории ─────────────────────────────────────── + html = parser.parse(category) + if html is None: + print("Extractor Error: empty page"); continue + soup = BeautifulSoup(html, "html.parser") + + script = soup.select_one("#serverApp-state") + + ####### Вывод того что есть Начало + # dump_name = f"state_dump_{int(time.time())}.json" + # pathlib.Path(dump_name).write_text(script.string, encoding="utf-8") + # print(f"🛈 serverApp-state saved → {dump_name}") + # + # state = loads(script.string) + # print("TOP-LEVEL KEYS:", list(state.keys())[:20]) + # print("inditex-data KEYS:", list(state.get("inditex-data", {}).keys())) + ####### Вывод того что есть Конец + + if not script: + print("Extractor Error: script#serverApp-state not found"); continue + try: + state = loads(script.string) + except Exception as e: + print(f"Extractor Error: bad JSON ({e})"); continue + + # ── category_id ────────────────────────────────────────── + cdata = state.get("inditex-data", {}) + cat_id = (cdata.get("iCategoryId") or + cdata.get("categoryId") or + cdata.get("iCategoryJSON", {}).get("id")) + if not cat_id: + for k in state: + m = search(r"/category/(\d+)/product", k) + if m: cat_id = m.group(1); break + if not cat_id: + print("Extractor Error: cannot detect category_id"); continue + + # ── блок с продуктами или их ID ───────────────────────── + key = next((k for k in state if f"/category/{cat_id}/product" in k), None) + if not key: + print("Extractor Error: products block not found"); continue + prod_block = state[key] + + summaries = [] + + # ★ Старая схема: products уже внутри + if "products" in prod_block: + for grp in prod_block["products"]: + summaries += grp["bundleProductSummaries"] + + # ★ Новая схема: нужно тянуть по productIds + else: + ids = (prod_block.get("productIds") or + prod_block.get("sortedProductIds") or + prod_block.get("sortedProductIdsByPricesAsc") or []) + print(f"→ pulling {len(ids)} products via API") + CHUNK = 20 + for p in range(0, len(ids), CHUNK): + ids_chunk = ",".join(map(str, ids[p:p+CHUNK])) + api = (f"{BASE_API}/productsArray" + f"?languageId=-1&productIds={ids_chunk}&appId=1") + data = parser.parse(api, return_type="json") + summaries += data.get("products", []) + print("DEBUG summaries count:", len(summaries)) + for p in summaries: + print(" •", p.get("id"), p.get("productUrl")) + + # ── путь категории для CSV ─────────────────────────────── + # cat_json = cdata.get("iCategoryJSON", {}) + # cat_title = "/".join(cat_json.get("parentNames", []) + + # [cat_json.get("name", "")]) + # cat_path = f"Каталог/ZaraHome/{cat_title}" + + seen = set() + for n, prod in enumerate(summaries, 1): + + short_url = prod.get("productUrl") + if not short_url or short_url in seen: + continue + seen.add(short_url) + print(f"Products: {n} / {len(summaries)} " + f"https://www.zarahome.com/pl/{short_url}") + + # ── у некоторых prod нет вариантов → смотрим глубже ── + variant_products = [] + if prod.get("detail", {}).get("colors"): + variant_products.append(prod) + elif prod.get("bundleProductSummaries"): + variant_products += prod["bundleProductSummaries"] + else: + variant_products.append(prod) # моно-товар без вариантов + + # ── обрабатываем каждый vprod (вариант или сам товар) ─ + for vprod in variant_products: + det = vprod["detail"] + + url_full = f"https://www.zarahome.com/pl/en/{vprod.get('productUrl','')}" + name = vprod.get("name", "") + article = det["displayReference"] + root_price = int(vprod.get("price", 0)) / 100 + root_wt = vprod.get("weight", "") + + # ── все изображения ──────────────────────────── + raw_xmedia = (det.get("xmedia") or vprod.get("xmedia") or []) + default_idx = det.get("xmediaDefaultSet") + if isinstance(raw_xmedia, list) and raw_xmedia: + media_sets = [raw_xmedia[default_idx]] if isinstance(default_idx, int) else raw_xmedia + elif isinstance(raw_xmedia, dict): + media_sets = [raw_xmedia] + else: + media_sets = [] + + all_imgs = [ + f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"] + ] + all_imgs_s = "\n".join(all_imgs) + + # ── состав / уход / происхождение ─────────────── + comp_block = det.get("compositionDetail") + comp_txt = "" + if comp_block and comp_block.get("parts"): + comp_txt = "\n".join( + extract_components_zarahome(comp_block["parts"]) + ) + care = "\n".join(c["description"] for c in det.get("care", [])) + + trace = "" + if det.get("traceability"): + trace = "\n".join( + f"{v['name']}\n" + "\n".join(v["country"]) + for v in det["traceability"].values() + if isinstance(v, dict) and v.get("country") and v.get("name") + ) + + # ── цвета и размеры ───────────────────────────── + colors_list = det.get("colors") or [] + if not colors_list: # моно-товар без цветов + colors_list = [{ + "id": 0, + "name": "DEFAULT", + "image": {"url": ""}, + "sizes": [{ + # "visibilityValue": "SHOW", + "name": "", + "description": "", + "weight": root_wt, + "price": vprod.get("price", 0) + }] + }] + + serial = 0 + for clr in colors_list: + if clr.get("image") is None and clr["name"] != "DEFAULT": + continue + + clr_code = clr.get("id") + clr_name = clr.get("name", "") + clr_image = "" + if clr.get("image") and clr["image"].get("url"): + clr_image = (f"https://static.zarahome.net/8/photos4" + f"{clr['image']['url']}_3_1_5.jpg") + + # картинки именно этого цвета + media_sets = [loc for loc in media_sets + if loc.get("colorCode") == clr_code] or media_sets + clr_imgs = [ + f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"] + ] + clr_imgs_s = "\n".join(clr_imgs) + + for size in clr["sizes"]: + # if size["visibilityValue"] != "SHOW": + # continue + #suffix = "" if serial == 0 else f"-{serial}" Раскомментить если надо добавлять "-1,2,3" к артикуду при повторениях + + serial += 1 + visibility = size.get("visibilityValue", "UNKNOWN") + size_name = size.get("name", "") + size_descr = size.get("description", "") + size_full = f"{size_descr} ({size_name})" if size_descr else size_name + size_weight = size.get("weight") or root_wt + size_price = int(size.get("price") or vprod.get("price", 0)) / 100 + + # ── путь категории из sectionNameEN / familyName / subFamilyName + sec = vprod.get("sectionNameEN") or "" # верхний уровень + fam = vprod.get("familyName") or "" # семья + sub = vprod.get("subFamilyName") or "" # подсемья + + cat_parts = [p for p in (sec, fam, sub) if p] # убираем пустые + cat_path = "Каталог/ZaraHome/" + "/".join(cat_parts) + + sku_val = size.get("sku", "") + partnumber_val = size.get("partnumber", "") + + table.append([ + url_full, + f"{article}", #{suffix}", Раскомментить если надо добавлять "-1,2,3" к артикуду при повторениях + name, + sku_val, # ← SKU + partnumber_val, # ← PartNumber + det.get("longDescription", ""), + clr_image, + clr_name, + size_full, + size_price, + size_weight, + visibility, + all_imgs_s, + clr_imgs_s, + comp_txt, + care, + trace, + cat_path, + USER_BRAND + ]) + + # ── запись CSV ────────────────────────────────────────── + csv_name = category.split("/")[-1] + recorder.record(csv_name, table) + + +def get_extractor(): + with open(abspath("parse_settings.json"), "r", encoding="utf-8") as file: + return Extractor(load(file)) \ No newline at end of file diff --git a/Parsing ZARAHOME/src/extractor copy 3.py b/Parsing ZARAHOME/src/extractor copy 3.py new file mode 100644 index 0000000..cb2e719 --- /dev/null +++ b/Parsing ZARAHOME/src/extractor copy 3.py @@ -0,0 +1,317 @@ +# extractor.py · v 2.0 · 2025-07-23 +from json import load, loads +from os.path import abspath +from bs4 import BeautifulSoup +from lxml import etree +import logging, os, sys + +# ────────────────────── настройка логирования ───────────────────── +_log_level = os.getenv("LOG_LEVEL", "INFO").upper() +logging.basicConfig( + level=_log_level, + stream=sys.stdout, + format="%(asctime)s │ %(levelname)-5s │ %(message)s", + datefmt="%H:%M:%S" +) +log = logging.getLogger("extractor") + +# ────────────────────── вспомогательные функции ─────────────────── +def extract_components_zarahome(parts): + comp = [] + for part in parts: + if part.get("areas") and part.get("description"): + if len(parts) != 1: + comp.append(part["description"]) + for area in part["areas"]: + comp.append(f"{area['description']} ({area['percentageArea']})") + for c in area["components"]: + comp.append(f"{c['percentage']} {c['material']}") + elif part.get("components") and part.get("description"): + if len(parts) != 1: + comp.append(part["description"]) + for c in part["components"]: + comp.append(f"{c['percentage']} {c['material']}") + return comp +# ──────────────────────────────────────────────────────────────────── + + +class Extractor: + def __init__(self, json_data): + + self.methods = { + "": (self.default_extract_method, []), + + "zarahome": (self.zarahome_extract_method, [ + "Краткое описание", + "Артикул", + "SKU", + "PartNumber", + "Название товара или услуги", + "Полное описание", + "Образец цвета", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Свойство: Вес(г)", + "Наличие на сайте", + "Изображения", + "Изображения варианта", + "Параметр: Состав", + "Параметр: Уход", + "Параметр: Происхождение", + "Размещение на сайте", + "Свойство: Бренд" + ]), + + "zara": (self.zara_extract_method, []), + "eobuwie": (self.eobuwie_extract_method, []), + "decathlon": (self.decathlon_extract_method, []), + "chanel": (self.chanel_extract_method, []), + } + + self.method = json_data["method"] + self.tags = json_data["tags"] + self.headers = self.methods[self.method][1].copy() + + for tag in self.tags: + self.headers.insert(tag["column_number"], tag["column_name"]) + + # ────────────────────────── общие утилиты ───────────────────── + def extract(self, parser, recorder, categories): + self.methods[self.method][0](parser, recorder, categories) + + def default_extract_method(self, *a, **kw): + log.info("Default extractor → nothing to do.") + + def tags_extract(self, soup, row): + dom = etree.HTML(str(soup)) + for tag in self.tags: + res = dom.xpath(tag["xpath"]) + col = "" + if res: + for el in res: + col += ''.join(el.itertext()).strip() + "\n" + row.insert(tag["column_number"], col) + + # ─────────── заглушки для неиспользуемых магазинов ──────────── + def zara_extract_method(self, *_, **__): log.info("ZARA extractor disabled.") + def eobuwie_extract_method(self, *_, **__): log.info("Eobuwie extractor disabled.") + def decathlon_extract_method(self, *_, **__): log.info("Decathlon extractor disabled.") + def chanel_extract_method(self, *_, **__): log.info("Chanel extractor disabled.") + + # ───────────────────── Z A R A H O M E ─────────────────────── + def zarahome_extract_method(self, parser, recorder, categories): + + BASE_API = "https://www.zarahome.com/itxrest/3/catalog/store/85009924/80290000" + USER_BRAND = "ZARAHOME" + + def fetch_json(url): + try: + return parser.parse(url, return_type="json") + except Exception as err: + log.warning("Request Error: %s - %s", err, url) + alt = url.replace( + "ieec2cihslb3-zarahome.central.inditex.grp", + "www.zarahome.com" + ) + if alt != url: + log.info("→ retry via public host") + return parser.parse(alt, return_type="json") + return None + + for c_idx, category in enumerate(categories, 1): + table = [self.headers] + log.info("Categories: %s / %s %s", c_idx, len(categories), category) + + html = parser.parse(category) + if html is None: + log.warning("Extractor Error: empty page"); continue + soup = BeautifulSoup(html, "html.parser") + + script = soup.select_one("#serverApp-state") + if not script: + log.warning("Extractor Error: script not found for %s", category) + continue + state = loads(script.string) + + cat_key = next(k for k in state if "/category?" in k) + cat_info = state[cat_key] + ids = [str(p["id"]) for p in cat_info.get("products", [])] + + summaries = [] + + # (A) productIds + if ids: + log.debug("→ pulling %s productIds via API", len(ids)) + CHUNK = 20 + for p in range(0, len(ids), CHUNK): + api = (f"{BASE_API}/productsArray?languageId=-1&" + f"productIds={','.join(ids[p:p+CHUNK])}&appId=1") + data = fetch_json(api) + if not data or "products" not in data: + log.debug("Skip chunk (no data)") + continue + summaries += data["products"] + + # (B) products в state или рекурсивный обход + else: + prod_key = next((k for k in state if "/product?" in k), None) + if prod_key and "products" in state[prod_key]: + log.debug("→ products array found in state") + for grp in state[prod_key]["products"]: + summaries += grp.get("bundleProductSummaries", []) + # ★ если products нет, но есть productIds → пользуемся API + elif prod_key and "productIds" in state[prod_key]: + ids = state[prod_key]["productIds"] + log.debug("→ pulling %s productIds via API (from prod_block)", len(ids)) + CHUNK = 20 + for p in range(0, len(ids), CHUNK): + api = (f"{BASE_API}/productsArray?languageId=-1&" + f"productIds={','.join(map(str, ids[p:p+CHUNK]))}&appId=1") + data = fetch_json(api) + if not data or "products" not in data: + log.debug("Skip chunk (no data)") + continue + summaries += data["products"] + else: + subcats = cat_info.get("subcategories") or [] + if not subcats: + log.info("→ no products in this category") + continue + log.info("→ diving into %s subcategories", len(subcats)) + for sub in subcats: + sub_url = "https://www.zarahome.com/pl/en/" + sub["url"] + sub_html = parser.parse(sub_url) + if not sub_html: + continue + sub_state = loads(BeautifulSoup(sub_html, "html.parser") + .select_one("#serverApp-state").string) + sub_prod_key = next((k for k in sub_state if "/product?" in k), None) + if sub_prod_key and "products" in sub_state[sub_prod_key]: + for grp in sub_state[sub_prod_key]["products"]: + summaries += grp.get("bundleProductSummaries", []) + + log.debug("JSON summaries count: %s", len(summaries)) + + seen_ids = set() + for n, prod in enumerate(summaries, 1): + prod_id = prod.get("id") + short_url = prod.get("productUrl") + + if not short_url and prod.get("seo"): + kw = prod["seo"].get("keyword", "") + sid = prod["seo"].get("seoProductId", "") + if kw and sid: + short_url = f"{kw}-p{sid}.html" + prod["productUrl"] = short_url + + if not short_url or prod_id in seen_ids: + continue + seen_ids.add(prod_id) + log.info("Products: %s / %s %s", n, len(summaries), + f"https://www.zarahome.com/pl/{short_url}") + + variants = prod.get("bundleProductSummaries") or [prod] + + for vprod in variants: + det = vprod["detail"] + + sec, fam, sub = (vprod.get("sectionNameEN") or "", + vprod.get("familyName") or "", + vprod.get("subFamilyName") or "") + cat_path = "Каталог/ZaraHome/" + "/".join(p for p in (sec, fam, sub) if p) + + url_full = f"https://www.zarahome.com/pl/en/{vprod.get('productUrl','')}" + name = vprod.get("name", "") + article = det["displayReference"] + root_price = int(vprod.get("price", 0)) / 100 + root_wt = vprod.get("weight", "") + + raw_xmedia = det.get("xmedia") or vprod.get("xmedia") or [] + default_idx = det.get("xmediaDefaultSet") + if isinstance(raw_xmedia, list) and raw_xmedia: + media_sets = [raw_xmedia[default_idx]] if isinstance(default_idx, int) else raw_xmedia + elif isinstance(raw_xmedia, dict): + media_sets = [raw_xmedia] + else: + media_sets = [] + all_imgs = [f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"]] + all_imgs_s = "\n".join(all_imgs) + + comp_txt = "" + if det.get("compositionDetail") and det["compositionDetail"].get("parts"): + comp_txt = "\n".join( + extract_components_zarahome(det["compositionDetail"]["parts"]) + ) + care = "\n".join(c["description"] for c in det.get("care", [])) + trace = "" + + colors = det.get("colors") or [{ + "id": 0, "name": "DEFAULT", "image": {"url": ""}, + "sizes": [{ + "visibilityValue": "SHOW", + "name": "", "description": "", + "weight": root_wt, "price": vprod.get("price", 0) + }] + }] + + #serial = 0 + for clr in colors: + clr_code = clr.get("id") + clr_name = clr.get("name", "") + clr_image = "" + if clr.get("image") and clr["image"].get("url"): + clr_image = f"https://static.zarahome.net/8/photos4{clr['image']['url']}_3_1_5.jpg" + + clr_sets = [loc for loc in media_sets if loc.get("colorCode") == clr_code] or media_sets + clr_imgs = [f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in clr_sets + for m in loc["xmediaItems"][0]["medias"]] + clr_imgs_s = "\n".join(clr_imgs) + + for size in clr["sizes"]: + vis = size.get("visibilityValue", "UNKNOWN") + price = int(size.get("price") or vprod.get("price", 0)) / 100 + weight = size.get("weight") or root_wt + # ── страна изготовления (если есть в size) + country = size.get("country") or "" + trace_local = f"Made in {country}" if country else trace + + size_name = size.get("name", "") + size_descr = size.get("description", "") + size_full = f"{size_descr} ({size_name})" if size_descr else size_name + # ── SKU / PartNumber берём из size ─────────────── + sku_val = size.get("sku", "") + partnumber_val = size.get("partnumber", "") + table.append([ + url_full, + article, + sku_val, + partnumber_val, + name, + det.get("longDescription", ""), + clr_image, + clr_name, + size_full, + price, + weight, + vis, + all_imgs_s, + clr_imgs_s, + comp_txt, + care, + trace_local, + cat_path, + USER_BRAND + ]) + + csv_name = category.split("/")[-1] + recorder.record(csv_name, table) + + +# ──────────────────────────────────────────────────────────────────── +def get_extractor(): + with open(abspath("parse_settings.json"), "r", encoding="utf-8") as fh: + return Extractor(load(fh)) diff --git a/Parsing ZARAHOME/src/extractor copy 4 -delthesame1.py b/Parsing ZARAHOME/src/extractor copy 4 -delthesame1.py new file mode 100644 index 0000000..8dfe95a --- /dev/null +++ b/Parsing ZARAHOME/src/extractor copy 4 -delthesame1.py @@ -0,0 +1,379 @@ +# extractor.py · v 2.0 · 2025-07-23 +from json import load, loads +from os.path import abspath +from bs4 import BeautifulSoup +from lxml import etree +import logging, os, sys + +# включение / выключение фильтра дубликатов +DEL_SAME = "YES" # "YES" → фильтр активен, "NO" → пишем всё как есть + +# ────────────────────── настройка логирования ───────────────────── +_log_level = os.getenv("LOG_LEVEL", "INFO").upper() +logging.basicConfig( + level=_log_level, + stream=sys.stdout, + format="%(asctime)s │ %(levelname)-5s │ %(message)s", + datefmt="%H:%M:%S" +) +log = logging.getLogger("extractor") + +# ────────────────────── вспомогательные функции ─────────────────── +def extract_components_zarahome(parts): + comp = [] + for part in parts: + if part.get("areas") and part.get("description"): + if len(parts) != 1: + comp.append(part["description"]) + for area in part["areas"]: + comp.append(f"{area['description']} ({area['percentageArea']})") + for c in area["components"]: + comp.append(f"{c['percentage']} {c['material']}") + elif part.get("components") and part.get("description"): + if len(parts) != 1: + comp.append(part["description"]) + for c in part["components"]: + comp.append(f"{c['percentage']} {c['material']}") + return comp +# ──────────────────────────────────────────────────────────────────── +# ────────────────── фильтр «одинаковых» товаров ────────────────── +def filter_duplicates(table, headers): + """Убирает строки по правилам DEL_SAME. table[0] — заголовок.""" + if DEL_SAME != "YES" or len(table) <= 2: + return table + + # индексы нужных колонок + idx = {h: i for i, h in enumerate(headers)} + art_i = idx["Артикул"] + name_i = idx["Название товара или услуги"] + size_i = idx["Свойство: Размер"] + price_i = idx["Цена закупки"] + clr_i = idx["Свойство: Цвет"] + pn_i = idx["PartNumber"] + vis_i = idx["Наличие на сайте"] + + keep_rows = [table[0]] # сохраняем заголовок + groups = {} + + # ── группируем по 5 базовым полям ─────────────────────────────── + for row in table[1:]: + key = (row[art_i], row[name_i], row[size_i], row[price_i], row[clr_i]) + groups.setdefault(key, []).append(row) + + # ── применяем правила к каждой группе ─────────────────────────── + for rows in groups.values(): + if len(rows) == 1: + keep_rows.append(rows[0]) + continue + + # 2) одни и те же PartNumber? → оставляем первую + pn_set = {r[pn_i] for r in rows} + if len(pn_set) == 1: + keep_rows.append(rows[0]) + continue + + # 3) vis одинаковый? + vis_set = {r[vis_i] for r in rows} + if len(vis_set) == 1: # одинаковые + # 4) сравниваем 4-символьные коды + good = [] + for r in rows: + art4 = r[art_i][:4] + pn4 = r[pn_i][1:5] if len(r[pn_i]) >= 5 else "" + if art4 == pn4: + good.append(r) + # оставляем только подходящие; если ни одного — первую + keep_rows.extend(good or [rows[0]]) + else: # 5) vis разные + show = [r for r in rows if r[vis_i] == "SHOW"] + keep_rows.extend(show or rows) # остаётся SHOW, иначе всё + + return keep_rows + + +class Extractor: + def __init__(self, json_data): + + self.methods = { + "": (self.default_extract_method, []), + + "zarahome": (self.zarahome_extract_method, [ + "Краткое описание", + "Артикул", + "SKU", + "PartNumber", + "Название товара или услуги", + "Полное описание", + "Образец цвета", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Свойство: Вес(г)", + "Наличие на сайте", + "Изображения", + "Изображения варианта", + "Параметр: Состав", + "Параметр: Уход", + "Параметр: Происхождение", + "Размещение на сайте", + "Свойство: Бренд" + ]), + + "zara": (self.zara_extract_method, []), + "eobuwie": (self.eobuwie_extract_method, []), + "decathlon": (self.decathlon_extract_method, []), + "chanel": (self.chanel_extract_method, []), + } + + self.method = json_data["method"] + self.tags = json_data["tags"] + self.headers = self.methods[self.method][1].copy() + + for tag in self.tags: + self.headers.insert(tag["column_number"], tag["column_name"]) + + # ────────────────────────── общие утилиты ───────────────────── + def extract(self, parser, recorder, categories): + self.methods[self.method][0](parser, recorder, categories) + + def default_extract_method(self, *a, **kw): + log.info("Default extractor → nothing to do.") + + def tags_extract(self, soup, row): + dom = etree.HTML(str(soup)) + for tag in self.tags: + res = dom.xpath(tag["xpath"]) + col = "" + if res: + for el in res: + col += ''.join(el.itertext()).strip() + "\n" + row.insert(tag["column_number"], col) + + # ─────────── заглушки для неиспользуемых магазинов ──────────── + def zara_extract_method(self, *_, **__): log.info("ZARA extractor disabled.") + def eobuwie_extract_method(self, *_, **__): log.info("Eobuwie extractor disabled.") + def decathlon_extract_method(self, *_, **__): log.info("Decathlon extractor disabled.") + def chanel_extract_method(self, *_, **__): log.info("Chanel extractor disabled.") + + # ───────────────────── Z A R A H O M E ─────────────────────── + def zarahome_extract_method(self, parser, recorder, categories): + + BASE_API = "https://www.zarahome.com/itxrest/3/catalog/store/85009924/80290000" + USER_BRAND = "ZARAHOME" + + def fetch_json(url): + try: + return parser.parse(url, return_type="json") + except Exception as err: + log.warning("Request Error: %s - %s", err, url) + alt = url.replace( + "ieec2cihslb3-zarahome.central.inditex.grp", + "www.zarahome.com" + ) + if alt != url: + log.info("→ retry via public host") + return parser.parse(alt, return_type="json") + return None + + for c_idx, category in enumerate(categories, 1): + table = [self.headers] + log.info("Categories: %s / %s %s", c_idx, len(categories), category) + + html = parser.parse(category) + if html is None: + log.warning("Extractor Error: empty page"); continue + soup = BeautifulSoup(html, "html.parser") + + script = soup.select_one("#serverApp-state") + if not script: + log.warning("Extractor Error: script not found for %s", category) + continue + state = loads(script.string) + + cat_key = next(k for k in state if "/category?" in k) + cat_info = state[cat_key] + ids = [str(p["id"]) for p in cat_info.get("products", [])] + + summaries = [] + + # (A) productIds + if ids: + log.debug("→ pulling %s productIds via API", len(ids)) + CHUNK = 20 + for p in range(0, len(ids), CHUNK): + api = (f"{BASE_API}/productsArray?languageId=-1&" + f"productIds={','.join(ids[p:p+CHUNK])}&appId=1") + data = fetch_json(api) + if not data or "products" not in data: + log.debug("Skip chunk (no data)") + continue + summaries += data["products"] + + # (B) products в state или рекурсивный обход + else: + prod_key = next((k for k in state if "/product?" in k), None) + if prod_key and "products" in state[prod_key]: + log.debug("→ products array found in state") + for grp in state[prod_key]["products"]: + summaries += grp.get("bundleProductSummaries", []) + # ★ если products нет, но есть productIds → пользуемся API + elif prod_key and "productIds" in state[prod_key]: + ids = state[prod_key]["productIds"] + log.debug("→ pulling %s productIds via API (from prod_block)", len(ids)) + CHUNK = 60 + for p in range(0, len(ids), CHUNK): + api = (f"{BASE_API}/productsArray?languageId=-1&" + f"productIds={','.join(map(str, ids[p:p+CHUNK]))}&appId=1") + data = fetch_json(api) + if not data or "products" not in data: + log.debug("Skip chunk (no data)") + continue + summaries += data["products"] + else: + subcats = cat_info.get("subcategories") or [] + if not subcats: + log.info("→ no products in this category") + continue + log.info("→ diving into %s subcategories", len(subcats)) + for sub in subcats: + sub_url = "https://www.zarahome.com/pl/en/" + sub["url"] + sub_html = parser.parse(sub_url) + if not sub_html: + continue + sub_state = loads(BeautifulSoup(sub_html, "html.parser") + .select_one("#serverApp-state").string) + sub_prod_key = next((k for k in sub_state if "/product?" in k), None) + if sub_prod_key and "products" in sub_state[sub_prod_key]: + for grp in sub_state[sub_prod_key]["products"]: + summaries += grp.get("bundleProductSummaries", []) + + log.debug("JSON summaries count: %s", len(summaries)) + + seen_ids = set() + for n, prod in enumerate(summaries, 1): + prod_id = prod.get("id") + short_url = prod.get("productUrl") + + if not short_url and prod.get("seo"): + kw = prod["seo"].get("keyword", "") + sid = prod["seo"].get("seoProductId", "") + if kw and sid: + short_url = f"{kw}-p{sid}.html" + prod["productUrl"] = short_url + + if not short_url or prod_id in seen_ids: + continue + seen_ids.add(prod_id) + log.info("Products: %s / %s %s", n, len(summaries), + f"https://www.zarahome.com/pl/{short_url}") + + variants = prod.get("bundleProductSummaries") or [prod] + + for vprod in variants: + det = vprod["detail"] + + sec, fam, sub = (vprod.get("sectionNameEN") or "", + vprod.get("familyName") or "", + vprod.get("subFamilyName") or "") + cat_path = "Каталог/ZaraHome/" + "/".join(p for p in (sec, fam, sub) if p) + + url_full = f"https://www.zarahome.com/pl/en/{vprod.get('productUrl','')}" + name = vprod.get("name", "") + article = det["displayReference"] + root_price = int(vprod.get("price", 0)) / 100 + root_wt = vprod.get("weight", "") + + raw_xmedia = det.get("xmedia") or vprod.get("xmedia") or [] + default_idx = det.get("xmediaDefaultSet") + if isinstance(raw_xmedia, list) and raw_xmedia: + media_sets = [raw_xmedia[default_idx]] if isinstance(default_idx, int) else raw_xmedia + elif isinstance(raw_xmedia, dict): + media_sets = [raw_xmedia] + else: + media_sets = [] + all_imgs = [f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"]] + all_imgs_s = "\n".join(all_imgs) + + comp_txt = "" + if det.get("compositionDetail") and det["compositionDetail"].get("parts"): + comp_txt = "\n".join( + extract_components_zarahome(det["compositionDetail"]["parts"]) + ) + care = "\n".join(c["description"] for c in det.get("care", [])) + trace = "" + + colors = det.get("colors") or [{ + "id": 0, "name": "DEFAULT", "image": {"url": ""}, + "sizes": [{ + "visibilityValue": "SHOW", + "name": "", "description": "", + "weight": root_wt, "price": vprod.get("price", 0) + }] + }] + + #serial = 0 + for clr in colors: + clr_code = clr.get("id") + clr_name = clr.get("name", "") + clr_image = "" + if clr.get("image") and clr["image"].get("url"): + clr_image = f"https://static.zarahome.net/8/photos4{clr['image']['url']}_3_1_5.jpg" + + clr_sets = [loc for loc in media_sets if loc.get("colorCode") == clr_code] or media_sets + clr_imgs = [f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in clr_sets + for m in loc["xmediaItems"][0]["medias"]] + clr_imgs_s = "\n".join(clr_imgs) + + for size in clr["sizes"]: + vis = size.get("visibilityValue", "UNKNOWN") + price = int(size.get("price") or vprod.get("price", 0)) / 100 + weight = size.get("weight") or root_wt + # ── страна изготовления (если есть в size) + country = size.get("country") or "" + trace_local = f"Made in {country}" if country else trace + + size_name = size.get("name", "") + size_descr = size.get("description", "") + size_full = f"{size_descr} ({size_name})" if size_descr else size_name + # ── SKU / PartNumber берём из size ─────────────── + sku_val = size.get("sku", "") + partnumber_val = size.get("partnumber", "") + table.append([ + url_full, + article, + sku_val, + partnumber_val, + name, + det.get("longDescription", ""), + clr_image, + clr_name, + size_full, + price, + weight, + vis, + all_imgs_s, + clr_imgs_s, + comp_txt, + care, + trace_local, + cat_path, + USER_BRAND + ]) + + csv_name = category.split("/")[-1] + clean_table = filter_duplicates(table, self.headers) + recorder.record(csv_name, clean_table) + + + #csv_name = category.split("/")[-1] + #recorder.record(csv_name, table) + + + +# ──────────────────────────────────────────────────────────────────── +def get_extractor(): + with open(abspath("parse_settings.json"), "r", encoding="utf-8") as fh: + return Extractor(load(fh)) diff --git a/Parsing ZARAHOME/src/extractor copy.py b/Parsing ZARAHOME/src/extractor copy.py new file mode 100644 index 0000000..0e0401b --- /dev/null +++ b/Parsing ZARAHOME/src/extractor copy.py @@ -0,0 +1,940 @@ +from json import load, loads +from os.path import abspath +from bs4 import BeautifulSoup +from lxml import etree +from re import split, search, sub + +def extract_components_zarahome(parts): + composition = [] + for part in parts: + if part.get("areas") and part.get("description"): + if len(parts) != 1: + composition.append(part["description"]) + for area in part["areas"]: + area_name = area["description"] + percentage_area = area["percentageArea"] + + composition.append(f"{area_name} ({percentage_area})") + for component in area["components"]: + material = component["material"] + percentage = component["percentage"] + + composition.append(f"{percentage} {material}") + elif part.get("components") and part.get("description"): + if len(parts) != 1: + composition.append(part["description"]) + for component in part["components"]: + material = component["material"] + percentage = component["percentage"] + + composition.append(f"{percentage} {material}") + + return composition + +# класс для извлечения нужных данных +class Extractor: + def __init__(self, json_data): + self.methods = { + "": (self.default_extract_method, []), + "zarahome": (self.zarahome_extract_method, [ + "Краткое описание", + "Артикул", + "Название товара или услуги", + "Полное описание", + "Образец цвета", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Свойство: Вес(г)", + "Изображения", + "Изображения варианта", + "Параметр: Состав", + "Параметр: Уход", + "Параметр: Происхождение", + "Размещение на сайте", + "Свойство: Бренд" + ]), + "eobuwie": (self.eobuwie_extract_method, [ + "Краткое описание", + "Артикул", + "Свойство: Размер", + "Полное описание(Таблица)", + "Название товара или услуги", + "Изображения", + "Размещение на сайте", + "Цена", + "Наличие" + ]), + "decathlon": (self.decathlon_extract_method, [ + "Краткое описание", + "Артикул", + "Название товара или услуги", + "Полное описание", + "Наличие", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Параметр: Вес(г)", + "Изображения варианта", + "Размещение на сайте" + ]), + "zara": (self.zara_extract_method, [ + "Краткое описание", + "Артикул", + "Название товара или услуги", + "Наличие", + "Образец цвета", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Изображения", + "Параметр: Состав", + "Параметр: Уход", + "Параметр: Происхождение", + "Размещение на сайте", + "Свойство: Бренд" + ]), + "chanel": (self.chanel_extract_method, [ + "Краткое описание", + "Артикул", + "Наличие", + "Свойство: Цвет", + "Свойство: Размер", + "Цена закупки", + "Изображения", + "Размещение на сайте", + "Свойство: Бренд" + ]) + } + self.method = json_data["method"] + self.tags = json_data["tags"] + + self.headers = self.methods[self.method][1] + + for tag in self.tags: + self.headers.insert(tag["column_number"], tag["column_name"]) + + def extract(self, parser, recorder, categories): + self.methods[self.method][0](parser, recorder, categories) + + def default_extract_method(self): + pass + + def tags_extract(self, soup, row): + + dom_tree = etree.HTML(str(soup)) + + for tag in self.tags: + + xpath_result = dom_tree.xpath(tag["xpath"]) + + column_data = "" + + if len(xpath_result): + + for element in xpath_result: + + column_data = ''.join(element.itertext()).strip() + "\n" + + row.insert(tag["column_number"], column_data) + + def chanel_extract_method(self, parser, recorder, categories): + + BASE_URL = "https://www.chanel.com" + + for i, category in enumerate(categories): + table = [self.headers] + + print(f"Categories: {i + 1} / {len(categories)}", category) + + continue_loop = True + + category_page = 1 + + request_elements_count = 24 + + product_number = 1 + + category_pattern = r"\/pl\/[\w\d]+\/" + + location = "chanel/" + search(category_pattern, category)[0].replace("pl", "").replace("/", "") + + while continue_loop: + + category_data = parser.parse(f"{category}?requestType=ajax&page={category_page}&totalElementsCount={request_elements_count}", return_type="json") + + if not category_data["next"]: + continue_loop = False + + products_count = category_data["totalProducts"] + + for product in category_data["dataLayer"]["productList"].values(): + + first_variant = True + + article_pattern = r"\/p\/[\d\w]+/" + + base_link = BASE_URL + product["quickviewPopin"]["page"] + + print(f"Products: {product_number} / {products_count}", base_link) + + product_number += 1 + + links = [base_link] + + while len(links): + + product_url = links.pop(0) + + product_page = parser.parse(product_url) + + if product_page == None: + continue + + soup = BeautifulSoup(product_page, "html.parser") + + if first_variant: + first_variant = False + + variants_links = soup.select(".link.js-tabpanel-anchor") + + replace_pattern = r"\/p\/.+$" + + for variant_link in variants_links: + article = variant_link.get("data-value") + + if not article in product_url: + + links.append(sub(replace_pattern, f"/p/{article}", product_url)) + + + product_url = soup.select("[property=\"og:url\"]")[0].get("content") + + article = search(article_pattern, product_url)[0].replace("/", "").replace("p", "") + + product_info = parser.parse(f"{BASE_URL}/pl/yapi/product/{article}?options=basic,vto,variants,stock&site=chanel", return_type="json") + + stock = 0 + + if product_info["stock"]["stockLevel"] == "IN_STOCK": + stock = 1 + + product_color_name = product_info["color"]["name"] + + product_size = product_info.get("size") + + product_price = product_info["buyNow"].get("priceValue") + + images = "\n".join(map(lambda x: x["url"], product_info["basic"]["images"])) + + product_brand = "chanel" + + + try: + + table_data = [] + + table_data.append([ + product_url, + article, + stock, + product_color_name, + product_size, + product_price, + images, + location, + product_brand + ]) + + self.tags_extract(soup, table_data[-1]) + + table += table_data.copy() + + + except Exception as error: + print(f"Extractor Error: {error}") + + csv_name = category.replace(f"{BASE_URL}/pl/", "").replace("/", "_") + recorder.record(csv_name, table) + + + def zara_extract_method(self, parser, recorder, categories): + + BASE_URL = "https://www.zara.com" + BASE_POLISH_URL = "https://www.zara.com/pl/en/" + + for i, category in enumerate(categories): + table = [self.headers] + + print(f"Categories: {i + 1} / {len(categories)}", category) + + category_page = parser.parse(category) + + category_soup = BeautifulSoup(category_page, "html.parser") + + verify_url = category_soup.select("[http-equiv=\"refresh\"]")[0].get("content").split("'")[1] + + bm_verify = verify_url.split("?")[-1] + + category_page = parser.parse(BASE_URL + verify_url) + + category_soup = BeautifulSoup(category_page, "html.parser") + + tag_script_inner = category_soup.select("[type=\"text/javascript\"][data-compress=\"true\"]")[0].text + + analytics_data = loads(search(r"zara\.analyticsData\s?=\s?{.+};", tag_script_inner)[0].split("=")[1].replace(";", "")) + + category_id = analytics_data["catGroupId"] + + category_products = parser.parse(f"{BASE_POLISH_URL}category/{category_id}/products?ajax=true", return_type="json") + + + + + location = "ZARA/" + "/".join(category.split("/")[5].split("-")[:2]).upper() + + all_products_count = 0 + + for element in category_products["productGroups"][0]["elements"]: + products = element.get("commercialComponents") + if not products: + continue + for product in products: + if not product.get("name"): + continue + all_products_count += 1 + + + product_number = 0 + + for element in category_products["productGroups"][0]["elements"]: + + products = element.get("commercialComponents") + + if not products: + continue + + for product in products: + + product_name = product.get("name") + + if not product_name: + continue + + product_number += 1 + + seo_keyword = product["seo"]["keyword"] + seo_id = product["seo"]["seoProductId"] + + if not seo_keyword: + continue + + product_url = f"{BASE_POLISH_URL}{seo_keyword}-p{seo_id}.html" + + print(f"Products: {product_number} / {all_products_count}", product_url) + + article = product["detail"]["displayReference"] + + product_color_hex = product["colorInfo"].get("mainColorHexCode") + + product_color_name = product["detail"]["colors"][0]["name"] + + product_price = product["price"] / 100 + + product_brand = product["brand"].get("brandGroupCode") + + product_page = parser.parse(f"{product_url}?{bm_verify}") + + if product_page == None: + continue + + soup = BeautifulSoup(product_page, "html.parser") + + sizes = soup.select("[data-qa-action][role=\"option\"]") + + images = "\n".join(map(lambda x: x.get("srcset").split(", ")[-1].split(" ")[0], soup.select(f"source[sizes=\"32vw\"]"))) + + + product_id = product["id"] + + extra_data = parser.parse(f"https://www.zara.com/pl/pl/product/{product_id}/extra-detail?ajax=true", return_type="json") + + + extra_data_extracted = {} + + for section in extra_data: + extra_data_extracted[section["sectionType"]] = "" + + for component in section["components"]: + if component["datatype"] in ["subtitle", "paragraph"]: + extra_data_extracted[section["sectionType"]] += component["text"]["value"] + "\n" + + elif component["datatype"] == "spacer": + extra_data_extracted[section["sectionType"]] += "\n" + + elif component["datatype"] == "iconList": + for item in component["items"]: + if item["datatype"] == "iconListItem" and item["description"]["datatype"] == "text": + extra_data_extracted[section["sectionType"]] += item["description"]["value"] + "\n" + + materials = extra_data_extracted.get("materials") + + care = extra_data_extracted.get("care") + + origin = extra_data_extracted.get("origin") + + + for size in sizes: + try: + + table_data = [] + + if size.get("data-qa-action") == "size-in-stock": + stock = 1 + else: + stock = 0 + + product_size = size.select(".product-size-info__main-label")[0].text + + table_data.append([ + product_url, + f"{article} - {product_size}", + product_name, + stock, + product_color_hex, + product_color_name, + product_size, + product_price, + images, + materials, + care, + origin, + location, + product_brand + ]) + + self.tags_extract(soup, table_data[-1]) + + table += table_data.copy() + + + + except Exception as error: + print(f"Extractor Error: {error}") + + csv_name = category.split("/")[-1].split("?")[0] + recorder.record(csv_name, table) + + + + def decathlon_extract_method(self, parser, recorder, categories): + + BASE_URL = "https://www.decathlon.pl" + + for i, category in enumerate(categories): + table = [self.headers] + + print(f"Categories: {i + 1} / {len(categories)}", category) + + continue_loop = True + + category_from = 0 + + while continue_loop: + + category_page = parser.parse(f"{category}?from={category_from}") + + category_soup = BeautifulSoup(category_page, "html.parser") + + offers_count = int(category_soup.select("h1 ~ span.count")[0].text.split(" ")[0]) + + products_links = category_soup.select("[class$=\"model-link\"]") + + products_links_count = len(products_links) + + for e, product_link in enumerate(products_links): + + product_url = BASE_URL + product_link.get("href") + + print(f"Products: {e + 1 + category_from} / {offers_count}", product_url) + + product_page = parser.parse(product_url) + + if product_page == None: + continue + + soup = BeautifulSoup(product_page, "html.parser") + + meta_script_tags = soup.select("[type=\"application/ld+json\"]") + + if len(meta_script_tags) <= 1: + continue + + meta_data = loads(meta_script_tags[1].text) + + path_steps = [] + + for step in meta_data["itemListElement"]: + path_steps.append(step["item"]["name"]) + + product_path = "decathlon/" + "/".join(path_steps) + + script_json = soup.select("#__dkt")[0] + + __dkt = loads(script_json.text.replace("__DKT = ", "")) + + if __dkt["_ctx"]["page"]["id"] != "product": + continue + + models_data = __dkt["_ctx"]["data"][4]["data"]["models"] + + for model in models_data: + + color = "" + colors = [] + + if model.get("colors"): + for color_info in model["colors"]: + colors.append(color_info["label"]) + + color = " / ".join(colors) + + images = [] + + for image_info in model["images"]["product"]: + images.append(image_info["url"].replace("/250x250", "")) + + image_lines = "\n".join(images) + + + product_name = model["webLabel"] + + + product_description = soup.select("[id^=\"ProductFunctionalities\"]") + + if len(product_description): + product_description = product_description[0].encode_contents() + else: + product_description = "" + + + + skus_data = model["skus"] + + sku_ids = [] + + for sku in skus_data: + sku_ids.append(sku["skuId"]) + + sku_ids = ",".join(sku_ids) + + stocks = parser.parse(f"https://www.decathlon.pl/pl/ajax/nfs/stocks/online?skuIds={sku_ids}", return_type="json") + + for sku in skus_data: + try: + + sku_id = sku["skuId"] + + + stock = stocks[sku_id]["stockOnline"] if stocks.get(sku_id) else "unknown" + + table_data = [] + + article = f'{model["modelId"]}-{sku_id}' + + size = "" + if sku.get("size"): + size = sku["size"] + + price = "" + if sku.get("price"): + price = sku["price"] + + weight = "" + if sku.get("grossWeight"): + weight = float(sku["grossWeight"]) + + table_data.append([ + product_url, + article, + product_name, + product_description, + stock, + color, + size, + price, + weight, + image_lines, + product_path + ]) + + self.tags_extract(soup, table_data[-1]) + + table += table_data.copy() + + except Exception as error: + print(f"Extractor Error: {error}") + + + if offers_count == products_links_count + category_from: + continue_loop = False + else: + category_from += products_links_count + + csv_name = "_".join(category.split("/")[4:]).replace(":", "-").replace("?", "_").replace("=", "_") + recorder.record(csv_name, table) + + + def eobuwie_extract_method(self, parser, recorder, categories): + + for i, category in enumerate(categories): + table = [self.headers] + + print(f"Categories: {i + 1} / {len(categories)}", category) + + category_page = 1 + + category_marka = category.split(":")[2].split("?")[0] + category_type = category.split("/")[4] + + while True: + + category_products_data = parser.parse(f"https://eobuwie.com.pl/t-api/rest/search/eobuwie/v5/search?channel=eobuwie¤cy=PLN&locale=pl_PL&limit=100&page={category_page}&filters[marka][in][]={category_marka}&categories[]={category_type}&select[]=url_key&select[]=product_group_associated&select[]=images&select[]=final_price&select[]=footwear_size&select_locales[]=pl_PL", return_type="json") + + total = category_products_data["total"] + + products = category_products_data["products"] + + for e, product in enumerate(products): + + short_url = product["values"]["url_key"]["value"]["pl_PL"] + + product_url = f"https://eobuwie.com.pl/p/{short_url}" + + print(f"Products: {e + 1 + ((category_page - 1) * 100)} / {total}", product_url) + + product_page = parser.parse(product_url) + + if product_page == None: + continue + + soup = BeautifulSoup(product_page, "html.parser") + + links = soup.select(".breadcrumb-list .text-link")[2:] + + product_location = "/".join(list(map(lambda x: x.text, links))) + + product_group = "" + + if product["values"].get("product_group_associated") and product["values"]["product_group_associated"].get("value"): + product_group = product["values"]["product_group_associated"]["value"] + + product_name = soup.select("[data-test-id=\"product-name\"]")[0].text.strip() + + product_name = split(r"\d", product_name)[0] + + product_name = f"{product_name} - {product_group}" + + + images_list = [] + + if product["values"].get("images") and product["values"]["images"].get("value"): + for image in product["values"]["images"]["value"]: + if image.get("url"): + images_list.append(f'https://img.modivo.cloud/eob_product_1800w_1800h({image["url"]}.jpg,webp)') + + images_list = "\n".join(images_list) + + for i, variant in enumerate(product["variants"].values()): + try: + table_data = [] + + size_url = variant["size"] + + variant_url = f"{product_url}?size={size_url}" + + article = variant["id"] + + size_name = "" + + if variant["values"].get("footwear_size"): + + size_name = variant["values"]["footwear_size"]["value"]["label"] + + description = "" + + location = f"Каталог/Обувь и аксессуары/{product_location}" + + availability = variant["stock_quantity"] + + if variant["stock_quantity"]: + price = variant["offers"][0]["final_price"]["amount"] + else: + price = product["values"]["final_price"]["value"]["pl_PL"]["PLN"]["amount"] + + table_data.append([ + variant_url, + article, + size_name, + description, + product_name, + images_list, + location, + price, + availability + ]) + + self.tags_extract(soup, table_data[-1]) + + table += table_data.copy() + + except Exception as error: + print(f"Extractor Error: {error}") + + + if category_page * 100 >= total: + break + + category_page += 1 + + + csv_name = category.split("/")[-1].replace(":", "-").replace("?", "_").replace("=", "_") + recorder.record(csv_name, table) + + def zarahome_extract_method(self, parser, recorder, categories): + + BASE_API = "https://ieec2cihslb3-zarahome.central.inditex.grp/itxrest/3/catalog/store/85009924/80290000" + USER_BRAND = "ZARAHOME" + + for i, category in enumerate(categories): + table = [self.headers] + print(f"Categories: {i + 1} / {len(categories)} {category}") + + # ── HTML категории ─────────────────────────────────────── + html = parser.parse(category) + if html is None: + print("Extractor Error: empty page"); continue + soup = BeautifulSoup(html, "html.parser") + + script = soup.select_one("#serverApp-state") + + ####### Вывод того что есть Начало + # dump_name = f"state_dump_{int(time.time())}.json" + # pathlib.Path(dump_name).write_text(script.string, encoding="utf-8") + # print(f"🛈 serverApp-state saved → {dump_name}") + # + # state = loads(script.string) + # print("TOP-LEVEL KEYS:", list(state.keys())[:20]) + # print("inditex-data KEYS:", list(state.get("inditex-data", {}).keys())) + ####### Вывод того что есть Конец + + if not script: + print("Extractor Error: script#serverApp-state not found"); continue + try: + state = loads(script.string) + except Exception as e: + print(f"Extractor Error: bad JSON ({e})"); continue + + # ── category_id ────────────────────────────────────────── + cdata = state.get("inditex-data", {}) + cat_id = (cdata.get("iCategoryId") or + cdata.get("categoryId") or + cdata.get("iCategoryJSON", {}).get("id")) + if not cat_id: + for k in state: + m = search(r"/category/(\d+)/product", k) + if m: cat_id = m.group(1); break + if not cat_id: + print("Extractor Error: cannot detect category_id"); continue + + # ── блок с продуктами или их ID ───────────────────────── + key = next((k for k in state if f"/category/{cat_id}/product" in k), None) + if not key: + print("Extractor Error: products block not found"); continue + prod_block = state[key] + + summaries = [] + + # ★ Старая схема: products уже внутри + if "products" in prod_block: + for grp in prod_block["products"]: + summaries += grp["bundleProductSummaries"] + + # ★ Новая схема: нужно тянуть по productIds + else: + ids = (prod_block.get("productIds") or + prod_block.get("sortedProductIds") or + prod_block.get("sortedProductIdsByPricesAsc") or []) + print(f"→ pulling {len(ids)} products via API") + CHUNK = 20 + for p in range(0, len(ids), CHUNK): + ids_chunk = ",".join(map(str, ids[p:p+CHUNK])) + api = (f"{BASE_API}/productsArray" + f"?languageId=-1&productIds={ids_chunk}&appId=1") + data = parser.parse(api, return_type="json") + summaries += data.get("products", []) + print("DEBUG summaries count:", len(summaries)) + for p in summaries: + print(" •", p.get("id"), p.get("productUrl")) + + # ── путь категории для CSV ─────────────────────────────── + # cat_json = cdata.get("iCategoryJSON", {}) + # cat_title = "/".join(cat_json.get("parentNames", []) + + # [cat_json.get("name", "")]) + # cat_path = f"Каталог/ZaraHome/{cat_title}" + + seen = set() + for n, prod in enumerate(summaries, 1): + + short_url = prod.get("productUrl") + if not short_url or short_url in seen: + continue + seen.add(short_url) + print(f"Products: {n} / {len(summaries)} " + f"https://www.zarahome.com/pl/{short_url}") + + # ── у некоторых prod нет вариантов → смотрим глубже ── + variant_products = [] + if prod.get("detail", {}).get("colors"): + variant_products.append(prod) + elif prod.get("bundleProductSummaries"): + variant_products += prod["bundleProductSummaries"] + else: + variant_products.append(prod) # моно-товар без вариантов + + # ── обрабатываем каждый vprod (вариант или сам товар) ─ + for vprod in variant_products: + det = vprod["detail"] + + url_full = f"https://www.zarahome.com/pl/en/{vprod.get('productUrl','')}" + name = vprod.get("name", "") + article = det["displayReference"] + root_price = int(vprod.get("price", 0)) / 100 + root_wt = vprod.get("weight", "") + + # ── все изображения ──────────────────────────── + raw_xmedia = (det.get("xmedia") or vprod.get("xmedia") or []) + default_idx = det.get("xmediaDefaultSet") + if isinstance(raw_xmedia, list) and raw_xmedia: + media_sets = [raw_xmedia[default_idx]] if isinstance(default_idx, int) else raw_xmedia + elif isinstance(raw_xmedia, dict): + media_sets = [raw_xmedia] + else: + media_sets = [] + + all_imgs = [ + f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"] + ] + all_imgs_s = "\n".join(all_imgs) + + # ── состав / уход / происхождение ─────────────── + comp_block = det.get("compositionDetail") + comp_txt = "" + if comp_block and comp_block.get("parts"): + comp_txt = "\n".join( + extract_components_zarahome(comp_block["parts"]) + ) + care = "\n".join(c["description"] for c in det.get("care", [])) + + trace = "" + if det.get("traceability"): + trace = "\n".join( + f"{v['name']}\n" + "\n".join(v["country"]) + for v in det["traceability"].values() + if isinstance(v, dict) and v.get("country") and v.get("name") + ) + + # ── цвета и размеры ───────────────────────────── + colors_list = det.get("colors") or [] + if not colors_list: # моно-товар без цветов + colors_list = [{ + "id": 0, + "name": "DEFAULT", + "image": {"url": ""}, + "sizes": [{ + # "visibilityValue": "SHOW", + "name": "", + "description": "", + "weight": root_wt, + "price": vprod.get("price", 0) + }] + }] + + serial = 0 + for clr in colors_list: + if clr.get("image") is None and clr["name"] != "DEFAULT": + continue + + clr_code = clr.get("id") + clr_name = clr.get("name", "") + clr_image = "" + if clr.get("image") and clr["image"].get("url"): + clr_image = (f"https://static.zarahome.net/8/photos4" + f"{clr['image']['url']}_3_1_5.jpg") + + # картинки именно этого цвета + media_sets = [loc for loc in media_sets + if loc.get("colorCode") == clr_code] or media_sets + clr_imgs = [ + f"https://static.zarahome.net/8/photos4{loc['path']}/{m['idMedia']}2.jpg" + for loc in media_sets + for m in loc["xmediaItems"][0]["medias"] + ] + clr_imgs_s = "\n".join(clr_imgs) + + for size in clr["sizes"]: + # if size["visibilityValue"] != "SHOW": + # continue + #suffix = "" if serial == 0 else f"-{serial}" Раскомментить если надо добавлять "-1,2,3" к артикуду при повторениях + + serial += 1 + visibility = size.get("visibilityValue", "UNKNOWN") + size_name = size.get("name", "") + size_descr = size.get("description", "") + size_full = f"{size_descr} ({size_name})" if size_descr else size_name + size_weight = size.get("weight") or root_wt + size_price = int(size.get("price") or vprod.get("price", 0)) / 100 + + # ── путь категории из sectionNameEN / familyName / subFamilyName + sec = vprod.get("sectionNameEN") or "" # верхний уровень + fam = vprod.get("familyName") or "" # семья + sub = vprod.get("subFamilyName") or "" # подсемья + + cat_parts = [p for p in (sec, fam, sub) if p] # убираем пустые + cat_path = "Каталог/ZaraHome/" + "/".join(cat_parts) + + sku_val = size.get("sku", "") + partnumber_val = size.get("partnumber", "") + + table.append([ + url_full, + f"{article}", #{suffix}", Раскомментить если надо добавлять "-1,2,3" к артикуду при повторениях + name, + sku_val, # ← SKU + partnumber_val, # ← PartNumber + det.get("longDescription", ""), + clr_image, + clr_name, + size_full, + size_price, + size_weight, + visibility, + all_imgs_s, + clr_imgs_s, + comp_txt, + care, + trace, + cat_path, + USER_BRAND + ]) + + # ── запись CSV ────────────────────────────────────────── + csv_name = category.split("/")[-1] + recorder.record(csv_name, table) + + + def get_extractor(): + with open(abspath("parse_settings.json"), "r", encoding="utf-8") as file: + return Extractor(load(file)) \ No newline at end of file diff --git a/Parsing ZARAHOME/src/extractor автономный для сбора категорий copy.py b/Parsing ZARAHOME/src/extractor автономный для сбора категорий copy.py new file mode 100644 index 0000000..716b7c6 --- /dev/null +++ b/Parsing ZARAHOME/src/extractor автономный для сбора категорий copy.py @@ -0,0 +1,11 @@ +from selenium import webdriver +from selenium.webdriver.chrome.options import Options + +opt = Options() +#opt.add_argument("--headless=new") # можно убрать, чтобы увидеть окно + +driver = webdriver.Chrome(options=opt) # БЕЗ service, БЕЗ путей! +driver.get("https://www.zarahome.com/pl/en") +print("Title:", driver.title) +print("ChromeDriver:", driver.capabilities['chrome']['chromedriverVersion']) +driver.quit() \ No newline at end of file diff --git a/Parsing ZARAHOME/src/extractor автономный для сбора категорий.py b/Parsing ZARAHOME/src/extractor автономный для сбора категорий.py new file mode 100644 index 0000000..970a715 --- /dev/null +++ b/Parsing ZARAHOME/src/extractor автономный для сбора категорий.py @@ -0,0 +1,71 @@ +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.chrome.options import Options +from bs4 import BeautifulSoup +import pandas as pd +from urllib.parse import urljoin + +BASE_URL = "https://www.zarahome.com" +START_URL = f"{BASE_URL}/pl/en/" +TIMEOUT = 30 + +opt = Options() +#opt.add_argument("--headless=new") +opt.add_argument("--window-size=1920,1080") +opt.add_argument("--disable-gpu") +opt.add_argument("--disable-blink-features=AutomationControlled") +opt.add_experimental_option("excludeSwitches", ["enable-automation"]) +opt.add_experimental_option("useAutomationExtension", False) + +driver = webdriver.Chrome(options=opt) +wait = WebDriverWait(driver, TIMEOUT) + +try: + driver.get(START_URL) + + # cookies + try: + wait.until(EC.element_to_be_clickable(( + By.XPATH, "//button[contains(.,'Accept') or contains(.,'Akcept')]")) + ).click() + except Exception: + pass + + # раскрываем бургер (если есть) + try: + wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, + "button[aria-label='Menu'], button[data-testid='menu-button']")) + ).click() + except Exception: + pass + + # ждём пунктов меню + wait.until(EC.presence_of_element_located(( + By.XPATH, "//nav//ul//a[normalize-space(text())!='']"))) + + html = driver.page_source +finally: + driver.quit() + +# ── парсинг +soup = BeautifulSoup(html, "lxml") +links = soup.select("nav ul a[href]") # любой href, не только https +print("Всего найдено ссылок в DOM:", len(links)) + +records = set() +for a in links: + name = a.get_text(strip=True) + href = a["href"] + if not name or href.startswith("javascript"): + continue + full_url = urljoin(BASE_URL, href) # /pl/en/... → https://www.zarahome.com/pl/en/... + records.add((full_url, name)) + +print("После фильтрации уникальных:", len(records)) + +df = pd.DataFrame(sorted(records), columns=["URL", "Category"]) +df.to_excel(r"C:\Users\valis\YandexDisk\Python3\Parsing ZARAHOME\src_2024-09-05categories.xlsx", index=False) +print(f"✔ Собрано {len(df)} ссылок → categories.xlsx") diff --git a/Parsing ZARAHOME/src/extractor автономный для списка товаров.py b/Parsing ZARAHOME/src/extractor автономный для списка товаров.py new file mode 100644 index 0000000..261ff28 --- /dev/null +++ b/Parsing ZARAHOME/src/extractor автономный для списка товаров.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +# zarahome_product_links.py +# — извлекает данные напрямую со страниц товаров Zara Home — +# Формат колонок совпадает с вашим категорийным парсером. + +import json, re, sys, time, pathlib, requests, pandas as pd +from bs4 import BeautifulSoup + +# ── константы ──────────────────────────────────────────────────── +HEADERS = {"User-Agent": "Mozilla/5.0"} +PID_RE = re.compile(r"-l(\d+)(?:[/?]|$)") # productId из URL +REST_API = ("https://www.zarahome.com/itxrest/3/catalog/store/" + "85009924/80290000/productsArray?languageId=-1" + "&productIds={ids}&appId=1") +BRAND = "ZARAHOME" + +# ── helpers ────────────────────────────────────────────────────── +def fetch(url: str, json_flag=False): + """GET-обёртка c timeout и user-agent.""" + r = requests.get(url, headers=HEADERS, timeout=15) + r.raise_for_status() + return r.json() if json_flag else r.text + +def try_json_ld(soup: BeautifulSoup): + """Ищем