no message

parent dfdb4f08
# uk de 的站点 没测过
site_name_secret_dict = {
"us": {'application':'amzn-mbl-cscan-us','username':'amzn-mbl-cscan-us','secret':'5b6874d3a20417591bd5464a25a37bc6','snap_url':'https://match-visualsearch.amazon.com'},
"uk": {'application':'amzn-mbl-cscan-uk','username':'amzn-mbl-cscan-uk','secret':'c1a79f745bbe6a8824ce3178c8b549ad','snap_url':'https://match-visualsearch-uk.amazon.com'},
"de": {'application':'amzn-mbl-cscan-de','username':'amzn-mbl-cscan-de','secret':'9e6d6d6c2c823012c493885a95cc5bf2','snap_url':'https://match-visualsearch-de.amazon.com'},
}
us_devices_list = [
{"clientDevice":"iOS - iPhone 16 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 16","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 15 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 15 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 14 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 14","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 13 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 13","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 12 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 12","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone SE (2022)","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone SE 3rd Gen","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"Android - Pixel 9 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 9","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 8 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 8","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 7 Pro","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Pixel 7a","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Pixel 6 Pro","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Pixel 6a","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Pixel 5a","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - Pixel 5","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - Galaxy S25 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S25","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S24 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S24","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S23 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy S23","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy A55","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy A54","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy Z Fold5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy Z Flip5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy A34","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy A14","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy S22 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy A53","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy S21 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"11"},
{"clientDevice":"Android - Galaxy A71","deviceManufacturer":"Samsung","clientDeviceVersion":"11"},
{"clientDevice":"Android - Moto Edge 60","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Moto Edge 50 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Moto G Power (2024)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto G Stylus 5G (2023)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto Razr 40 Ultra","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto Edge 30 Fusion","deviceManufacturer":"Motorola","clientDeviceVersion":"12"},
{"clientDevice":"Android - Moto G Pure (2023)","deviceManufacturer":"Motorola","clientDeviceVersion":"12"},
{"clientDevice":"Android - Moto One 5G Ace","deviceManufacturer":"Motorola","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus 12","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus 10 Pro","deviceManufacturer":"OnePlus","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus 9 Pro","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus Nord N30","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord 3","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Ace 2","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord CE 3","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Xiaomi 14 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 14","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 12 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi K70","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Redmi K60","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus ROG Phone 8","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus Zenfone 11","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 7","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus Zenfone 10","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 40 SE","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL Stylus 5G","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 30 V 5G","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"Android - Nokia X30 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia G42 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia G22","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Vivo X100 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo X100","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo V30 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Find X7 Ultra","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Oppo Find X6 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Reno 11 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme GT5 Pro","deviceManufacturer":"Realme","clientDeviceVersion":"14"},
{"clientDevice":"Android - Realme 11 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 10 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"12"},
{"clientDevice":"iOS - iPhone 16 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 15 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 15","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 14 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 14 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 13 Mini","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 13 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 12 Mini","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 12 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel Fold","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 8a","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Pixel 7","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Pixel 6","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Pixel 4a (5G)","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - Galaxy S25 Plus","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S24 Plus","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Galaxy S23 Plus","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy A74 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Galaxy Z Fold4","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy Z Flip4","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy A33 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy A23 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy S22","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Galaxy S21","deviceManufacturer":"Samsung","clientDeviceVersion":"11"},
{"clientDevice":"Android - Moto Edge 40 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto G Stylus (2024)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto Razr 40","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto G54 5G","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto Edge 30 Ultra","deviceManufacturer":"Motorola","clientDeviceVersion":"12"},
{"clientDevice":"Android - Moto G34 5G","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Moto E32","deviceManufacturer":"Motorola","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus 12R","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11R","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus 9","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus Nord N200 5G","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus Nord 2T","deviceManufacturer":"OnePlus","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus Ace","deviceManufacturer":"OnePlus","clientDeviceVersion":"12"},
{"clientDevice":"Android - Xiaomi 13 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Xiaomi 12S Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 13","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 12","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi K50 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"12"},
{"clientDevice":"Android - Redmi 12C","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus ROG Phone 6","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - Asus Zenfone 9","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - TCL 405","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 30 SE","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"Android - Nokia X20 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Nokia G50 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Vivo V29 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo S18 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Find X5 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"12"},
{"clientDevice":"Android - Oppo Reno 10 Pro+","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme GT Neo5","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 9 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"12"}
]
uk_devices_list = [
{"clientDevice":"iOS - iPhone 16","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 16 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 15","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 15 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 14 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 14 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 13 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 13 Mini","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone SE (2022)","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPad Air (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad Pro 11-inch (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad 10th Gen","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"Android - Samsung Galaxy S25 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S25","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S24 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S24","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy A56","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A55","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Z Fold5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Z Flip5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 10 Pro XL","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 10 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 9 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 9","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 8 Pro","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 8a","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord N100","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus 12","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord 2 5G","deviceManufacturer":"OnePlus","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus 8 Pro","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus 7t","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - Nokia 2.1","deviceManufacturer":"Nokia","clientDeviceVersion":"11"},
{"clientDevice":"Android - Nokia X30 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia G42 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo A54s 2021","deviceManufacturer":"Oppo","clientDeviceVersion":"11"},
{"clientDevice":"Android - Oppo Find X7 Ultra","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Oppo Find X6 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Reno 11 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo X100 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo V30 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo S18 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei P20","deviceManufacturer":"Huawei","clientDeviceVersion":"10"},
{"clientDevice":"Android - Huawei Mate 20 Lite","deviceManufacturer":"Huawei","clientDeviceVersion":"10"},
{"clientDevice":"Android - Huawei Y6ii Compact","deviceManufacturer":"Huawei","clientDeviceVersion":"10"},
{"clientDevice":"Android - Huawei Ascend G510","deviceManufacturer":"Huawei","clientDeviceVersion":"10"},
{"clientDevice":"Android - Motorola Razr 5G 2nd Gen","deviceManufacturer":"Motorola","clientDeviceVersion":"11"},
{"clientDevice":"Android - Motorola Edge 60","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola G Power (2024)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vodafone V1230","deviceManufacturer":"Vodafone","clientDeviceVersion":"11"},
{"clientDevice":"Android - Vodafone V1210","deviceManufacturer":"Vodafone","clientDeviceVersion":"10"},
{"clientDevice":"Android - Vodafone Smart III","deviceManufacturer":"Vodafone","clientDeviceVersion":"10"},
{"clientDevice":"Android - HTC One Mini LTE 601n","deviceManufacturer":"HTC","clientDeviceVersion":"10"},
{"clientDevice":"Android - Samsung Galaxy S21 Ultra 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"11"},
{"clientDevice":"Android - Samsung Galaxy S9 Plus","deviceManufacturer":"Samsung","clientDeviceVersion":"10"},
{"clientDevice":"Android - Samsung Galaxy Note 8","deviceManufacturer":"Samsung","clientDeviceVersion":"10"},
{"clientDevice":"Android - Samsung Galaxy Express 2","deviceManufacturer":"Samsung","clientDeviceVersion":"10"},
{"clientDevice":"Android - Samsung Galaxy S5","deviceManufacturer":"Samsung","clientDeviceVersion":"10"},
{"clientDevice":"Android - Realme GT5 Pro","deviceManufacturer":"Realme","clientDeviceVersion":"14"},
{"clientDevice":"Android - Realme 11 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme GT Neo5","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"iOS - iPhone XS","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 11 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 12 5G","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 12 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPad Pro 11-inch 2021","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPad Pro 11-inch 2020","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPad Air CDMA A1475","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 3a","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - Google Pixel 4a (5G)","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - Google Pixel 5a","deviceManufacturer":"Google","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus Nord N20","deviceManufacturer":"OnePlus","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus Nord N30","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A54","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A34","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A14","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy S22 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Samsung Galaxy S22","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Samsung Galaxy A53 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Samsung Galaxy A33 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Xiaomi 14 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 14","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi K70","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Redmi K60","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus ROG Phone 8","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 7","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus Zenfone 11","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus Zenfone 10","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 40 SE","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL Stylus 5G","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 30 V 5G","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"Android - Blackberry Key2","deviceManufacturer":"Blackberry","clientDeviceVersion":"10"},
{"clientDevice":"Android - Blackberry Key2 Red Edition","deviceManufacturer":"Blackberry","clientDeviceVersion":"10"},
{"clientDevice":"Android - Blackberry Keyone","deviceManufacturer":"Blackberry","clientDeviceVersion":"10"},
{"clientDevice":"Android - Motorola Razr 40 Ultra","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto G54 5G","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto Edge 40 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"iOS - iPhone 16 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 15 Plus","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 14 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 13 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 12 Mini","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone SE 3rd Gen","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPad Pro 5G 11-inch 2021","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPad Air (2022)","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"Android - Samsung Galaxy S23 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy S23","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Z Fold4","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Samsung Galaxy Z Flip4","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Google Pixel 7 Pro","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 7a","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 6 Pro","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Google Pixel 6a","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus 12R","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11R","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord CE 3","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Reno 10 Pro+","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Find X5 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"12"},
{"clientDevice":"Android - Vivo V29 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 9 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"12"},
{"clientDevice":"Android - Xiaomi 13 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 12","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi K50 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"12"},
{"clientDevice":"Android - Asus Zenfone 9","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - Asus ROG Phone 6","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - TCL 405","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 30 SE","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"Android - Nokia X20 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Nokia G50 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Motorola Moto G Stylus 5G (2023)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto One 5G Ace","deviceManufacturer":"Motorola","clientDeviceVersion":"11"},
{"clientDevice":"Android - Vodafone Smart V10","deviceManufacturer":"Vodafone","clientDeviceVersion":"11"},
{"clientDevice":"Android - HTC U23 Pro","deviceManufacturer":"HTC","clientDeviceVersion":"13"},
{"clientDevice":"Android - HTC Wildfire E5 Plus","deviceManufacturer":"HTC","clientDeviceVersion":"12"},
{"clientDevice":"iOS - iPhone 17 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"19"},
{"clientDevice":"iOS - iPhone 17","deviceManufacturer":"Apple","clientDeviceVersion":"19"},
{"clientDevice":"iOS - iPad Pro 12.9-inch (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad Mini 6th Gen","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"Android - Samsung Galaxy S26 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy A57 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 11 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 13","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Oppo Find X8 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo X110 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 15 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Realme GT6 Pro","deviceManufacturer":"Realme","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 9","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola Edge 70 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Nokia X40 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"14"},
{"clientDevice":"Android - TCL 50 SE","deviceManufacturer":"TCL","clientDeviceVersion":"14"}
]
de_devices_list = [
{"clientDevice":"iOS - iPhone 16 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 16","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPhone 15 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 15","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPhone 14 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 14","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone 13 Pro Max","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 13","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone 12 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone 12","deviceManufacturer":"Apple","clientDeviceVersion":"14"},
{"clientDevice":"iOS - iPhone SE (2022)","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPhone SE 3rd Gen","deviceManufacturer":"Apple","clientDeviceVersion":"16"},
{"clientDevice":"iOS - iPhone Air","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"Android - Samsung Galaxy S26 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S26 Pro","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S26 FE","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S25 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S25","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S24 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy S24 FE","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy S23 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A57 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy A56","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A55","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy A54","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Z Fold5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Z Flip5","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Samsung Galaxy Tab S12 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy Tab S12","deviceManufacturer":"Samsung","clientDeviceVersion":"14"},
{"clientDevice":"Android - Samsung Galaxy Tab S11 Lite","deviceManufacturer":"Samsung","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 9 Pro Fold","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 9 Pro","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 9","deviceManufacturer":"Google","clientDeviceVersion":"14"},
{"clientDevice":"Android - Google Pixel 8 Pro","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 8","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 7 Pro","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Google Pixel 7","deviceManufacturer":"Google","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo X300 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"16"},
{"clientDevice":"Android - Vivo X300","deviceManufacturer":"Vivo","clientDeviceVersion":"16"},
{"clientDevice":"Android - Vivo X200","deviceManufacturer":"Vivo","clientDeviceVersion":"15"},
{"clientDevice":"Android - Vivo V50 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"15"},
{"clientDevice":"Android - Vivo V50","deviceManufacturer":"Vivo","clientDeviceVersion":"15"},
{"clientDevice":"Android - Vivo Y500","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo Y37 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Vivo IQOO 12","deviceManufacturer":"Vivo","clientDeviceVersion":"15"},
{"clientDevice":"Android - Xiaomi 15 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 15","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 14 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 14T Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 14","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 14 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Redmi Note 13 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi Note 12 Pro","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi 14R","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Redmi K70 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"14"},
{"clientDevice":"Android - Redmi K60","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Pura 70 Ultra","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Pura 70 Pro+","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Pura 70 Pro","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Pura 70","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Nova 12 Ultra","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova 12 Pro","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova 12","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova 12 Lite","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova Flip","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Mate XT Ultimate","deviceManufacturer":"Huawei","clientDeviceVersion":"14"},
{"clientDevice":"Android - Huawei Enjoy 70","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Find X8 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Oppo Find X7 Ultra","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Oppo Find X6 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Reno 11 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo Reno 10 Pro+","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo A6 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo A6 GT 5G","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo A6i 5G","deviceManufacturer":"Oppo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo F31","deviceManufacturer":"Oppo","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 13","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 12","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord N30","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord 3","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - OnePlus Nord CE 3","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 13 4G","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 11 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme GT6 Pro","deviceManufacturer":"Realme","clientDeviceVersion":"14"},
{"clientDevice":"Android - Realme GT5 Pro","deviceManufacturer":"Realme","clientDeviceVersion":"14"},
{"clientDevice":"Android - Realme GT Neo5","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme Narzo N61","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme V60","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Edge 70 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola Edge 60 Neo","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola Edge 60","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola Edge 50 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"14"},
{"clientDevice":"Android - Motorola Moto G06 Power","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto G Power (2024)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto G Stylus 5G (2023)","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Honor 500 Pro","deviceManufacturer":"Honor","clientDeviceVersion":"14"},
{"clientDevice":"Android - Honor 500","deviceManufacturer":"Honor","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 9","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 8","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus ROG Phone 7","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus Zenfone 11","deviceManufacturer":"Asus","clientDeviceVersion":"14"},
{"clientDevice":"Android - Asus Zenfone 10","deviceManufacturer":"Asus","clientDeviceVersion":"13"},
{"clientDevice":"Android - ZTE Nubia Air","deviceManufacturer":"ZTE","clientDeviceVersion":"13"},
{"clientDevice":"Android - Ulefone Armor 26 Ultra","deviceManufacturer":"Ulefone","clientDeviceVersion":"13"},
{"clientDevice":"Android - Ulefone Armor 24","deviceManufacturer":"Ulefone","clientDeviceVersion":"13"},
{"clientDevice":"Android - Ulefone Power Armor 18 Ultra","deviceManufacturer":"Ulefone","clientDeviceVersion":"13"},
{"clientDevice":"Android - Ulefone Power Armor 18 T Ultra","deviceManufacturer":"Ulefone","clientDeviceVersion":"13"},
{"clientDevice":"Android - Ulefone Note 17 Pro","deviceManufacturer":"Ulefone","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 50 SE","deviceManufacturer":"TCL","clientDeviceVersion":"14"},
{"clientDevice":"Android - TCL 40 SE","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL Stylus 5G","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - TCL 30 V 5G","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"Android - Tecno Pova Slim","deviceManufacturer":"Tecno","clientDeviceVersion":"13"},
{"clientDevice":"Android - Tecno Megapad Pro","deviceManufacturer":"Tecno","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia G42 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia X30 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia X40 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"14"},
{"clientDevice":"Android - Nokia G50 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - Vodafone Smart V10","deviceManufacturer":"Vodafone","clientDeviceVersion":"13"},
{"clientDevice":"iOS - iPad Pro 12.9-inch (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad Pro 11-inch (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad Air (2024)","deviceManufacturer":"Apple","clientDeviceVersion":"18"},
{"clientDevice":"iOS - iPad Mini 6th Gen","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"iOS - iPad 10th Gen","deviceManufacturer":"Apple","clientDeviceVersion":"17"},
{"clientDevice":"Android - Samsung Galaxy S22 Ultra","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Samsung Galaxy A53 5G","deviceManufacturer":"Samsung","clientDeviceVersion":"12"},
{"clientDevice":"Android - Google Pixel 6 Pro","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Google Pixel 6","deviceManufacturer":"Google","clientDeviceVersion":"12"},
{"clientDevice":"Android - Vivo V30 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo S18 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Xiaomi 13 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Redmi K50 Ultra","deviceManufacturer":"Xiaomi","clientDeviceVersion":"12"},
{"clientDevice":"Android - Oppo Find X5 Pro","deviceManufacturer":"Oppo","clientDeviceVersion":"12"},
{"clientDevice":"Android - OnePlus 12R","deviceManufacturer":"OnePlus","clientDeviceVersion":"14"},
{"clientDevice":"Android - OnePlus 11R","deviceManufacturer":"OnePlus","clientDeviceVersion":"13"},
{"clientDevice":"Android - Realme 9 Pro+","deviceManufacturer":"Realme","clientDeviceVersion":"12"},
{"clientDevice":"Android - Motorola Moto Edge 40 Pro","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto G54 5G","deviceManufacturer":"Motorola","clientDeviceVersion":"13"},
{"clientDevice":"Android - Nokia X20 5G","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - TCL 405","deviceManufacturer":"TCL","clientDeviceVersion":"13"},
{"clientDevice":"Android - Asus Zenfone 9","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - Asus ROG Phone 6","deviceManufacturer":"Asus","clientDeviceVersion":"12"},
{"clientDevice":"Android - Huawei Nova 12i","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova 12s","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Huawei Nova 12 SE","deviceManufacturer":"Huawei","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo V29 Pro","deviceManufacturer":"Vivo","clientDeviceVersion":"13"},
{"clientDevice":"Android - Vivo V40 Lite","deviceManufacturer":"Vivo","clientDeviceVersion":"14"},
{"clientDevice":"Android - Xiaomi Redmi 12C","deviceManufacturer":"Xiaomi","clientDeviceVersion":"13"},
{"clientDevice":"Android - Motorola Moto One 5G Ace","deviceManufacturer":"Motorola","clientDeviceVersion":"11"},
{"clientDevice":"Android - OnePlus Nord N200 5G","deviceManufacturer":"OnePlus","clientDeviceVersion":"11"},
{"clientDevice":"Android - Realme GT Neo5 SE","deviceManufacturer":"Realme","clientDeviceVersion":"13"},
{"clientDevice":"Android - Oppo A54s 2021","deviceManufacturer":"Oppo","clientDeviceVersion":"11"},
{"clientDevice":"Android - Nokia G22","deviceManufacturer":"Nokia","clientDeviceVersion":"12"},
{"clientDevice":"Android - TCL 30 SE","deviceManufacturer":"TCL","clientDeviceVersion":"12"},
{"clientDevice":"iOS - iPhone 17 Pro","deviceManufacturer":"Apple","clientDeviceVersion":"19"},
{"clientDevice":"iOS - iPhone 17","deviceManufacturer":"Apple","clientDeviceVersion":"19"},
{"clientDevice":"iOS - iPad Pro 11-inch 2021","deviceManufacturer":"Apple","clientDeviceVersion":"15"},
{"clientDevice":"iOS - iPad Air (2022)","deviceManufacturer":"Apple","clientDeviceVersion":"16"}
]
# us_cookie_dict ={"i18n-prefs": "USD", "lc-main": "en_US", "session-id": "137-6850115-5627367", "session-id-time": "2082787201l", "session-token": "NDR0kD9QBkk81plbn2yEFeEJ205I0LEzv9G4Q3nG90PVEmpZEtEiL6Ixj3alIu5KBvaiePi9IOHhzSh48qBNQH2yroklDf1+rDTtJ8HNzcfae0ZEL3/szlwFWXRsxH7UwfHip9R66v9ZoO5ni9mrz+4J6QgjTmrzCW7uVjTMthdesVgOk2SVmxyfoLQnmYuScp17v+ayrztH3VFIg/VyhzNBlVbkZDIHg2WB3F+U0JHkiQfiZB1q2uCMWOEIOwRkCGhaRrWHbBgpQtvHnf+Iw2KxVkl2gv1jZga2iNQUhO6cIr2Py5V7evAyuXXhjRaBzIl/STRh58Jr9ctbhdBXnTQsbThexXLn", "skin": "noskin", "ubid-main": "133-5836273-3821350"}
# uk_cookie_dict ={"i18n-prefs": "HKD", "lc-acbuk": "en_GB", "session-id": "521-9387816-0582061", "session-id-time": "2082787201l", "session-token": "\"ANvQ1SZ9VE6Y9cGcEdwhYcEpI1Jql7bOXZ7Q+qdBbb41IuuIFXvUzDSoaXOzPlcUTa3CIMoLIIzD2QOAWnN2h1E/c/iXEzpM8qd4LqR9otFV6PQecFkZKnC/i5v3QIguYgLt3KB9halOcaKi+KXcpG1b5jjYSicsMknbJMQVgfkiqMDXOLcxIns2cHs1xpXgf/DrjOHNpIB6Q24VKaqLTuKbWd8biHv86NGyoBNIs1kkjJxdwZhvWtQC/rHqoiz0e853W2lkrUrdr6Ko3dSIYojEBEgVuglCENJWLmkQzqEMxcIzNgcrpf4ZSlRHhMpmi2D14A6rwrwdo/JMozJSol+Wx3dL7j/AEGiXa1IWwrA=\"", "ubid-acbuk": "259-9451176-7460703"}
# de_cookie_dict ={"i18n-prefs": "HKD", "lc-acbde": "de_DE", "session-id": "258-7262769-1488647", "session-id-time": "2082787201l", "session-token": "RxPtESM/cUQ4JAxsgMz8crm9EMbFhHLK4vPgZzTj2w23v5yWkzjXZsVVsErU5Oi8qzT3Le8nxU1zxeDEWuAg2IL+5fb2VwhE9UOQpLMmnOBWaukpW0CKFMOTvJU6Fu7+IZhWpJWt+ypu5b0KEYVi7CyTsHKh38q8N2m7tGBwb94NyT4tLHyE69XovznI5HV7y19J0aJrDyEYBfk00m6/SwxxOhRbkOXWVIagnGK4N1uQ27n9827rd7o1TpHQc8sWnn1bDAvYbCtGOaUYUHJ8HxnZPsTjKZ2b8OgzIKE9nlvpoAAQOArarZlZxneJTfUY++ucym9Te+RUvPp6SrhpPJyP7W425mA9", "ubid-acbde": "257-6077242-9988057"}
import hashlib
import time
import uuid
from typing import Optional, List
from loguru import logger
import requests
from requests.exceptions import RequestException, ConnectionError, Timeout
# 配置日志
logger.add("amazon_search.log", rotation="10 MB", level="INFO")
# 全局变量(clientDeviceId 固定,cookie 失效时更新)
GLOBAL_CLIENT_DEVICE_ID = str(uuid.uuid4())
logger.info(f"初始化全局 clientDeviceId: {GLOBAL_CLIENT_DEVICE_ID}")
# 常量配置
AMAZON_STYLE_SNAP_URL = "https://match-visualsearch.amazon.com/style-snap/2.0"
AMAZON_SEARCH_BASE_URL = "https://www.amazon.com/s?rh=p_78:{bbx_asin_list}&rank=asin-scores-asc-rank&searchMethod=CameraSearch"
SECRET = "5b6874d3a20417591bd5464a25a37bc6"
APPLICATION = "amzn-mbl-cscan-us"
USERNAME = "amzn-mbl-cscan-us"
RETRY_TIMES = 5 # 重试次数
RETRY_DELAY = 1 # 重试间隔(秒)
def get_amazon_search_url(image_path: str, cookies: dict) -> Optional[str]:
"""
调用亚马逊以图搜物接口,获取搜索结果并生成最终搜索URL
:param image_path: 图片本地路径
:param cookies: 亚马逊请求所需的cookies
:return: 拼接后的搜索URL,失败时返回None
"""
for retry in range(RETRY_TIMES):
try:
logger.info(f"开始第 {retry + 1}/{RETRY_TIMES} 次请求")
# 1. 准备动态参数
session_id = cookies.get("session-id", "")
if not session_id:
logger.error("Cookies中缺少session-id")
return None
client_id = str(uuid.uuid4()) # 每次请求生成新的clientId
ts = str(int(time.time()))
# 2. 生成authtoken
combined = SECRET + USERNAME + APPLICATION + ts
authtoken = hashlib.sha512(combined.encode("utf-8")).hexdigest()
logger.debug(f"生成authtoken: {authtoken[:10]}...") # 只打印前10位避免过长
# 3. 构建query_metadata
query_metadata = (
'{"amznSessionId":"%s","clientVersion":"30.20.2.100","cardsVersion":"1.0",'
'"clientMessageVersion":"1.0","amznDirectedCustomerId":"","clientDeviceId":"%s",'
'"clientDevice":"Android - Pixel 2","deviceManufacturer":"Google","clientDeviceVersion":"10",'
'"clientId":"%s","orientation":"-1","sourceType":"Photo","ingressSource":"ctp","uiMode":"stylesnap"}'
% (session_id, GLOBAL_CLIENT_DEVICE_ID, client_id)
)
# logger.debug(f"构建query_metadata: {query_metadata[:50]}...") # 只打印前50位
# 4. 读取图片文件
try:
with open(image_path, "rb") as f:
image_data = f.read()
logger.info(f"成功读取图片: {image_path} (大小: {len(image_data)} bytes)")
except Exception as e:
logger.error(f"读取图片失败: {str(e)}", exc_info=True)
return None # 图片错误无需重试
# 5. 构建请求头
headers = {
"x-amz-access-token": "",
"x-amz-lens-session-auth-token": cookies.get("session-token", ""),
"x-amz-lens-session-id": session_id,
"x-amz-lens-ubid": cookies.get("ubid-main", ""),
"accept-encoding": "gzip",
"user-agent": "okhttp/4.9.1"
}
# 6. 构建表单数据
files = [
("application", (None, APPLICATION, "multipart/form-data; charset=utf-8")),
("query_metadata", (None, query_metadata, "multipart/form-data; charset=utf-8")),
("authtoken", (None, authtoken, "multipart/form-data; charset=utf-8")),
("lang", (None, "en_US", "multipart/form-data; charset=utf-8")),
("username", (None, USERNAME, "multipart/form-data; charset=utf-8")),
("ts", (None, ts, "multipart/form-data; charset=utf-8")),
("file", ("", image_data, "image/jpeg"))
]
# 7. 发送请求
logger.info("发送POST请求到亚马逊以图搜物接口")
response = requests.post(
url=AMAZON_STYLE_SNAP_URL,
headers=headers,
files=files,
cookies=cookies,
timeout=10 # 10秒超时
)
response.raise_for_status() # 抛出HTTP错误状态码
logger.info(f"请求成功,状态码: {response.status_code}")
# 8. 解析响应
try:
response_json = response.json()
# logger.debug(f"响应数据: {str(response_json)[:100]}...") # 打印前100字符
except ValueError:
logger.error("响应不是有效的JSON格式", exc_info=True)
if retry < RETRY_TIMES - 1:
logger.info(f"等待 {RETRY_DELAY} 秒后重试...")
time.sleep(RETRY_DELAY)
continue
return None
# 9. 提取bbxAsinList
try:
search_result = response_json.get("style-snap", {}).get("searchResult", [])
if not search_result:
logger.warning("searchResult列表为空")
return None
first_result = search_result[0]
bbx_asin_list = first_result.get("bbxAsinList", [])
if not bbx_asin_list:
logger.warning("bbxAsinList列表为空")
return None
logger.info(f"成功提取bbxAsinList,共 {len(bbx_asin_list)} 个元素,注意 实际有些不可用 打开网页数据少几个为正常现象")
joined_asin = "|".join(bbx_asin_list)
final_url = AMAZON_SEARCH_BASE_URL.format(bbx_asin_list=joined_asin)
logger.success(f"生成最终搜索URL: {final_url}")
return final_url
except (IndexError, KeyError) as e:
logger.error(f"解析响应结构失败: {str(e)}", exc_info=True)
if retry < RETRY_TIMES - 1:
logger.info(f"等待 {RETRY_DELAY} 秒后重试...")
time.sleep(RETRY_DELAY)
continue
return None
except (ConnectionError, Timeout) as e:
logger.error(f"网络错误: {str(e)}", exc_info=True)
except RequestException as e:
# 处理HTTP错误(如401/403可能是cookie过期)
status_code = getattr(e.response, "status_code", None)
logger.error(f"请求异常 (状态码: {status_code}): {str(e)}", exc_info=True)
# 401/403 通常是认证失效,直接终止重试(需要更新cookie)
if status_code in (401, 403):
logger.warning("检测到认证失效,终止重试")
return None
except Exception as e:
logger.error(f"未知错误: {str(e)}", exc_info=True)
# 重试前等待
if retry < RETRY_TIMES - 1:
logger.info(f"等待 {RETRY_DELAY} 秒后重试...")
time.sleep(RETRY_DELAY)
logger.error(f"经过 {RETRY_TIMES} 次重试后仍失败")
return None
if __name__ == "__main__":
sample_cookies = {"i18n-prefs": "USD", "lc-main": "en_US", "session-id": "131-0347800-4175077", "session-id-time": "2082787201l", "session-token": "Jo+AthxsQrcFH8qeii+sHhoo7puFd/cpJUEsjnWXtCLhr8ycF9TQSAv9zuyoAvFjfmXZuACFNa/D+i5et63EafMMPDK/825m8TUtNtlO88KmmEsm94fiyoPL0UakTyZsUBv/CzndcKB7h0K3NkbeFws9gZSdwYRGJFVeX+pPQ9ceN0WkE+XLwCt0plIIxG3BC+VtdFJWxPKxH+R5dlnbtxPso2S5zlrOf1FTEdGNNhNZvVq25XeydshrSp7AKG6VUOicnipgfAY0Qle3Y4bw72N1IqY9i3rXVZlkrkGePamBxew+Vel7U8ccVsEIT/vtOtLHPfsTljTgltlJU0bzk0YeoJ1LwI9S", "skin": "noskin", "ubid-main": "134-9889499-1876667"}
# 调用函数
result_url = get_amazon_search_url("test_image/amazon3.png", sample_cookies)
if result_url:
logger.success(f"最终搜索URL: {result_url}")
else:
logger.error("未能生成搜索URL")
\ No newline at end of file
import hashlib import hashlib
import os
import time import time
import uuid import uuid
import random import random
...@@ -18,11 +19,18 @@ from amazon_configs import ( ...@@ -18,11 +19,18 @@ from amazon_configs import (
uk_cookie_dict, uk_cookie_dict,
de_cookie_dict de_cookie_dict
) )
# 日志目录配置
# LOG_DIR = "log" # 日志文件夹名称
# 关键新增:判断日志目录是否存在,不存在则创建
# if not os.path.exists(LOG_DIR):
# os.makedirs(LOG_DIR, exist_ok=True) # exist_ok=True 避免目录已存在时报错
# 配置日志 # 配置日志
# logger.add("amazon_search_optimized.log", rotation="10 MB", level="INFO") # logger.add("log/amazon_search_optimized.log", rotation="10 MB", level="INFO", encoding="utf-8")
# log_file = os.path.join(LOG_DIR, "amazon_search_optimized.log")
# logger.add(log_file,rotation="10 MB", level="INFO",encoding="utf-8")
# 站点配置映射(关联设备列表和Cookie) # 站点配置映射(关联设备列表和Cookie) uk 和de 未测试准确性
SITE_CONFIG_MAPPER = { SITE_CONFIG_MAPPER = {
"us": { "us": {
"devices": us_devices_list, "devices": us_devices_list,
...@@ -41,9 +49,10 @@ SITE_CONFIG_MAPPER = { ...@@ -41,9 +49,10 @@ SITE_CONFIG_MAPPER = {
# asin 网页端打开 url # asin 网页端打开 url
AMAZON_SEARCH_BASE_URL = "https://www.amazon.com/s?rh=p_78:{bbx_asin_list}&rank=asin-scores-asc-rank&searchMethod=CameraSearch" AMAZON_SEARCH_BASE_URL = "https://www.amazon.com/s?rh=p_78:{bbx_asin_list}&rank=asin-scores-asc-rank&searchMethod=CameraSearch"
# 重试策略配置 # 重试策略配置(全局重试次数,包含解析失败)
RETRY_TIMES = 5 GLOBAL_RETRY_TIMES = 5 # 整体流程重试次数(含Cookie更新)
RETRY_DELAY = 1 STEP_RETRY_TIMES = 5 # 单步请求重试次数
RETRY_DELAY = 1 # 重试延迟(秒)
def get_image_size(image_path: str) -> Optional[Dict[str, int]]: def get_image_size(image_path: str) -> Optional[Dict[str, int]]:
...@@ -62,6 +71,9 @@ def get_image_size(image_path: str) -> Optional[Dict[str, int]]: ...@@ -62,6 +71,9 @@ def get_image_size(image_path: str) -> Optional[Dict[str, int]]:
class AmazonImageSearch: class AmazonImageSearch:
def __init__(self, site_name: str): def __init__(self, site_name: str):
'''
:param site_name: 站点名 如 uk us de
'''
# 验证站点合法性 # 验证站点合法性
if site_name not in site_name_secret_dict: if site_name not in site_name_secret_dict:
raise ValueError(f"不支持的站点: {site_name},支持站点:{list(site_name_secret_dict.keys())}") raise ValueError(f"不支持的站点: {site_name},支持站点:{list(site_name_secret_dict.keys())}")
...@@ -69,16 +81,12 @@ class AmazonImageSearch: ...@@ -69,16 +81,12 @@ class AmazonImageSearch:
raise ValueError(f"站点 {site_name} 缺少设备或Cookie配置") raise ValueError(f"站点 {site_name} 缺少设备或Cookie配置")
self.site_name = site_name self.site_name = site_name
# 加载站点基础配置(secret等)
self.site_config = site_name_secret_dict[site_name] self.site_config = site_name_secret_dict[site_name]
# 加载站点设备列表和Cookie
self.site_specific = SITE_CONFIG_MAPPER[site_name] self.site_specific = SITE_CONFIG_MAPPER[site_name]
self.cookies = self.site_specific["cookies"]
self.session_id = self.cookies.get("session-id",'')
# 从站点设备列表随机选择一个设备(用于query_metadata) # 初始化Cookie和设备信息
self.device_info = self._get_random_device() self._update_cookie() # 初始加载Cookie
# 生成客户端设备ID self._update_device() # 初始加载设备
self.client_device_id = str(uuid.uuid4()) self.client_device_id = str(uuid.uuid4())
logger.info( logger.info(
...@@ -87,7 +95,27 @@ class AmazonImageSearch: ...@@ -87,7 +95,27 @@ class AmazonImageSearch:
f"clientDeviceId: {self.client_device_id}" f"clientDeviceId: {self.client_device_id}"
) )
# 构建请求头 # 构建请求头(依赖Cookie,初始化时生成)
self._update_headers()
self.snap_url = f"{self.site_config['snap_url']}/style-snap/2.0"
def _update_cookie(self) -> None:
"""更新Cookie(当前固定返回站点对应Cookie,后续可扩展为从数据库读取)"""
self.cookies = self.site_specific["cookies"].copy() # 复制一份避免修改原配置
self.session_id = self.cookies.get("session-id", "")
logger.info(f"站点 {self.site_name} Cookie已更新(session-id: {self.session_id[:20]}...)")
def _update_device(self) -> None:
"""更新随机设备信息"""
devices = self.site_specific["devices"]
if not devices:
raise ValueError(f"站点 {self.site_name} 的设备列表为空")
self.device_info = random.choice(devices)
logger.debug(f"设备已更新: {self.device_info.get('clientDevice')}")
def _update_headers(self) -> None:
"""更新请求头(依赖Cookie,Cookie变更后需重新生成)"""
self.headers = { self.headers = {
"x-amz-access-token": "", "x-amz-access-token": "",
"x-amz-lens-session-auth-token": self.cookies.get("session-token", ""), "x-amz-lens-session-auth-token": self.cookies.get("session-token", ""),
...@@ -97,15 +125,6 @@ class AmazonImageSearch: ...@@ -97,15 +125,6 @@ class AmazonImageSearch:
"user-agent": "okhttp/4.9.1", "user-agent": "okhttp/4.9.1",
} }
self.snap_url = f"{self.site_config['snap_url']}/style-snap/2.0"
def _get_random_device(self) -> Dict[str, str]:
"""从站点设备列表中随机选择一个设备"""
devices = self.site_specific["devices"]
if not devices:
raise ValueError(f"站点 {self.site_name} 的设备列表为空")
return random.choice(devices)
def _generate_auth_params(self) -> Dict[str, str]: def _generate_auth_params(self) -> Dict[str, str]:
"""生成认证所需的 authtoken 和 ts""" """生成认证所需的 authtoken 和 ts"""
ts = str(int(time.time())) ts = str(int(time.time()))
...@@ -137,8 +156,16 @@ class AmazonImageSearch: ...@@ -137,8 +156,16 @@ class AmazonImageSearch:
return json.dumps(base_params) return json.dumps(base_params)
def _parse_response(self, response_json: Dict[str, Any]) -> Optional[Dict[str, Any]]: def _parse_response(self, response_json: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""从API响应中解析ASIN列表并构建结果""" """从API响应中解析ASIN列表并构建结果,缺失关键字段视为解析失败"""
try: try:
# 严格检查必须存在的字段
if "style-snap" not in response_json:
raise KeyError("响应缺少 'style-snap' 字段")
if "searchResult" not in response_json["style-snap"]:
raise KeyError("响应缺少 'style-snap.searchResult' 字段")
if not response_json["style-snap"]["searchResult"]:
raise IndexError("'searchResult' 列表为空")
search_result = response_json["style-snap"]["searchResult"][0] search_result = response_json["style-snap"]["searchResult"][0]
bbx_asin_list = search_result.get("bbxAsinList", []) bbx_asin_list = search_result.get("bbxAsinList", [])
...@@ -155,31 +182,30 @@ class AmazonImageSearch: ...@@ -155,31 +182,30 @@ class AmazonImageSearch:
"search_url": AMAZON_SEARCH_BASE_URL.format(bbx_asin_list=joined_asins), "search_url": AMAZON_SEARCH_BASE_URL.format(bbx_asin_list=joined_asins),
} }
except (KeyError, IndexError, TypeError) as e: except (KeyError, IndexError, TypeError) as e:
logger.error(f"解析响应失败: {e}. 响应内容: {response_json}") logger.error(f"解析响应失败: {e}. 响应内容: {json.dumps(response_json, ensure_ascii=False)}...")
return None return None # 返回None表示解析失败,触发重试
def _perform_request(self, **kwargs) -> Dict[str, Any]: def _perform_request(self, **kwargs) -> Dict[str, Any]:
"""统一的请求发送方法,包含重试逻辑""" """单步请求的重试逻辑(不更新Cookie,仅处理网络错误)"""
for attempt in range(RETRY_TIMES): for attempt in range(STEP_RETRY_TIMES):
try: try:
response = requests.post(**kwargs, timeout=10) response = requests.post(**kwargs, timeout=10)
response.raise_for_status() # 对非2xx响应抛出HTTPError response.raise_for_status() # 对非2xx响应抛出HTTPError
return response.json() return response.json()
except JSONDecodeError: except JSONDecodeError:
logger.error(f"请求失败 (第 {attempt + 1}/{RETRY_TIMES} 次): 响应不是有效的JSON格式。") logger.error(f"请求失败 (第 {attempt + 1}/{STEP_RETRY_TIMES} 次): 响应不是有效的JSON格式")
except RequestException as e: except RequestException as e:
logger.error(f"请求失败 (第 {attempt + 1}/{RETRY_TIMES} 次): {e}") logger.error(f"请求失败 (第 {attempt + 1}/{STEP_RETRY_TIMES} 次): {e}")
if attempt < RETRY_TIMES - 1: if attempt < STEP_RETRY_TIMES - 1:
logger.warning(f"将在 {RETRY_DELAY} 秒后重试...") logger.warning(f"将在 {RETRY_DELAY} 秒后重试...")
time.sleep(RETRY_DELAY) time.sleep(RETRY_DELAY)
raise RequestException(f"API请求在 {RETRY_TIMES} 次尝试后最终失败。") raise RequestException(f"单步API请求在 {STEP_RETRY_TIMES} 次尝试后最终失败")
def _default_search(self, image_path: str) -> Dict[str, Any]: def _default_search(self, image_path: str) -> Dict[str, Any]:
"""执行默认的图片识别请求(第一步)""" """执行默认的图片识别请求(第一步)"""
logger.info(f"开始默认识别 (站点: {self.site_name}, 图片: {image_path}),站点链接:{self.snap_url}") logger.info(f"开始默认识别 (站点: {self.site_name}, 图片: {image_path}), 站点链接:{self.snap_url}")
try: try:
with open(image_path, "rb") as f: with open(image_path, "rb") as f:
...@@ -189,18 +215,18 @@ class AmazonImageSearch: ...@@ -189,18 +215,18 @@ class AmazonImageSearch:
raise raise
auth_params = self._generate_auth_params() auth_params = self._generate_auth_params()
query_metadata = self._build_query_metadata({"orientation": "-1"}) # 默认图片搜索 额外传 orientation query_metadata = self._build_query_metadata({"orientation": "-1"})
files = { files = {
"application": (None, self.site_config['application']), "application": (None, self.site_config['application']),
"query_metadata": (None, query_metadata), "query_metadata": (None, query_metadata),
"authtoken": (None, auth_params['authtoken']), "authtoken": (None, auth_params['authtoken']),
# "authtoken": (None, ''), # 为空失请求失败 测试重试功能
"lang": (None, "en_US"), "lang": (None, "en_US"),
"username": (None, self.site_config['username']), "username": (None, self.site_config['username']),
"ts": (None, auth_params['ts']), "ts": (None, auth_params['ts']),
"file": ("image.jpg", image_data, "image/jpeg"), "file": ("image.jpg", image_data, "image/jpeg"),
} }
return self._perform_request(url=self.snap_url, files=files, headers=self.headers) return self._perform_request(url=self.snap_url, files=files, headers=self.headers)
def _full_image_search(self, query_id: str, image_path: str) -> Dict[str, Any]: def _full_image_search(self, query_id: str, image_path: str) -> Dict[str, Any]:
...@@ -209,7 +235,7 @@ class AmazonImageSearch: ...@@ -209,7 +235,7 @@ class AmazonImageSearch:
image_size = get_image_size(image_path) image_size = get_image_size(image_path)
if not image_size: if not image_size:
raise ValueError("无法获取图片尺寸,无法进行全图搜索") raise ValueError("无法获取图片尺寸,无法进行全图搜索")
# 生成随机裁剪框 # 生成随机裁剪框
offset = random.randint(0, 2) offset = random.randint(0, 2)
...@@ -242,54 +268,80 @@ class AmazonImageSearch: ...@@ -242,54 +268,80 @@ class AmazonImageSearch:
def search(self, image_path: str, search_mode: str = "default") -> Dict[str, Any]: def search(self, image_path: str, search_mode: str = "default") -> Dict[str, Any]:
""" """
执行图片搜索 执行图片搜索(包含全局重试逻辑,解析失败时更新Cookie重试)
:param image_path: 本地图片文件路径 :param image_path: 本地图片文件路径
:param search_mode: 搜索模式 ('default' 或 'full_image') :param search_mode: 搜索模式 ('default' 或 'full_image')
:return: 包含搜索结果的字典 :return: 包含搜索结果的字典
""" """
# 默认的返回值字典
base_result = { base_result = {
"is_web": 0, "is_app": 0, "asin_list_web": "", "asin_list_app": "", "is_web": 0, "is_app": 0, "asin_list_web": "", "asin_list_app": "",
"asin_list_join": "", "site_name": self.site_name, "asin_list_join": "", "site_name": self.site_name,
"search_url": None, "mode": search_mode "search_url": None, "mode": search_mode,
"retry_count": 0 # 记录重试次数
} }
# 全局重试逻辑(包含Cookie更新)
for global_attempt in range(GLOBAL_RETRY_TIMES):
try:
# 检查Cookie有效性(每次重试前确认)
if not self.session_id: if not self.session_id:
logger.error("Cookies中缺少'session-id',无法继续。") logger.warning("Cookie中缺少'session-id',尝试更新Cookie...")
return base_result self._update_cookie()
self._update_headers() # 同步更新请求头
try: # 步骤1: 执行默认搜索(全图模式依赖此步骤的query_id)
# 步骤 1: 执行默认搜索(全图模式需依赖此步骤的query_id) default_response = self._default_search(image_path)
default_response = self._default_search(image_path) # 得到首次以图搜物响应
# 处理默认模式结果 # 处理默认模式
if search_mode == "default": if search_mode == "default":
parsed_result = self._parse_response(default_response) parsed_result = self._parse_response(default_response)
if parsed_result: if parsed_result: # 解析成功才返回
base_result.update(parsed_result) # 更新返回值 base_result.update(parsed_result)
base_result["asin_list_join"] = parsed_result["asin_list_app"] base_result["asin_list_join"] = parsed_result["asin_list_app"]
base_result["retry_count"] = global_attempt
return base_result return base_result
else:
# 解析失败,准备重试
raise ValueError("默认模式响应解析失败,触发重试")
# 处理全图模式结果 # 处理全图模式
elif search_mode == "full_image": elif search_mode == "full_image":
query_id = default_response.get("queryId") query_id = default_response.get("queryId")
if not query_id: if not query_id:
logger.error("默认识别未返回 queryId,无法进行全图搜索。") raise ValueError("默认识别未返回queryId,无法进行全图搜索")
return base_result
full_image_response = self._full_image_search(query_id, image_path) # 带上queryId 第二次请求 获取全图识别结果 full_image_response = self._full_image_search(query_id, image_path)
parsed_result = self._parse_response(full_image_response) parsed_result = self._parse_response(full_image_response)
if parsed_result: if parsed_result: # 解析成功才返回
base_result.update(parsed_result) base_result.update(parsed_result)
base_result["asin_list_join"] = parsed_result["asin_list_app"] base_result["asin_list_join"] = parsed_result["asin_list_app"]
base_result["retry_count"] = global_attempt
return base_result return base_result
else:
# 解析失败,准备重试
raise ValueError("全图模式响应解析失败,触发重试")
else: else:
logger.error(f"不支持的搜索模式: {search_mode}") logger.error(f"不支持的搜索模式: {search_mode}")
return base_result return base_result
except Exception as e: except Exception as e:
logger.error(f"处理 '{search_mode}' 模式搜索时发生异常: {e}") logger.error(f"第 {global_attempt + 1}/{GLOBAL_RETRY_TIMES} 次尝试失败: {e}")
# 最后一次重试失败则返回基础结果
if global_attempt == GLOBAL_RETRY_TIMES - 1:
base_result["error"] = str(e)
return base_result
# 非最后一次重试:更新Cookie和设备,延迟后重试
logger.info("准备更新Cookie和设备信息后重试...")
self._update_cookie() # 更新Cookie(当前固定站点Cookie,后续可从数据库读取)
self._update_device() # 更新设备信息
self._update_headers() # 同步更新请求头
self.client_device_id = str(uuid.uuid4()) # 更新客户端ID
logger.info(f"重试准备完成(下次是第 {global_attempt + 2} 次尝试)")
time.sleep(RETRY_DELAY)
return base_result return base_result
...@@ -298,20 +350,22 @@ if __name__ == "__main__": ...@@ -298,20 +350,22 @@ if __name__ == "__main__":
image_file_path = "temp_img/B0BYNB2J6W.jpg" image_file_path = "temp_img/B0BYNB2J6W.jpg"
try: try:
# 测试不同站点(如"us"、"uk"、"de") # 测试不同站点
for site in ["us", "uk", "de"]: for site in ["us","uk","de"]:
logger.info(f"\n{'=' * 20} 测试站点: {site} {'=' * 20}") logger.info(f"\n{'=' * 40}")
logger.info(f"开始测试站点: {site}")
logger.info(f"{'=' * 40}")
client = AmazonImageSearch(site_name=site) client = AmazonImageSearch(site_name=site)
# 测试默认识别模式 # 测试默认识别模式
logger.info("\n--- 默认识别模式 ---") logger.info("\n--- 测试默认识别模式 ---")
default_result = client.search(image_file_path, search_mode="default") default_result = client.search(image_file_path, search_mode="default")
logger.info(f"结果: {default_result}") logger.info(f"默认模式结果: {json.dumps(default_result, ensure_ascii=False, indent=2)}")
# 测试全图识别模式 # # 测试全图识别模式
logger.info("\n--- 全图识别模式 ---") logger.info("\n--- 测试全图识别模式 ---")
full_image_result = client.search(image_file_path, search_mode="full_image") full_image_result = client.search(image_file_path, search_mode="full_image")
logger.info(f"结果: {full_image_result}") logger.info(f"全图模式结果: {json.dumps(full_image_result, ensure_ascii=False, indent=2)}")
except ValueError as e: except ValueError as e:
logger.error(f"初始化失败: {e}") logger.error(f"初始化失败: {e}")
......
...@@ -2,209 +2,267 @@ import os ...@@ -2,209 +2,267 @@ import os
import time import time
import threading import threading
import queue import queue
import csv import random
import json
from datetime import datetime from datetime import datetime
from typing import List, Dict, Tuple from typing import List, Dict
import app_amazon_image_recognition as amazon_recog
from loguru import logger from loguru import logger
import pandas as pd
from app_img_search_api_new import AmazonImageSearch # 导入客户端类
from amazon_configs import (
site_name_secret_dict,
us_devices_list,
uk_devices_list,
de_devices_list
)
# 日志目录配置
LOG_DIR = "log" # 日志文件夹名称
# 判断日志目录是否存在,不存在则创建
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR, exist_ok=True) # exist_ok=True 避免目录已存在时报错
# 测试配置 # 测试配置
TEST_FOLDER = "temp_img" # 图片文件夹路径 TEST_FOLDER = "temp_img" # 图片文件夹路径
REQUESTS_PER_IMAGE = 1 # 每张图片请求次数 REQUESTS_PER_IMAGE = 1 # 每张图片每个站点的请求次数(每种模式各执行一次)
THREAD_COUNT = 10 # 线程数量 THREAD_COUNT = 30 # 线程数量
RESULT_CSV = "test_results.csv" # 结果保存文件 RESULT_EXCEL = "multi_mode_test_results3.xlsx" # 结果保存文件
ALL_SITES = ["us", "uk", "de"] # 要测试的三个站点
# 线程安全的队列用于分发任务 ALL_MODES = ["default", "full_image"] # 两种搜索模式
# 站点设备列表映射
SITE_DEVICES = {
"us": us_devices_list,
"uk": uk_devices_list,
"de": de_devices_list
}
# 线程安全组件
task_queue = queue.Queue() task_queue = queue.Queue()
# 结果存储(线程安全)
result_lock = threading.Lock() result_lock = threading.Lock()
test_results = [] test_results = []
def worker(cookies: dict): def worker():
"""线程工作函数,处理队列中的任务""" """线程工作函数:先执行默认模式,再执行全图模式,记录两种模式结果"""
thread_name = threading.current_thread().name # 获取线程名称(如Worker-1) thread_id = threading.current_thread().ident
thread_name = threading.current_thread().name
while not task_queue.empty(): while not task_queue.empty():
try: try:
# # 从队列获取任务(图片路径+当前请求序号),非阻塞模式 # 从队列获取任务:图片路径、请求序号、站点
image_path, request_idx = task_queue.get(block=False) image_path, request_idx, site_name = task_queue.get(block=False)
image_name = os.path.basename(image_path) image_name = os.path.basename(image_path)
logger.info(
f"[{thread_name}] 开始处理 {image_name} 第 {request_idx} 次请求 "
f"(站点:{site_name},两种模式)"
)
# 初始化客户端(同一客户端实例,确保设备信息一致)
client = AmazonImageSearch(site_name=site_name)
device_info = client.device_info # 获取设备信息(两种模式共用)
device_str = (
f"设备: {device_info.get('clientDevice')}, "
f"厂商: {device_info.get('deviceManufacturer')}, "
f"系统版本: {device_info.get('clientDeviceVersion')}"
)
logger.debug(f"[{thread_name}] {device_str}")
# 依次执行两种模式
for mode in ALL_MODES:
try:
# 记录单次模式开始时间
mode_start = time.time()
start_time = time.time() # 执行对应模式的搜索
start_datetime = datetime.now() result_data = client.search(
image_path=image_path,
# 打印开始请求的日志(关键:展示线程、图片、序号) search_mode=mode
logger.info(f"[{thread_name}] 开始处理 {image_name} 第 {request_idx} 次请求") )
# 执行请求 传入cookies.copy()避免多线程共享同一字典导致的修改冲突
result_url = amazon_recog.get_amazon_search_url(image_path, cookies.copy())
# 计算耗时 # 计算单次模式耗时
end_time = time.time() duration = round(time.time() - mode_start, 4)
duration = end_time - start_time save_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 标记请求是否成功(1=成功,0=失败)
success = 1 if result_url else 0
# 记录结果 # 锁定并保存结果(保持原有数据格式,新增mode字段)
with result_lock: with result_lock:
test_results.append({ test_results.append({
"thread_name": thread_name, # 记录线程名 "image": image_name,
"image": image_name, # 图片文件名 "request_index": request_idx, # 同一请求序号关联两种模式
"request_index": request_idx, # 第几次请求(1到1000) "mode": mode, # 新增:标记当前模式
"start_time": start_datetime.strftime("%Y-%m-%d %H:%M:%S.%f"), # 开始时间 "duration": duration,
"duration": round(duration, 4), # 耗时 保留4位小数) "success": result_data.get("is_app", 0),
"success": success, # 是否成功 "result_url": result_data.get("search_url", "None"),
"result_url": result_url if success else "None", # 成功时的URL,失败为None "thread_id": thread_id,
"thread_id": threading.current_thread().ident # 处理线程ID "is_web": result_data.get("is_web", 0),
"is_app": result_data.get("is_app", 0),
"asin_list_web": result_data.get("asin_list_web", ""),
"asin_list_app": result_data.get("asin_list_app", ""),
"asin_list_join": result_data.get("asin_list_join", ""),
"site_name": site_name,
"device_info": json.dumps(device_info, ensure_ascii=False),
# "device_summary": f"{device_info.get('clientDevice')} ({device_info.get('clientDeviceVersion')})",
"save_time": save_time
}) })
logger.info(f"[{thread_name}] {mode}模式完成(耗时{duration}秒)")
# 每完成100次请求打印进度 except Exception as e:
if request_idx % 100 == 0: logger.error(f"[{thread_name}] {mode}模式处理出错: {str(e)}")
logger.info(f"图片 {os.path.basename(image_path)} 完成第 {request_idx} 次请求,耗时 {duration:.2f}s") # 记录模式失败结果
with result_lock:
test_results.append({
"image": image_name,
"request_index": request_idx,
"mode": mode,
"duration": 0,
"success": 0,
"result_url": "None",
"thread_id": thread_id,
"is_web": 0,
"is_app": 0,
"asin_list_web": "",
"asin_list_app": "",
"asin_list_join": "",
"site_name": site_name,
"device_info": json.dumps(device_info, ensure_ascii=False),
# "device_summary": f"{device_info.get('clientDevice')} ({device_info.get('clientDeviceVersion')})",
"save_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
# "error": str(e)
})
except queue.Empty: except queue.Empty:
# 队列已空,退出循环
break break
except Exception as e: except Exception as e:
logger.error(f"线程处理出错: {str(e)}") logger.error(f"[{thread_name}] 整体任务出错: {str(e)}")
finally: finally:
# 队列已空,退出循环
task_queue.task_done() task_queue.task_done()
def load_test_cookies() -> dict:
"""加载测试用的cookies"""
return {
"i18n-prefs": "USD",
"lc-main": "en_US",
"session-id": "131-0347800-4175077",
"session-id-time": "2082787201l",
"session-token": "Jo+AthxsQrcFH8qeii+sHhoo7puFd/cpJUEsjnWXtCLhr8ycF9TQSAv9zuyoAvFjfmXZuACFNa/D+i5et63EafMMPDK/825m8TUtNtlO88KmmEsm94fiyoPL0UakTyZsUBv/CzndcKB7h0K3NkbeFws9gZSdwYRGJFVeX+pPQ9ceN0WkE+XLwCt0plIIxG3BC+VtdFJWxPKxH+R5dlnbtxPso2S5zlrOf1FTEdGNNhNZvVq25XeydshrSp7AKG6VUOicnipgfAY0Qle3Y4bw72N1IqY9i3rXVZlkrkGePamBxew+Vel7U8ccVsEIT/vtOtLHPfsTljTgltlJU0bzk0YeoJ1LwI9S",
"skin": "noskin",
"ubid-main": "134-9889499-1876667"
}
def collect_image_paths(folder: str) -> List[str]: def collect_image_paths(folder: str) -> List[str]:
"""收集文件夹中的所有图片路径""" """收集文件夹中的图片路径(仅支持常见图片格式)"""
image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.bmp') image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.bmp')
if not os.path.exists(folder): if not os.path.exists(folder):
logger.error(f"图片文件夹不存在: {folder}") logger.error(f"图片文件夹不存在: {folder}")
return [] return []
image_paths = [ return [
os.path.join(folder, f) os.path.join(folder, f)
for f in os.listdir(folder) for f in os.listdir(folder)
if f.lower().endswith(image_extensions) if f.lower().endswith(image_extensions)
] ]
logger.info(f"发现 {len(image_paths)} 张图片: {[os.path.basename(p) for p in image_paths]}")
return image_paths
COLLECT_IMAGE_PATHS = collect_image_paths
def init_task_queue(image_paths: List[str]): def init_task_queue(image_paths: List[str]):
"""初始化任务队列 将每张图片的N次请求加入队列""" """初始化任务队列:包含所有站点、所有图片、所有请求次数(一次任务对应两种模式)"""
# for image_path in image_paths: for site in ALL_SITES:
# for i in range(1, REQUESTS_PER_IMAGE + 1):
# task_queue.put((image_path, i)) # 每个任务是(图片路径,请求序号)
# 轮询交替放任务(每张图片交替入队)
for request_idx in range(1, REQUESTS_PER_IMAGE + 1): for request_idx in range(1, REQUESTS_PER_IMAGE + 1):
for image_path in image_paths: for image_path in image_paths:
task_queue.put((image_path, request_idx)) task_queue.put((image_path, request_idx, site))
logger.info(f"任务队列初始化完成,总任务数: {task_queue.qsize()}") total_tasks = task_queue.qsize()
logger.info(
f"任务队列初始化完成 - 总任务数: {total_tasks} "
def save_results_to_csv(results: List[Dict], filename: str): f"(每个任务包含{len(ALL_MODES)}种模式),"
"""将结果保存到CSV文件""" f"站点数: {len(ALL_SITES)}, 图片数: {len(image_paths)}, "
f"单图单站请求数: {REQUESTS_PER_IMAGE}"
)
def save_results_to_excel(results: List[Dict]):
"""将结果写入Excel,新增mode字段区分模式"""
if not results: if not results:
logger.warning("没有结果可保存") logger.warning("结果可保存")
return return
with open(filename, 'w', newline='', encoding='utf-8') as f: # 转换为DataFrame,确保字段顺序(新增mode字段)
# 以结果列表中第一个字典的键作为CSV表头 df = pd.DataFrame(results)[[
fieldnames = results[0].keys() "image", "request_index", "mode", "duration", "success", "result_url",
writer = csv.DictWriter(f, fieldnames=fieldnames) "thread_id", "is_web", "is_app", "asin_list_web", "asin_list_app",
"asin_list_join", "site_name", "device_info", "save_time"
]]
writer.writeheader() # 保存到Excel
for row in results: df.to_excel(RESULT_EXCEL, index=False, engine="openpyxl")
writer.writerow(row) # 写入每行数据 logger.info(f"结果已保存到 {RESULT_EXCEL}")
with open(RESULT_CSV, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=test_results[0].keys())
writer.writeheader()
writer.writerows(test_results)
logger.info(f"结果已保存到 {RESULT_CSV}")
def print_summary(results: List[Dict]): def print_summary(results: List[Dict]):
"""打印测试总结(成功率、耗时等关键指标)""" """打印测试总结(按站点和模式分组统计)"""
if not results: if not results:
return return
total = len(results) total = len(results)
success = sum(1 for r in test_results if r["success"]) total_duration = sum(r["duration"] for r in results)
logger.info(f"\n===== 测试总结 =====") logger.info("\n===== 测试总结 =====")
logger.info(f"总请求: {total},成功: {success},成功率: {success/total*100:.2f}%") logger.info(f"总请求数: {total}(含{len(ALL_MODES)}种模式),"
f"总耗时: {total_duration:.2f}秒,"
# 按图片分组统计 (每张图片的单独表现) f"平均耗时: {total_duration / total:.4f}秒")
image_stats = {}
for r in results: # 按站点分组统计
img = r["image"] for site in ALL_SITES:
if img not in image_stats: site_results = [r for r in results if r["site_name"] == site]
image_stats[img] = {"total": 0, "success": 0, "duration": []} site_total = len(site_results)
image_stats[img]["total"] += 1 if site_total == 0:
image_stats[img]["success"] += r["success"] continue
image_stats[img]["duration"].append(r["duration"])
logger.info(f"\n----- 站点: {site} 统计 -----")
# 按线程统计 logger.info(f"总请求数: {site_total},平均耗时: {sum(r['duration'] for r in site_results) / site_total:.4f}秒")
thread_stats = {}
for r in test_results: # 按模式分组统计
t = r["thread_name"] for mode in ALL_MODES:
thread_stats[t] = thread_stats.get(t, 0) + 1 mode_results = [r for r in site_results if r["mode"] == mode]
logger.info("\n线程任务分配:") mode_total = len(mode_results)
for t, cnt in thread_stats.items(): if mode_total == 0:
logger.info(f" {t}: {cnt} 次请求") continue
mode_success = sum(1 for r in mode_results if r["is_app"] == 1)
def main(): mode_success_rate = (mode_success / mode_total) * 100 if mode_total else 0
# 初始化日志 logger.info(
logger.add("stability_test.log", rotation="10 MB", level="INFO") f"模式 {mode}: "
f"请求数 {mode_total}, 成功数 {mode_success}, "
f"成功率 {mode_success_rate:.2f}%, "
f"平均耗时 {sum(r['duration'] for r in mode_results) / mode_total:.4f}秒"
)
# 设备多样性统计
# devices_used = {r["device_summary"] for r in site_results}
# logger.info(f"使用设备种类: {len(devices_used)} 种")
cookies = load_test_cookies()
image_paths = COLLECT_IMAGE_PATHS(TEST_FOLDER)
if not image_paths:
logger.error("没有找到图片,无法进行测试")
return
if __name__ == "__main__":
# 初始化日志
log_file = os.path.join(LOG_DIR, "multi_mode_stability_test.log")
logger.add(log_file,rotation="10 MB",level="INFO",encoding="utf-8")
# 验证所有站点的合法性
for site in ALL_SITES:
if site not in site_name_secret_dict:
logger.error(f"不支持的站点: {site},支持站点: {list(site_name_secret_dict.keys())}")
exit(1)
if not SITE_DEVICES.get(site, []):
logger.warning(f"站点 {site} 的设备列表为空,可能影响测试结果")
# 准备资源
image_paths = collect_image_paths(TEST_FOLDER)
if not image_paths:
logger.error("未找到图片,退出测试")
exit(1)
init_task_queue(image_paths) init_task_queue(image_paths)
# 记录测试开始时间 # 启动多线程
test_start_time = time.time() start_time = time.time()
# 创建并启动线程
threads = [] threads = []
for i in range(THREAD_COUNT): for i in range(THREAD_COUNT):
t = threading.Thread(target=worker, args=(cookies,), name=f"Worker-{i + 1}") t = threading.Thread( target=worker, name=f"Worker-{i + 1}")
threads.append(t) threads.append(t)
t.start() t.start()
logger.info(f"启动线程: {t.name}") logger.info(f"启动线程: {t.name}")
# 等待所有任务完成 # 等待所有任务完成
task_queue.join() task_queue.join()
# 等待所有线程结束
for t in threads: for t in threads:
t.join() t.join()
# 计算总耗时 total_time = time.time() - start_time
total_test_time = time.time() - test_start_time logger.info(f"所有任务完成,总耗时: {total_time:.2f}秒")
logger.info(f"所有测试完成,总耗时: {total_test_time:.2f}秒")
# 保存结果并打印总结 # 保存结果并打印总结
save_results_to_csv(test_results, RESULT_CSV) save_results_to_excel(test_results)
print_summary(test_results) print_summary(test_results)
\ No newline at end of file
if __name__ == "__main__":
main()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment