I have a huge list of URL's (around 40 million).
I wrote a script that scrapes this URL's with multithreading. But I need an extra solution, which should be economical in OS resources, so I've decided to develop the ASYNC version as well.
I've studied asyncio and aiohttp in Python for a week.
Below is the working code:
from pathlib import Path
import time
import asyncio
import aiohttp
import pypeln as pl
import async_timeout
# for calculating the total elapsed time
start = time.time()
successful_counter = 0
# files and folders
urlFile = open('url500.txt', 'r')
# list for holding processed url's so far
urlList = []
#######################
# crawler function start
#######################
async def crawling(line, session1): # function wrapper for parallelizing the process
# getting URL's from the file
global successful_counter
line = line.strip()
# try to establish a connection
try:
async with async_timeout.timeout(25):
async with session1.get('http://' + line) as r1:
x = r1.headers
if ('audio' in x['Content-Type'] or 'video' in x['Content-Type']):
print("Url: " + line + " is a streaming website \n")
return # stream website, skip this website
# means we have established a connection and got the expected result
if r1.status // 100 == 2:
#print("Returned 2** for the URL:", line)
try:
text1 = await r1.text()
successful_counter += 1
'''
f1 = open('200/' + line + '.html', 'w')
f1.write(text1)
f1.close()
'''
except Exception as exc:
print(line + ": " + str(exc))
return
urlList.append(line)
return
else:
return
# some error occured
except Exception as exc:
print("Url: " + line + " created the error: \n" + str(exc))
return
#######################
# crawler function end
#######################
async def main(tempList):
'''
limit = 1000
await pl.task.each(
crawling, tempList, workers=limit,
)
'''
conn = aiohttp.TCPConnector(limit=0)
custom_header1 = {'User-agent': 'Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/74.0'}
#'''
async with aiohttp.ClientSession(headers=custom_header1, connector=conn) as session1:
await asyncio.gather(*[asyncio.ensure_future(crawling(url, session1)) for url in tempList])
#'''
return
asyncio.run(main(urlFile))
print("total successful: ", successful_counter)
# for calculating the total elapsed time
end = time.time()
print("Total elapsed time in seconds:", end-start)
Here is the problem: when I don't put any timeouts, it works with no problems but takes too much time. I want to spend at most 25 seconds per request, if the website does not give me any response, I should skip that website, and move on.
So far, every method I've tried failed me. When I put a timeout of 25 seconds in somewhere, it always restricts the whole program, instead of the single request. So whether I have a file that has 500 URLs, or 1000000 URLs, it's always ending in 25 seconds.
I've tried wrapping the crawler function with async_timeout, using the built-in timeout of aiohttp library
async with session1.get('http://' + line, timeout=25)
Tried to create session inside the crawler function and put a timeout on the session (again using aiohttp's built-in methods).
Nothing worked... Probably I'm missing something huge, but I'm stuck for days, and ran out of options to try :D