Skip to content

Commit 41c2267

Browse files
committed
consolidate timeout pauses to simulate_human_behavior
1 parent c5285cc commit 41c2267

File tree

4 files changed

+11
-34
lines changed

4 files changed

+11
-34
lines changed

src/automation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ async def scroll_and_load_listings(page: Page, max_entries: int = 100, max_no_ch
193193
logger.debug("Lazy loading complete. Total property cards loaded: %s", final_count)
194194

195195
await scroll_to_top(page)
196+
await simulate_human_behavior(page)
196197

197198

198199
async def check_and_click_next_page(page: Page) -> bool:
@@ -246,7 +247,7 @@ async def sort_by_newest(page: Page) -> None:
246247

247248
await sort_button.click()
248249
await page.wait_for_load_state()
249-
await page.wait_for_timeout(1.23)
250+
await simulate_human_behavior(page)
250251

251252
newest_button = page.get_by_text("Newest")
252253
if not newest_button:

src/form_submission.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from patchright.async_api import TimeoutError as PlaywrightTimeoutError
88
from tqdm import tqdm
99

10-
from src.constants import MAX_WAIT_TIME, MIN_WAIT_TIME, GoogleFormConstants
10+
from src.automation import simulate_human_behavior
11+
from src.constants import GoogleFormConstants
1112
from src.scraper import PropertyListing
1213

1314
logger = logging.getLogger(__name__)
@@ -17,7 +18,7 @@
1718
async def _submit_single_listing(page: Page, url: str, listing: PropertyListing) -> None:
1819
"""Submit a single listing to the Google Form."""
1920
await page.goto(url)
20-
await page.wait_for_timeout(cryptogen.randint(MIN_WAIT_TIME, MAX_WAIT_TIME))
21+
await simulate_human_behavior(page)
2122

2223
await page.fill(GoogleFormConstants.ADDRESS_INPUT_XPATH, listing.address)
2324
await page.fill(GoogleFormConstants.PRICE_INPUT_XPATH, listing.price)
@@ -31,7 +32,7 @@ async def _submit_single_listing(page: Page, url: str, listing: PropertyListing)
3132
error_msg = f"Form submission confirmation not received for {listing.address}"
3233
raise PlaywrightTimeoutError(error_msg) from e
3334

34-
await page.wait_for_timeout(cryptogen.randint(MIN_WAIT_TIME, MAX_WAIT_TIME))
35+
await simulate_human_behavior(page)
3536

3637

3738
async def submit_listings(page: Page, form_url: str, listings: list[PropertyListing]) -> None:

src/main.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ async def scrape_listings(context: BrowserContext, config: Config) -> list[Prope
3939

4040
logger.info("Scraping all listings...")
4141
await sort_by_newest(page)
42-
await page.wait_for_timeout(0.84)
4342
all_listings = await scrape_all_pages(page)
4443

4544
logger.info("Deduplicating %s listings...", len(all_listings))

tests/test_form_submission.py

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def wait_for_selector_side_effect(*_, **__) -> AsyncMock:
5353
mock_page.wait_for_selector.side_effect = wait_for_selector_side_effect
5454
form_url = "https://example.com/form"
5555

56-
with caplog.at_level("INFO"), patch("src.form_submission.cryptogen.randint", return_value=250):
56+
with caplog.at_level("INFO"), patch("src.automation.cryptogen.randint", return_value=250):
5757
await submit_listings(mock_page, form_url, sample_listings)
5858

5959
assert mock_page.goto.call_count == 3
@@ -67,7 +67,7 @@ async def test_submit_listings_all_succeed(caplog: LogCaptureFixture, sample_lis
6767
mock_page = AsyncMock()
6868
form_url = "https://example.com/form"
6969

70-
with caplog.at_level("INFO"), patch("src.form_submission.cryptogen.randint", return_value=250):
70+
with caplog.at_level("INFO"), patch("src.automation.cryptogen.randint", return_value=250):
7171
await submit_listings(mock_page, form_url, sample_listings)
7272

7373
assert "3 successful, 0 failed" in caplog.text
@@ -82,7 +82,7 @@ async def test_submit_listings_all_fail(caplog: LogCaptureFixture, sample_listin
8282
mock_page.wait_for_selector.side_effect = PlaywrightTimeoutError("Timeout")
8383
form_url = "https://example.com/form"
8484

85-
with caplog.at_level("INFO"), patch("src.form_submission.cryptogen.randint", return_value=250):
85+
with caplog.at_level("INFO"), patch("src.automation.cryptogen.randint", return_value=250):
8686
await submit_listings(mock_page, form_url, sample_listings)
8787

8888
assert "0 successful, 3 failed" in caplog.text
@@ -107,7 +107,7 @@ async def test_submit_single_listing_flow_order() -> None:
107107
mock_page.wait_for_selector.side_effect = lambda *_, **__: call_order.append("wait_for_selector")
108108
mock_page.wait_for_timeout.side_effect = lambda _: call_order.append("wait_for_timeout")
109109

110-
with patch("src.form_submission.cryptogen.randint", return_value=250):
110+
with patch("src.automation.cryptogen.randint", return_value=250):
111111
await _submit_single_listing(mock_page, form_url, listing)
112112

113113
# Verify the sequence
@@ -123,30 +123,6 @@ async def test_submit_single_listing_flow_order() -> None:
123123
]
124124

125125

126-
@pytest.mark.asyncio
127-
async def test_submit_listings_uses_random_waits() -> None:
128-
"""Test that random wait times are used between submissions."""
129-
mock_page = AsyncMock()
130-
listings = [
131-
PropertyListing("Addr1", "$1000", "1000", "http://link1"),
132-
PropertyListing("Addr2", "$2000", "2000", "http://link2"),
133-
]
134-
form_url = "https://example.com/form"
135-
136-
wait_times: list[int] = []
137-
mock_page.wait_for_timeout.side_effect = wait_times.append
138-
139-
with patch("src.form_submission.cryptogen.randint") as mock_randint:
140-
# Return different values for each call
141-
mock_randint.side_effect = [100, 150, 200, 250]
142-
await submit_listings(mock_page, form_url, listings)
143-
144-
# Should have wait_for_timeout called multiple times (2 per listing)
145-
assert len(wait_times) == 4
146-
# Verify the random values were used
147-
assert wait_times == [100, 150, 200, 250]
148-
149-
150126
@pytest.mark.parametrize(
151127
"empty_list_arg",
152128
[
@@ -177,7 +153,7 @@ async def test_submit_single_listing_field_mapping(mock_page: AsyncMock) -> None
177153
listing = PropertyListing(address="742 Evergreen Terrace", price="$2,500/mo", median_price="2500", link="https://zillow.com/listing/999")
178154
form_url = "https://example.com/form"
179155

180-
with patch("src.form_submission.cryptogen.randint", return_value=250):
156+
with patch("src.automation.cryptogen.randint", return_value=250):
181157
await _submit_single_listing(mock_page, form_url, listing)
182158

183159
fill_calls = mock_page.fill.call_args_list

0 commit comments

Comments
 (0)