import re import time from urllib.parse import unquote import requests import json from lxml import etree from openpyxl import load_workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side class ubereats: def __init__(self): self.html = "" self.wb = load_workbook('Menu to 11.05PM.xlsx') self.get_Html() self.modify_first_row = self.modify_first_row() def clear_sheet(self, sheet): ws = self.wb[sheet] for row in ws.iter_rows(min_row=2): # 首行不清空 for cell in row: if cell.value is not None: cell.value = None self.wb.save('Menu.xlsx') def clear_except_first_row(self, sheet): ws = self.wb[sheet] # **解除所有合并单元格** merged_ranges = list(ws.merged_cells.ranges) for merged_range in merged_ranges: ws.unmerge_cells(str(merged_range)) # **获取最大行和最大列** max_row = ws.max_row max_col = ws.max_column # **清除第二行及之后的所有数据和格式** if max_row > 1: for row in range(2, max_row + 1): # 从第二行开始清除 for col in range(1, max_col + 1): cell = ws.cell(row=row, column=col) cell.value = None # 清除数据 cell.fill = PatternFill(fill_type=None) # 清除背景色 cell.font = Font() # 重置字体 cell.alignment = Alignment() # 重置对齐方式 cell.border = Border() # 清除边框 # **删除第二行及之后的所有行** ws.delete_rows(2, max_row - 1 if max_row > 2 else 1) # **清除行级别格式** for row in range(2, max_row + 1): if row in ws.row_dimensions: ws.row_dimensions[row].fill = PatternFill(fill_type=None) # 清除行级背景色 ws.row_dimensions[row].font = Font() # 清除行级字体 ws.row_dimensions[row].alignment = Alignment() # 清除行级对齐方式 # **保存 Excel** self.wb.save('Menu.xlsx') def get_Html(self): url = "https://www.ubereats.com/store/orlando-china-ocean/xFyut_WfRn6gd83QgBGLoA?diningMode=PICKUP&mod=storeDeliveryTime&modctx=%257B%2522entryPoint%2522%253A%2522store-auto-surface%2522%252C%2522encodedStoreUuid%2522%253A%2522xFyut_WfRn6gd83QgBGLoA%2522%257D&pl=JTdCJTIyYWRkcmVzcyUyMiUzQSUyMkhlbGx1JTIwQ29mZmVlJTIyJTJDJTIycmVmZXJlbmNlJTIyJTNBJTIyQ2hJSjdjWHV4cFlaMmpFUlBtd2dfeGR4TXNFJTIyJTJDJTIycmVmZXJlbmNlVHlwZSUyMiUzQSUyMmdvb2dsZV9wbGFjZXMlMjIlMkMlMjJsYXRpdHVkZSUyMiUzQTEuMjgzMzU3MyUyQyUyMmxvbmdpdHVkZSUyMiUzQTEwMy44NDg0NzMzJTdE&ps=1&sc=SEARCH_SUGGESTION" payload = {} headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Alt-Used': 'www.ubereats.com', 'Connection': 'keep-alive', 'Cookie': 'uev2.id.xp=13f67607-d8f3-4ef4-ac9c-fae732d3a38c; dId=99b6b840-9ad5-4458-af7e-b832fa6602cb; uev2.id.session=a6af5007-9946-4ab1-a1bc-4d2b69736607; uev2.ts.session=1741796659278; uev2.diningMode=PICKUP; uev2.loc=%7B%22address%22%3A%7B%22address1%22%3A%22Hellu%20Coffee%22%2C%22address2%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%22%2C%22aptOrSuite%22%3A%22%22%2C%22eaterFormattedAddress%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%2C%20Singapore%20049965%22%2C%22subtitle%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%22%2C%22title%22%3A%22Hellu%20Coffee%22%2C%22uuid%22%3A%22%22%7D%2C%22latitude%22%3A1.2833573%2C%22longitude%22%3A103.8484733%2C%22reference%22%3A%22ChIJ7cXuxpYZ2jERPmwg_xdxMsE%22%2C%22referenceType%22%3A%22google_places%22%2C%22type%22%3A%22google_places%22%2C%22addressComponents%22%3A%7B%22city%22%3A%22%22%2C%22countryCode%22%3A%22SG%22%2C%22firstLevelSubdivisionCode%22%3A%22%22%2C%22postalCode%22%3A%22%22%7D%2C%22categories%22%3A%5B%22CAFE%22%2C%22FOOD_AND_BEVERAGE%22%2C%22RESTAURANT%22%2C%22SHOPS_AND_SERVICES%22%2C%22place%22%5D%2C%22originType%22%3A%22user_autocomplete%22%2C%22source%22%3A%22rev_geo_reference%22%2C%22userState%22%3A%22Unknown%22%7D; _ua={"session_id":"bdbf8384-0ffe-4501-90f8-6daa0eea2379","session_time_ms":1741796659351}; marketing_vistor_id=e17c0968-ef3d-4331-8211-c79c2ac7357e; jwt-session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNsYXRlLWV4cGlyZXMtYXQiOjE3NDE3OTg0NTkzNTB9LCJpYXQiOjE3NDE3OTY2NjAsImV4cCI6MTc0MTg4MzA2MH0.v-uUZO3RxqF6M29LFRNxNE_LpRMLWx7ApE7b7kPlQMQ; marketing_vistor_id=e17c0968-ef3d-4331-8211-c79c2ac7357e; uev2.diningMode=PICKUP; uev2.id.session=a6af5007-9946-4ab1-a1bc-4d2b69736607; uev2.ts.session=1741796659278', 'Upgrade-Insecure-Requests': '1', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-User': '?1', 'Priority': 'u=0, i' } response = requests.request("GET", url, headers=headers, data=payload) self.html = response.text.encode('utf-8').decode('unicode_escape') with open('html_postman2utf8.html', 'w', encoding="utf-8") as f: f.write(self.html) # with open('html_11.html', 'r', encoding='utf-8') as f: # self.html = f.read() def get_Menu(self): xpath_info = etree.HTML(self.html) menu_list = xpath_info.xpath("//button[starts-with(@id, 'tabs-desktop-ofd-menu-tab-')]/span/text()") menu_time = xpath_info.xpath("//p[@data-baseweb='typo-paragraphxsmall']/text()") menu_time = menu_time[1].encode('latin-1').decode('utf-8') if menu_list else "" menu_time = re.sub(r'\s+', '', menu_time) # Menu Description self.clear_sheet("Menu") ws = self.wb["Menu"] ws["A2"] = "Third Party Menu" self.clear_sheet("Categories") ws = self.wb["Categories"] for idx, item in enumerate(menu_list, start=2): ws.cell(row=idx, column=1, value="Third Party Menu") ws.cell(row=idx, column=2, value=item) ws.cell(row=idx, column=3, value="") # 翻译 ws.cell(row=idx, column=4, value=menu_time) ws.cell(row=idx, column=5, value="") self.wb.save('Menu.xlsx') def modify_first_row(self): ws = self.wb["Modifier"] source_row = 1 row_data = {} # 提取第一行数据和格式 for col in range(1, ws.max_column + 1): source_cell = ws.cell(row=source_row, column=col) row_data[col] = { "value": source_cell.value, # 数据 "font": Font( name=source_cell.font.name, size=source_cell.font.size, bold=source_cell.font.bold, italic=source_cell.font.italic, underline=source_cell.font.underline, color=source_cell.font.color.rgb if source_cell.font.color else None ), "alignment": Alignment( horizontal=source_cell.alignment.horizontal, vertical=source_cell.alignment.vertical, wrap_text=source_cell.alignment.wrap_text ), "fill": PatternFill( fill_type=source_cell.fill.patternType, fgColor=source_cell.fill.fgColor.rgb if source_cell.fill.fgColor else None, bgColor=source_cell.fill.bgColor.rgb if source_cell.fill.bgColor else None ) if source_cell.fill and source_cell.fill.patternType else None, "border": Border( left=Side(style=source_cell.border.left.style, color=source_cell.border.left.color), right=Side(style=source_cell.border.right.style, color=source_cell.border.right.color), top=Side(style=source_cell.border.top.style, color=source_cell.border.top.color), bottom=Side(style=source_cell.border.bottom.style, color=source_cell.border.bottom.color), ) if source_cell.border else None } row_data["row_height"] = ws.row_dimensions[source_row].height return row_data def get_item(self): html_info = re.findall(r'', self.html, re.S) js2json = unquote(html_info[5]) json_data = json.loads(js2json) # with open('data.json', 'w', encoding='utf-8') as f: # f.write(json.dumps(json_data, indent=4)) # exit() self.clear_except_first_row("Item") self.clear_except_first_row("Modifier") ws = self.wb["Item"] data = [] # with open('data.json', 'r', encoding='utf-8') as f: # json_data = json.load(f) queries = json_data['queries'][0]['state']['data'] storeUuid = queries['uuid'] sectionUuid = list(queries["catalogSectionsMap"].keys())[0] index = 2 for catalog in queries["catalogSectionsMap"][sectionUuid]: playload = catalog['payload'] standardItemsPayload = playload['standardItemsPayload'] _type = standardItemsPayload['title']['text'] for citem in standardItemsPayload['catalogItems']: menuItemUuid = citem['uuid'] title = citem['title'] price = citem['price'] / 100 itemDescription = citem['itemDescription'] if "/ ." in itemDescription: itemDescription = itemDescription.replace("/ .", "") if "é" in itemDescription: itemDescription = itemDescription.replace("é", "é") hasCustomizations = citem['hasCustomizations'] subsectionUuid = citem['subsectionUuid'] if hasCustomizations: modifier = self.get_itemV1(storeUuid, sectionUuid, subsectionUuid, menuItemUuid) if modifier['ism'] != 1: for addons in modifier['addons']: existing_addon = next((item for item in data if item["name"] == addons["name"]), None) if existing_addon: existing_items = {item["name"] for item in existing_addon["list"]} new_items = [item for item in addons["list"] if item["name"] not in existing_items] existing_addon["list"].extend(new_items) else: data.append(addons) ws.cell(row=index, column=1, value="Online Lunch Menu") ws.cell(row=index, column=2, value=_type) ws.cell(row=index, column=3, value=title) ws.cell(row=index, column=4, value="") ws.cell(row=index, column=5, value=price) ws.cell(row=index, column=7, value=itemDescription) ws.cell(row=index, column=8, value="Sales Tax") if not hasCustomizations: ws.cell(row=index, column=6, value="") else: if modifier['ism'] == 3 or modifier['ism'] == 1: value = ";".join( [f"{format(price if i['price'] == 0.0 else i['price'] + price, '.2f')}/{i['name']}" for i in modifier['sizes']]) ws.cell(row=index, column=5, value=value) if modifier['ism'] == 3: v2 = "\n".join([i for i in modifier['nameList']]) ws.cell(row=index, column=6, value=v2) if modifier['ism'] == 2: v2 = "\n".join([i['name'] for i in modifier['addons']]) ws.cell(row=index, column=6, value=v2) index += 1 self.wb.save('Menu.xlsx') with open('Adata.json', 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=4) def write_xlsx(self): ws = self.wb["Modifier"] self.clear_except_first_row("Modifier") # 清除数据,但保留第一行 with open('Adata.json', 'r', encoding='utf-8') as f: data = json.load(f) index = 2 # **确保从第 2 行开始填充数据** for i in data: # **确保从 index > 2 才复制格式** if index > 2: ws.row_dimensions[index].height = self.modify_first_row["row_height"] for col, cell_data in self.modify_first_row.items(): if col == "row_height": continue target_cell = ws.cell(row=index, column=col) # **正确赋值** target_cell.value = cell_data["value"] # **复制格式** if cell_data["font"]: target_cell.font = Font( name=cell_data["font"].name, size=cell_data["font"].size, bold=cell_data["font"].bold, italic=cell_data["font"].italic, underline=cell_data["font"].underline, color=cell_data["font"].color ) if cell_data["alignment"]: target_cell.alignment = Alignment( horizontal=cell_data["alignment"].horizontal, vertical=cell_data["alignment"].vertical, wrap_text=cell_data["alignment"].wrap_text ) if cell_data["fill"] and cell_data["fill"].patternType: target_cell.fill = PatternFill( fill_type=cell_data["fill"].patternType, fgColor=cell_data["fill"].fgColor.rgb, bgColor=cell_data["fill"].bgColor.rgb ) if cell_data["border"]: target_cell.border = Border( left=Side(style=cell_data["border"].left.style, color=cell_data["border"].left.color), right=Side(style=cell_data["border"].right.style, color=cell_data["border"].right.color), top=Side(style=cell_data["border"].top.style, color=cell_data["border"].top.color), bottom=Side(style=cell_data["border"].bottom.style, color=cell_data["border"].bottom.color), ) index += 1 # **填充 JSON 数据** ws.cell(row=index, column=1, value=i['name']) ws.cell(row=index, column=2, value="") ws.cell(row=index, column=7, value="Required" if i['required'] else "Not Required") ws.cell(row=index, column=8, value="1") ws.cell(row=index, column=9, value=i['maxPermitted']) ws.cell(row=index, column=10, value="NO") aindex = index for item in i['list']: ws.cell(row=index, column=3, value=item['name']) ws.cell(row=index, column=6, value=item['price']) index += 1 index += 1 bindex = index if bindex - aindex > 1: ws.merge_cells(start_row=aindex, start_column=1, end_row=bindex - 2, end_column=1) ws.cell(row=aindex, column=1).alignment = Alignment(horizontal="center", vertical="center") ws.merge_cells(start_row=aindex, start_column=2, end_row=bindex - 2, end_column=2) ws.cell(row=aindex, column=2).alignment = Alignment(horizontal="center", vertical="center") ws.merge_cells(start_row=aindex, start_column=7, end_row=bindex - 2, end_column=7) ws.cell(row=aindex, column=7).alignment = Alignment(horizontal="center", vertical="center") ws.merge_cells(start_row=aindex, start_column=8, end_row=bindex - 2, end_column=8) ws.cell(row=aindex, column=8).alignment = Alignment(horizontal="center", vertical="center") ws.merge_cells(start_row=aindex, start_column=9, end_row=bindex - 2, end_column=9) ws.cell(row=aindex, column=9).alignment = Alignment(horizontal="center", vertical="center") ws.merge_cells(start_row=aindex, start_column=10, end_row=bindex - 2, end_column=10) ws.cell(row=aindex, column=10).alignment = Alignment(horizontal="center", vertical="center") self.wb.save('Menu.xlsx') def get_itemV1(self, storeUuid, sectionUuid, subsectionUuid, menuItemUuid): cookies = { 'dId': '201f1380-db90-4fce-b53c-9e5f1a1797db', 'uev2.diningMode': 'PICKUP', 'marketing_vistor_id': 'b2b08d27-61c5-49a5-8960-3bf57d7dc740', 'u-cookie-prefs': 'eyJ2ZXJzaW9uIjoxMDAsImRhdGUiOjE3NDExNzE2MjgyODAsImNvb2tpZUNhdGVnb3JpZXMiOlsiYWxsIl0sImltcGxpY2l0Ijp0cnVlfQ%3D%3D', 'uev2.gg': 'true', '_gcl_au': '1.1.639637700.1741171631', '_scid': 'PKHcwyQACjnCw9d1hw_hGGK2mECWKPAw', '_fbp': 'fb.1.1741171631251.75638408989351243', '_ga': 'GA1.1.1953756175.1741171632', '_ScCbts': '%5B%5D', '_yjsu_yjad': '1741171631.b78cd8ba-9e38-46b9-b413-15deb0d5a676', '_sctr': '1%7C1741104000000', '_tt_enable_cookie': '1', '_ttp': '01JNJYND745JBKHC19JF1B3ENF_.tt.1', 'uev2.embed_theme_preference': 'dark', 'uev2.id.xp': 'bd485f5e-f8f1-4dce-bf88-c1e92a3cd4c0', '_ua': '{"session_id":"f08842b9-416c-4e82-bed0-25250e9abe14","session_time_ms":1741398128598}', 'utm_medium': 'undefined', 'utm_source': 'undefined', '_clck': 'oo6f3j%7C2%7Cfu1%7C0%7C1890', 'uev2.loc': '%7B%22address%22%3A%7B%22address1%22%3A%22Hellu%20Coffee%22%2C%22address2%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%22%2C%22aptOrSuite%22%3A%22%22%2C%22eaterFormattedAddress%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%2C%20Singapore%20049965%22%2C%22subtitle%22%3A%22137%20Amoy%20St%2C%20%2301-05%20Far%20East%20Square%22%2C%22title%22%3A%22Hellu%20Coffee%22%2C%22uuid%22%3A%22%22%7D%2C%22latitude%22%3A1.2833573%2C%22longitude%22%3A103.8484733%2C%22reference%22%3A%22ChIJ7cXuxpYZ2jERPmwg_xdxMsE%22%2C%22referenceType%22%3A%22google_places%22%2C%22type%22%3A%22google_places%22%2C%22addressComponents%22%3A%7B%22city%22%3A%22%22%2C%22countryCode%22%3A%22SG%22%2C%22firstLevelSubdivisionCode%22%3A%22%22%2C%22postalCode%22%3A%22%22%7D%2C%22categories%22%3A%5B%22CAFE%22%2C%22FOOD_AND_BEVERAGE%22%2C%22RESTAURANT%22%2C%22SHOPS_AND_SERVICES%22%2C%22place%22%5D%2C%22originType%22%3A%22user_autocomplete%22%2C%22source%22%3A%22manual_auto_complete%22%2C%22userState%22%3A%22Unknown%22%7D', 'uev2.id.session': '92a4abd6-d9c4-4a11-97ee-ae4a7083eedd', 'uev2.ts.session': '1741414539843', 'jwt-session': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InNsYXRlLWV4cGlyZXMtYXQiOjE3NDE0MTYzNDAyOTl9LCJpYXQiOjE3NDEzOTgxMjksImV4cCI6MTc0MTQ4NDUyOX0.hpvIQEo4HoKsyOfRlVGrxuXN1dO_R_9k_tHCbMe_q3s', 'utag_main__sn': '5', 'utag_main_ses_id': '1741414545690%3Bexp-session', 'utag_main__pn': '1%3Bexp-session', '_scid_r': 'SCHcwyQACjnCw9d1hw_hGGK2mECWKPAwQvf-Wg', 'utag_main__se': '2%3Bexp-session', 'utag_main__ss': '0%3Bexp-session', 'utag_main__st': '1741416357381%3Bexp-session', '_userUuid': '', '_ga_P1RM71MPFP': 'GS1.1.1741414542.6.1.1741414563.39.0.0', '_uetsid': '8fabeee0fbbe11ef9b636786bd2c1b62', '_uetvid': '32f691f0f9af11efad4d6dc246fea42a', } headers = { 'accept': '*/*', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'no-cache', 'content-type': 'application/json', 'origin': 'https://www.ubereats.com', 'pragma': 'no-cache', 'priority': 'u=1, i', # 'referer': 'https://www.ubereats.com/store/orlando-china-ocean/xFyut_WfRn6gd83QgBGLoA?diningMode=PICKUP&mod=quickView&modctx=%257B%2522storeUuid%2522%253A%2522c45caeb7-f59f-467e-a077-cdd080118ba0%2522%252C%2522sectionUuid%2522%253A%2522aa0f2b6d-8a05-575d-824a-814fa08b06d9%2522%252C%2522subsectionUuid%2522%253A%25228a6f7010-f06b-5f85-b417-38d9e96676f7%2522%252C%2522itemUuid%2522%253A%2522bad6eebb-46ff-571e-8d30-d42c40cdb62b%2522%252C%2522showSeeDetailsCTA%2522%253Atrue%257D&ps=1&sc=SEARCH_SUGGESTION', 'sec-ch-prefers-color-scheme': 'dark', 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', 'x-csrf-token': 'x', 'x-uber-client-gitref': 'a7f1b446e212f9e1ae1ee1c6541dbf565c7c6293' } json_data = { 'itemRequestType': 'ITEM', 'storeUuid': storeUuid, 'sectionUuid': sectionUuid, 'subsectionUuid': subsectionUuid, 'menuItemUuid': menuItemUuid, 'cbType': 'EATER_ENDORSED', 'contextReferences': [ { 'type': 'GROUP_ITEMS', 'payload': { 'type': 'groupItemsContextReferencePayload', 'groupItemsContextReferencePayload': {}, }, 'pageContext': 'UNKNOWN', }, ], } proxies = { 'http': 'http://127.0.0.1:7890', 'https': 'http://127.0.0.1:7890' } response = requests.post('https://www.ubereats.com/_p/api/getMenuItemV1', cookies=cookies, headers=headers, json=json_data, proxies=None).json() size_identifiers = ["(S)", "(L)", "(小)", "(大)", "(Half Gallon)", "(One Gallon)", "1.4pcs", "8pcs", "4pcs"] data = {"ism": 0, "sizes": [], "addons": [], "nameList": []} # **新增 nameList** has_size_option = False has_addon_option = False customizationsList = response['data']['customizationsList'] for customizations in customizationsList: title = customizations['title'] customization_entry = {"name": title, "list": []} for item in customizations['options']: option_title = item['title'] price = item['price'] / 100 is_required = customizations['minPermitted'] > 0 customization_entry["required"] = is_required customization_entry["maxPermitted"] = customizations['maxPermitted'] if any(option_title.startswith(size) for size in size_identifiers): data['sizes'].append({"name": option_title, "price": price}) has_size_option = True else: customization_entry["list"].append({"name": option_title, "price": price}) has_addon_option = True # **解析子配菜** if "childCustomizationList" in item and len(item['childCustomizationList']) > 0: for child_customization in item["childCustomizationList"]: for child_option in child_customization["options"]: child_option_title = child_option["title"] child_price = child_option["price"] / 100 customization_entry["list"].append({"name": child_option_title, "price": child_price}) has_addon_option = True # **子配菜也是配菜* if customization_entry["list"]: data["addons"].append(customization_entry) # **在 ism=3 时,生成 `nameList`** if has_size_option and has_addon_option: data['ism'] = 3 # **大小份 + 配菜** data['ism'] = 3 # **大小份 + 配菜** rename = data["addons"][0]["name"] data['nameList'] = [f"{size['name']}: {rename}" for size in data["sizes"]] elif has_size_option: data['ism'] = 1 # **只有大小份** elif has_addon_option: data['ism'] = 2 # **只有配菜** print(data) # **检查数据是否正确** return data if __name__ == '__main__': ubereats = ubereats() ubereats.get_Menu() ubereats.get_item() ubereats.get_item() ubereats.write_xlsx() # ubereats.get_itemV1("","","","") # ubereats.get_itemV1("0212c830-1845-41d2-aa06-6c78bfb97315", "516658e0-667f-5063-a3e9-d9d3e13a2e53", "017a5d2c-88c7-5f1e-8c5e-d8bf76ac5d12", "28eaf6a2-f83b-5d67-b20a-1cd59b4ed42c") # ubereats.write_xlsx()