Skip to content

Commit 0358673

Browse files
Merge pull request steam-bell-92#1095 from knoxiboy/feat/issue-971-async-scraper
feat: implement async I/O for web scraping scripts
2 parents ef9bc24 + 851ee2e commit 0358673

2 files changed

Lines changed: 31 additions & 20 deletions

File tree

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pytest>=8.0.0
1010

1111
nltk==3.9.4
1212
requests==2.34.2
13+
aiohttp==3.11.11
1314

1415
# Markdown-to-PDF dependencies
1516
markdown2==2.5.5

utilities/Typing-Speed-Tester/Typing-Speed-Tester.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import json
55
import sys
66
import os
7+
import asyncio
8+
import aiohttp
79

810
# Add root directory to sys.path to import utils package
911
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
@@ -28,32 +30,40 @@
2830
"The best way to predict the future is to create it"
2931
]
3032

33+
async def fetch_url(session, url):
34+
try:
35+
async with session.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=3) as resp:
36+
if resp.status == 200:
37+
data = await resp.json()
38+
phrase = data.get('quote') or data.get('content')
39+
if phrase:
40+
return phrase
41+
except Exception:
42+
pass
43+
return None
44+
45+
async def fetch_phrase_async():
46+
urls = [
47+
"https://dummyjson.com/quotes/random",
48+
"https://api.quotable.io/random"
49+
]
50+
async with aiohttp.ClientSession() as session:
51+
tasks = [fetch_url(session, url) for url in urls]
52+
# Gather them concurrently
53+
results = await asyncio.gather(*tasks)
54+
for res in results:
55+
if res:
56+
return res
57+
return None
58+
3159
print("\n⌨️ ===============================")
3260
print(" WELCOME TO TYPING SPEED TESTER")
3361
print("================================ ⌨️\n")
3462

3563
while True:
3664
print("🌐 Fetching a fresh phrase for you...")
3765

38-
# Try multiple APIs for robustness
39-
urls = [
40-
"https://dummyjson.com/quotes/random",
41-
"https://api.quotable.io/random"
42-
]
43-
44-
sentence = None
45-
for url in urls:
46-
try:
47-
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
48-
with urllib.request.urlopen(req, timeout=3) as response:
49-
data = json.loads(response.read().decode())
50-
# dummyjson uses 'quote', quotable uses 'content'
51-
phrase = data.get('quote') or data.get('content')
52-
if phrase:
53-
sentence = phrase
54-
break
55-
except Exception:
56-
continue
66+
sentence = asyncio.run(fetch_phrase_async())
5767

5868
if not sentence:
5969
print("📴 Offline or API unavailable. Using a classic phrase instead.")
@@ -126,4 +136,4 @@
126136
again = input("\n🔄 Do you want to test again? (y/n): ").strip().lower()
127137
if again != 'y':
128138
print("\n👋 Thanks for testing your typing speed! Goodbye!\n")
129-
break
139+
break

0 commit comments

Comments
 (0)