como melhorar a velocidade do código Webscrapping por meio do código python multithreading
abaixo está o meu código no qual estou escrevendo linha por linha (há cerca de 900 páginas com 10 linhas e 5 dados em cada linha). Existe alguma maneira de tornar isso mais rápido. atualmente, está levando 80 minutos para exportar os dados para csv. Existe alguma maneira de fazer solicitações paralelas para páginas e tornar este código mais eficiente.
import requests
from urllib3.exceptions import InsecureRequestWarning
import csv
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from bs4 import BeautifulSoup as bs
f = csv.writer(open('GEM.csv', 'w', newline=''))
f.writerow(['Bidnumber', 'Items', 'Quantitiy', 'Department', 'Enddate'])
def scrap_bid_data():
page_no = 1
while page_no < 910:
print('Hold on creating URL to fetch data...')
url = 'https://bidplus.gem.gov.in/bidlists?bidlists&page_no=' + str(page_no)
print('URL created: ' + url)
scraped_data = requests.get(url, verify=False)
soup_data = bs(scraped_data.text, 'lxml')
extracted_data = soup_data.find('div', {'id': 'pagi_content'})
if len(extracted_data) == 0:
break
else:
for idx in range(len(extracted_data)):
if (idx % 2 == 1):
bid_data = extracted_data.contents[idx].text.strip().split('\n')
bidno = bid_data[0].split(":")[-1]
items = bid_data[5].split(":")[-1]
qnty = int(bid_data[6].split(':')[1].strip())
dept = (bid_data[10] + bid_data[12].strip()).split(":")[-1]
edate = bid_data[17].split("End Date:")[-1]
f.writerow([bidno, items, qnty, dept, edate])
page_no=page_no+1
scrap_bid_data()
Respostas
Reestruturei seu código um pouco para garantir que seu arquivo CSV seja fechado. Também recebi a seguinte mensagem de erro:
ConnectionError: HTTPSConnectionPool (host = 'bidplus.gem.gov.in', port = 443): Máximo de tentativas excedido com url: / bidlists? Bidlists & page_no = 1 (Causado por NewConnectionError ('<urllib3.connection.HTTPSConnection object em 0x0000012EB0DF1E>: 0x0000012EB0DF1E Falha ao estabelecer uma nova conexão: [WinError 10060] Uma tentativa de conexão falhou porque a parte conectada não respondeu adequadamente após um período de tempo, ou a conexão estabelecida falhou porque o host conectado não respondeu ',))
Você deve experimentar o NUMBER_THREADSvalor:
import requests
from urllib3.exceptions import InsecureRequestWarning
import csv
import concurrent.futures
import functools
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from bs4 import BeautifulSoup as bs
def download_page(session, page_no):
url = 'https://bidplus.gem.gov.in/bidlists?bidlists&page_no=' + str(page_no)
print('URL created: ' + url)
resp = session.get(url, verify=False)
return resp.text
def scrap_bid_data():
NUMBER_THREADS = 30 # number of concurrent download requests
with open('GEM.csv', 'w', newline='') as out_file:
f = csv.writer(out_file)
f.writerow(['Bidnumber', 'Items', 'Quantitiy', 'Department', 'Enddate'])
with requests.Session() as session:
page_downloader = functools.partial(download_page, session)
with concurrent.futures.ThreadPoolExecutor(max_workers=NUMBER_THREADS) as executor:
pages = executor.map(page_downloader, range(1, 910))
page_no = 0
for page in pages:
page_no += 1
soup_data = bs(page, 'lxml')
extracted_data = soup_data.find('div', {'id': 'pagi_content'})
if extracted_data is None or len(extracted_data) == 0:
print('No data at page number', page_no)
print(page)
break
else:
for idx in range(len(extracted_data)):
if (idx % 2 == 1):
bid_data = extracted_data.contents[idx].text.strip().split('\n')
bidno = bid_data[0].split(":")[-1]
items = bid_data[5].split(":")[-1]
qnty = int(bid_data[6].split(':')[1].strip())
dept = (bid_data[10] + bid_data[12].strip()).split(":")[-1]
edate = bid_data[17].split("End Date:")[-1]
f.writerow([bidno, items, qnty, dept, edate])
scrap_bid_data()