33import asyncio
44import logging
55
6- from src .automation import deduplicate_listings , get_browser_page , scrape_all_pages , simulate_human_behavior , sort_by_newest
6+ from patchright .async_api import BrowserContext
7+
8+ from src .automation import create_browser_context , deduplicate_listings , get_browser_page , scrape_all_pages , simulate_human_behavior , sort_by_newest
79from src .config import Config , SubmissionType , load_configs
810from src .form_submission import submit_listings
911from src .scraper import PropertyListing
1315logger = logging .getLogger (__name__ )
1416
1517
16- async def scrape_listings (config : Config ) -> list [PropertyListing ]:
18+ async def scrape_listings (context : BrowserContext , config : Config ) -> list [PropertyListing ]:
1719 """Scrape and deduplicate listings from Zillow."""
18- async with get_browser_page () as page :
20+ async with get_browser_page (context ) as page :
1921 logger .info ("Loading search URL: %s..." , config .search_url )
2022
2123 await page .goto (config .search_url )
@@ -28,11 +30,11 @@ async def scrape_listings(config: Config) -> list[PropertyListing]:
2830 await sort_by_newest (page )
2931 all_listings = await scrape_all_pages (page )
3032
31- logger .info ("Deduplicating %s listings..." , len (all_listings ))
32- return deduplicate_listings (all_listings )
33+ logger .info ("Deduplicating %s listings..." , len (all_listings ))
34+ return deduplicate_listings (all_listings )
3335
3436
35- async def submit_listings_to_destination (config : Config , listings : list [PropertyListing ]) -> None :
37+ async def submit_listings_to_destination (context : BrowserContext , config : Config , listings : list [PropertyListing ]) -> None :
3638 """Submit listings based on configuration."""
3739 if not listings :
3840 logger .warning ("No listings to submit" )
@@ -48,26 +50,27 @@ async def submit_listings_to_destination(config: Config, listings: list[Property
4850 )
4951 elif config .submission_type == SubmissionType .FORM and isinstance (config .form_url , str ):
5052 logger .info ("Submitting %s listings to Google Form..." , len (listings ))
51- async with get_browser_page () as page :
53+ async with get_browser_page (context ) as page :
5254 await submit_listings (page , config .form_url , listings )
5355 else :
5456 logger .warning ("No submission destination configured" )
5557
5658
57- async def scrape_and_submit (config : Config ) -> None :
59+ async def scrape_and_submit (context : BrowserContext , config : Config ) -> None :
5860 """Orchestrate scraping and submission workflow."""
59- listings = await scrape_listings (config )
60- await submit_listings_to_destination (config , listings )
61+ listings = await scrape_listings (context , config )
62+ await submit_listings_to_destination (context , config , listings )
6163
6264
63- def main () -> None :
65+ async def main () -> None :
6466 """Load configurations and run scraper for each."""
6567 configs = load_configs ()
66- for config in configs :
67- logger .info ("Processing config: '%s'" , config .config_name )
68- asyncio .run (scrape_and_submit (config ))
69- logger .debug ("Completed config: '%s'" , config .config_name )
68+ async with create_browser_context () as context :
69+ for config in configs :
70+ logger .info ("Processing config: '%s'" , config .config_name )
71+ await scrape_and_submit (context , config )
72+ logger .debug ("Completed config: '%s'" , config .config_name )
7073
7174
7275if __name__ == "__main__" :
73- main ()
76+ asyncio . run ( main () )
0 commit comments