Есть несколько вопросов об асинхронных запросах в Python - PullRequest
0 голосов
/ 14 февраля 2020

Я хочу проверить ссылки на более чем 10 тыс. Страниц за один прогон. У меня есть рабочее решение, но, к сожалению, оно СЛИШКОМ слишком медленное, потому что оно обрабатывает requests.get один за другим, поэтому программе всегда нужно ждать ответа от URL, прежде чем обрабатывать следующий URL.

У меня есть пытался найти решение и заметил эту статью с основами многопоточности, асинхронных запросов и многопроцессорности. Попытался реализовать асинхронное решение для моего случая и придумал следующий тестовый код:

import asyncio
import aiohttp
import time
from bs4 import BeautifulSoup

DOMAIN = 'forbes.com'


class Link:
    url = None
    anchor = None
    rel = None


async def get_link(session, url):
    internal_links = list()
    async with session.get(url) as response:
        soup = BeautifulSoup(response.content, 'html.parser', from_encoding='iso-8859-1')
        for link in soup.find_all('a'):
            if DOMAIN in link.get('href'):
                internal_links.append(Link())
                internal_links[-1].url = link.get('href')
                internal_links[-1].anchor = link.text
                internal_links[-1].rel = link.get('rel')
    if len(internal_links) != 0:
        for internal_link in internal_links:
            print(f'URL is {internal_link.url}\n Anchor is {internal_link.anchor}\n Rel is {internal_link.rel}\n\n')


async def get_all_links(urls):
    async with aiohttp.ClientSession() as session:
        tasks = list()
        for url in urls:
            task = asyncio.ensure_future(get_link(session, url))
            tasks.append(task)
        await asyncio.gather(*tasks, return_exceptions=True)


if __name__ == '__main__':
    pages = [
        'https://www.forbes.com/',
        'https://www.forbes.com/sites/davidphelan/2020/02/13/apple-reveals-dazzlingly-different-apple-watch-design--features/',
        'https://www.forbes.com/sites/johnarcher/2020/02/12/netflix-and-samsung-reveal-controversial-exclusive-content-deal/',
        'https://www.forbes.com/sites/jamiecartereurope/2020/02/12/voyager-1s-iconic-pale-blue-dot-photo-is-30-years-old-so-nasa-made-a-new-one/',
        'https://www.forbes.com/sites/daveywinder/2020/02/13/love-is-not-getting-catfished-creeped-or-scammed-this-valentines-day/',
        'https://www.forbes.com/sites/daveywinder/2020/02/12/cia-secretly-bought-global-encryption-provider-built-backdoors-spied-on-100-foreign-governments/',
        'https://www.forbes.com/sites/kateoflahertyuk/2020/02/12/apple-just-made-a-striking-new-security-move-that-could-impact-all-users/',
        'https://www.forbes.com/sites/csylt/2020/02/12/london-to-get-worlds-first-batman-themed-restaurant/',
        'https://www.forbes.com/sites/davidnikel/2020/02/13/is-anything-truly-scandinavian-the-bizarre-sas-ad-controversy-explained/',
        'https://www.forbes.com/sites/ceciliarodriguez/2020/02/13/wildlife-photographer-of-the-year-peoples-choice-winning-images-released/',
        'https://www.forbes.com/sites/davidphelan/2020/02/12/apple-to-launch-surprise-new-airpods-pro-in-months-report-says/',
        'https://www.forbes.com/sites/davidphelan/2020/02/11/why-apple-ios-1331-matters-iphone-u1-tracking-fix-screen-time/'
    ] * 50
    start_time = time.time()
    asyncio.get_event_loop().run_until_complete(get_all_links(pages))
    duration = time.time() - start_time
    print(f'Downloaded {len(pages)} pages in {duration} seconds!')

Сразу же я столкнулся с несколькими проблемами:

  1. print делает не работает с get_link, поэтому у меня нет возможности проверить, действительно ли он работает так, как нужно, или нет.

  2. Я не могу понять, как вернуть данные из get_link и get_all_links к моей основной программе. В этом конкретном случае c как мне получить все данные из internal_links в get_link, чтобы я мог продолжить их обработку в main?

  3. Я не могу понять, как правильно используйте прокси и заголовки, когда дело доходит до асинхронного решения. Это было легко с пошаговым решением. Я мог бы просто использовать proxyscrape и получить рабочий прокси для каждой requests.get строки. Здесь я не уверен, как реализовать прокси и user-agent.

  4. Я не могу понять, как правильно написать try-исключение, кроме как в этом случае и как получить ошибки процесса, указанные c такие как TooManyRedirects, ProxyError, et c.

  5. Я не могу понять, что именно означают async with и async def. Мол, это очевидно на более высоком уровне, но что на самом деле происходит, когда мы пишем async до def и with?

Не могли бы вы, ребята, пожалуйста, помогите мне с вопросами выше

...