Как ускорить сканирование с помощью комбинации Request и BeautifulSoup в Python? - PullRequest
0 голосов
/ 12 июля 2020

Цель состоит в том, чтобы очистить несколько страниц , используя BeautifulSoup, данные которых поступают из модуля requests.get.

Шаги:

Сначала загрузите html с использованием requests

page = requests.get('https://oatd.org/oatd/' + url_to_pass)

Затем очистите содержимое html, используя определение ниже:

def get_each_page(page_soup):
    return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                paper_title=page_soup.find(attrs={"itemprop": "name"}).text)

Скажем, у нас есть сотня уникальных URL-адресов, которые нужно удалить ['record?record=handle\:11012\%2F16478&q=eeg'] * 100, весь процесс может быть завершен с помощью кода ниже:

import requests
from bs4 import BeautifulSoup as Soup

def get_each_page(page_soup):
    return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                paper_title=page_soup.find(attrs={"itemprop": "name"}).text)

list_of_url = ['record?record=handle\:11012\%2F16478&q=eeg'] * 100 # In practice, there will be 100 diffrent unique sub-href. But for illustration purpose, we purposely duplicate the url
all_website_scrape = []
for url_to_pass in list_of_url:

    page = requests.get('https://oatd.org/oatd/' + url_to_pass)
    if page.status_code == 200:
        all_website_scrape.append(get_each_page(Soup(page.text, 'html.parser')))

Однако каждый URL-адрес запрашивается и очищается каждый раз, что в принципе требует времени.

Интересно, есть ли другой способ повысить производительность приведенного выше кода, о котором я не знаю?

Ответы [ 2 ]

1 голос
/ 12 июля 2020

real python .com имеет хорошую статью об ускорении python скриптов с одновременным выполнением.

https://realpython.com/python-concurrency/

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

    from bs4 import BeautifulSoup as Soup
    import concurrent.futures
    import requests
    import threading
    import time
    
    def get_each_page(page_soup):
        return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                    paper_title=page_soup.find(attrs={"itemprop": "name"}).text)
    
    def get_session():
        if not hasattr(thread_local, "session"):
            thread_local.session = requests.Session()
        return thread_local.session
    
    def download_site(url_to_pass):
        session = get_session()
        page = session.get('https://oatd.org/oatd/' + url_to_pass, timeout=10)
        print(f"{page.status_code}: {page.reason}")
        if page.status_code == 200:
            all_website_scrape.append(get_each_page(Soup(page.text, 'html.parser')))
    
    def download_all_sites(sites):
        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            executor.map(download_site, sites)
    
    if __name__ == "__main__":
        list_of_url = ['record?record=handle\:11012\%2F16478&q=eeg'] * 100  # In practice, there will be 100 diffrent unique sub-href. But for illustration purpose, we purposely duplicate the url
        all_website_scrape = []
        thread_local = threading.local()
        start_time = time.time()
        download_all_sites(list_of_url)
        duration = time.time() - start_time
        print(f"Downloaded {len(all_website_scrape)} in {duration} seconds")
0 голосов
/ 12 июля 2020

Возможно, вы сможете использовать модуль потоковой передачи. Вы можете сделать скрипт многопоточным и go намного быстрее. https://docs.python.org/3/library/threading.html

Но если вы хотите изменить свое мнение, я рекомендую scrapy

...