Оптимально по скорости спарсить большой объем информации с API

Рейтинг: 0Ответов: 1Опубликовано: 07.05.2023

я новичок в парсинге и хотел бы узнать, есть ли способ выполнить эту задачу эффективнее.

У меня есть файл, где лежат id научных статей с ресурса OpenAlex. Их 31000. Мне нужно узнать год публикации каждой из этих статей. Некоторые Id недействительны, поэтому стоит обработчик ошибок.

Я реализовал это так:

import csv
import asyncio
from aiohttp import ClientSession
import pandas as pd


async def get_sites(sites):
    tasks = [asyncio.create_task(fetch_site(s)) for s in sites]
    return await asyncio.gather(*tasks)


async def fetch_site(url):
    async with ClientSession() as session:
        async with session.get(url) as resp:
            if resp.status == 404:
                dat = ''
            else:
                dat = await resp.json()
    return dat


df = pd.read_excel('stati_bez_goda.xlsx')  # список статей
iter_df = df['Label']
URL_TEMPLATE = 'https://api.openalex.org/works'
all_years = []
file = open("out.csv", "w")

def years():
    for i in range(len(iter_df)):
        param = str(iter_df[i])
        sites = [f"{URL_TEMPLATE}/{param}?select=publication_year"]  # перебираем id статьи
        data = asyncio.run(get_sites(sites))
        if data[0]=='':
            year=data
        else:
            year=data[0]['publication_year']
        year=str(year)
        file.write(year+'\n')
        all_years.append(year)

years()
file.close()
# df['Year'] = all_years

Но код работает ОЧЕНЬ медленно. Он обрабатывает ~80 записей за минуту. То есть все статьи он обработает за 6 часов. Так же есть риск, что код просто завершиться с ошибкой. Пожалуйста, помогите разобраться с этой задачей

Ответы

▲ 1Принят

На мой взгляд распараллеливание запросов к сайтам происходит внутри ClientSession по формуле 1 сессия = N запросов. В Вашем случае получается 1 сессия = 1 запрос. Создание сессии дело затратное и когда их создается 3000 еще и долгое. Ниже привожу скелет как должно быть.

async def fetch_site(session: ClientSession, url: str):
    async with session.get(url) as request_result:
        return request_result


async def get_sites(sites):
    async with ClientSession() as session:
        # Формируем список сопрограмм для каждого запроса
        requests = [fetch_site(session, url) for url in sites]
        # Функция gather автоматически обернет каждую сопрограмму задачей и запустит их
        resp = await asyncio.gather(*requests)
    return resp


def years():
    sites = ["https://google.com" for _ in range(3000)]
    data = asyncio.run(get_sites(sites))