Ошибка 503 при загрузке дампов из Википедии - PullRequest
0 голосов
/ 25 октября 2018

У меня есть следующий скрипт для загрузки (и позже процесса) дампов просмотров страниц Википедии.Я получаю 503 ошибки на всех страницах (чьи URL-адреса правильные).

import argparse
import aiohttp
import asyncio
import async_timeout
import re

base_url = "http://dumps.wikimedia.org/other/pagecounts-raw/{year}/{year}-{month:02d}/pagecounts-{year}{month:02d}{day:02d}-{hour:02d}0000.gz"

async def downloadFile(semaphore, session, url):
    try:
        async with semaphore:
            with async_timeout.timeout(10):
                async with session.get(url) as remotefile:
                    if remotefile.status == 200:
                        data = await remotefile.read()
                        outfile = re.sub("/", "_", url[7:])
                        with open(outfile, 'wb') as fp:
                            print('Saving')
                            fp.write(data)
                    else:
                        print(remotefile.status)
                        return
    except Exception as e:
        print(e)
        return

async def aux(urls):
    sem = asyncio.Semaphore(10)
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in urls:
            print(url)
            task = asyncio.ensure_future(downloadFile(sem, session, url))
            tasks.append(task)
        await asyncio.gather(*tasks)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--year", type=int, default=2016)
    parser.add_argument("--month", type=int, default=4)
    parser.add_argument("--temp_folder", type=str)
    args = parser.parse_args()

    urls = []

    for day in range(1, 32)[:3]:
        for hour in range(24)[:2]:
            urls.append(base_url.format(
                year=args.year, month=args.month, day=day, hour=hour))

    loop = asyncio.get_event_loop()
    asyncio.ensure_future(aux(urls))
    loop.run_until_complete(aux(urls))


if __name__ == "__main__":
    main()

Я получаю ошибку:

<ClientResponse(https://dumps.wikimedia.org/other/pagecounts-raw/2016/2016-04/pagecounts-20160402-000000.gz) [503 Service Temporarily Unavailable]>
<CIMultiDictProxy('Server': 'nginx/1.13.6', 'Date': 'Wed, 24 Oct 2018 21:27:58 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '213', 'Connection': 'keep-alive', 'Strict-Transport-Security': 'max-age=106384710; includeSubDomains; preload')>

Но это действительно странно, поскольку copy-вставка тех же URL на моем браузере Chrome делает свою работу!

1 Ответ

0 голосов
/ 27 октября 2018

Я играл с кодом и могу сказать следующее:

  • Википедия не разрешает множественные запросы на один IP
  • Время ожидания 10 для этого URL слишком мало

Чтобы ваш код работал:

  • Измените asyncio.Semaphore(10) на asyncio.Semaphore(1)
  • Измените async_timeout.timeout(10) на async_timeout.timeout(120)
  • Полностью удалить строкуasyncio.ensure_future(aux(urls)), вам это не нужно, так как вы передаете пароль aux(urls) run_until_complete

Окончательная версия, которая успешно загружает один архив:

import argparse
import aiohttp
import asyncio
import async_timeout
import re

base_url = "http://dumps.wikimedia.org/other/pagecounts-raw/{year}/{year}-{month:02d}/pagecounts-{year}{month:02d}{day:02d}-{hour:02d}0000.gz"

async def downloadFile(semaphore, session, url):
    try:
        async with semaphore:
            with async_timeout.timeout(120):
                async with session.get(url, ssl=False) as remotefile:
                    if remotefile.status == 200:
                        data = await remotefile.read()
                        outfile = re.sub("/", "_", url[7:])
                        with open(outfile, 'wb') as fp:
                            print('Saving')
                            fp.write(data)
                    else:
                        print('status:', remotefile.status)
                        return
    except Exception as e:
        print('exception:', type(e), str(e))
        return

async def aux(urls):
    sem = asyncio.Semaphore(1)
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in urls:
            print('url:', url)
            task = asyncio.ensure_future(downloadFile(sem, session, url))
            tasks.append(task)
        await asyncio.gather(*tasks)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--year", type=int, default=2016)
    parser.add_argument("--month", type=int, default=4)
    parser.add_argument("--temp_folder", type=str)
    args = parser.parse_args()

    urls = []

    for day in range(1, 32)[:1]:
        for hour in range(24)[:1]:
            urls.append(base_url.format(
                year=args.year, month=args.month, day=day, hour=hour))

    loop = asyncio.get_event_loop()
    loop.run_until_complete(aux(urls))


if __name__ == "__main__":
    main()
...