#!/usr/bin/python3 import os from datetime import datetime from playwright.sync_api import Playwright, Request, expect, sync_playwright from rich.pretty import pprint skip_domains = { "cdn.linkedin.oribi.io", "cdn.evgnet.com", "zdassets.com", "doubleclick.net", "linkedin.com", "facebook", "adservice.google.com", "google", "bing", "eurotunnel.report-uri.com", } skip_content_type = {"image", "text/css", "application/x-woff", "text/javascript"} data_loc = os.path.expanduser("~/lib/data/eurotunnel") outbound_label = "Select your outbound tickets from Folkestone to Calais" return_label = "Select your Return tickets from Calais to Folkestone" choose_your_tickets = "https://www.eurotunnel.com/book/ChooseYourTickets/(0)" def data_filename(page_type: str, ext: str = "html") -> str: """Filename to use for saving data.""" now_str = datetime.utcnow().strftime("%Y-%m-%d_%H%M%S") return os.path.join(data_loc, now_str + f"_{page_type}.{ext}") class HandleResponse: got_outbound: bool = False def requestfinished(self, request: Request) -> None: """Show details of finished request.""" if any(d in request.url for d in skip_domains): return if "tunnel" not in request.url: return response = request.response() reply_ct = response.headers.get("content-type") if reply_ct and any(reply_ct.startswith(ct) for ct in skip_content_type): return url = request.url show = { "url": url, "method": request.method, "request_headers": request.headers, "response_headers": response.headers, } if request.method == "POST": show["post_data"] = request.post_data pprint(show) if not request.method == "GET" or not url.startswith(choose_your_tickets): return if url == choose_your_tickets + "?d=o": filename = data_filename("outbound") with open(filename, "wb") as out: out.write(response.body()) if url == choose_your_tickets + "?d=r": filename = data_filename("return") with open(filename, "wb") as out: out.write(response.body()) def run(playwright: Playwright) -> None: """Launch browser and search for options.""" browser = playwright.chromium.launch(headless=False) context = browser.new_context() page = context.new_page() hr = HandleResponse() page.on("requestfinished", hr.requestfinished) page.goto("https://www.eurotunnel.com/uk/") page.get_by_role("button", name="Accept All Cookies").click() page.get_by_role("textbox", name="Outbound").click() page.get_by_role("row", name="August 2023").get_by_role("cell").nth(1).click() page.get_by_role("cell", name="29").click() page.get_by_role("textbox", name="Return").click() page.get_by_role("row", name="September 2023").get_by_role("cell").nth(2).click() page.get_by_role("cell", name="6", exact=True).click() page.get_by_role("button", name="Search and book").click() page.get_by_label("Enter your vehicle registration").fill("KE69HRR") page.get_by_role("button", name="Find").click() page.get_by_text("No", exact=True).first.click() page.get_by_text("No", exact=True).nth(1).click() page.get_by_text("Conventional (Diesel/Petrol)").click() page.get_by_role("combobox", name="Country of residence").select_option("GB") page.get_by_role("button", name="Continue").click() expect(page.get_by_text(outbound_label)).to_be_visible() filename = data_filename("outbound_prices") with open(filename, "w") as out: out.write(page.content()) page.locator("#slots div").filter(has_text="12:00To").locator("span").click() page.locator("div:nth-child(5) > .times > div:nth-child(2) > .radio-button").click() page.locator( "div:nth-child(17) > .d-flex > div > .body > .radio-button" ).first.click() page.get_by_role("button", name="Confirm and choose return ticket").click() expect(page.get_by_text(return_label)).to_be_visible() filename = data_filename("return_prices") with open(filename, "w") as out: out.write(page.content()) page.close() context.close() browser.close() with sync_playwright() as playwright: run(playwright)