urllib2 / BeautifulSoup для извлечения одной страницы кажется медленным - PullRequest
1 голос
/ 07 марта 2020

Я учусь извлекать данные из Интернета. Для этого я использую python 2.7, urllib2 и BeautifulSoup (используя python2 .7, потому что это версия, которую я использую на работе, поэтому не хочу смешивать синтаксисы ...)

На данный момент у меня есть унитарный тест, который просто выбирает одну страницу, чтобы получить некоторую информацию

Исходный URL: https://www.basketball-reference.com/teams/TOR/2019.html

Я получаю название команды, год, тренер и запись на данный момент.

У меня нет опыта загрузки веб-страниц, но мне не терпится просто выбрать одну страницу.

У меня время

D:\miniconda3\envs\tes1\python.exe C:/Users/my_name/PycharmProjects/testing/web_scraping/bb_ref/my_test_web_classes.py
urlopen in 1.4240 secs
generate res in 2.8070 secs
Finished get_page in 4.2310 secs
Finished get_team_info in 0.0000 secs
Team: Toronto Raptors   Coach: Nick Nurse   Year: 2018-19   Record: 58-24   
Process finished with exit code 0

Мы видим, сколько времени уходит на получение информации. Мой тест

from web_classes import WebPage
from bb_ref_team import Team


page_bs = WebPage.get_page('https://www.basketball-reference.com/teams/TOR/2019.html', output='bs')
team_info = Team.get_team_info(page_bs)
team = Team(name=team_info['team'],
            coach=team_info['coach'],
            year=team_info['year'],
            record=team_info['record'])
print team

Класс, получающий страницу:

from bs4 import BeautifulSoup
from urllib2 import urlopen
from urllib2 import HTTPError
from urllib2 import URLError
from decorators import timer
import time


class WebPage:
    def __init__(self, url):
        self.url = url

    @staticmethod
    @timer
    def get_page(url, output='text'):
        try:
            start_time = time.time()
            html = urlopen(url)
            run_time = time.time() - start_time
            print ' urlopen in {:.4f} secs'.format(run_time)
        except HTTPError as e:
            print e
            return None
        except URLError as e:
            print e
            return None
        else:
            if output == 'text':
                start_time = time.time()
                res = html.read()
                run_time = time.time() - start_time
                print ' generate res in {:.4f} secs'.format(run_time)
                return res
            elif output == 'bs':
                start_time = time.time()
                res = BeautifulSoup(html, 'html.parser')
                run_time = time.time() - start_time
                print ' generate res in {:.4f} secs'.format(run_time)
                return res

Класс разбора экземпляра BeautifulSoup для создания моего экземпляра Team:

from bb_ref_data import Data
from decorators import timer
import re


class Team(Data):
    def __init__(self, name, coach, year, record):
        super(Team, self).__init__()
        self.data['year'] = year
        self.data['name'] = name
        self.data['coach'] = coach
        self.data['record'] = record  # win_game-lost_game

    def __str__(self):
        return "Team: %s\tCoach: %s\tYear: %s\tRecord: %s\t" % (self.data['name'],
                                                                self.data['coach'],
                                                                self.data['year'],
                                                                self.data['record'])

    @staticmethod
    @timer
    def get_team_info(page):
        """
        return team page information
        :param page: BeautifulSoup page object
        :return:
        """
        summary = page.find('div', {'data-template': 'Partials/Teams/Summary'})
        title = summary.h1.find_all('span')
        year = title[0].get_text()
        team = title[1].get_text()
        infos = summary.find_all('p')
        rec = re.search(r'(\d+-\d+)', infos[0].get_text()).group()
        coach = re.search(r'Coach: (\w+( \w+)*)', infos[1].get_text()).group(1)
        return {'team': team, 'coach': coach, 'year': year, 'record': rec}

Класс команды наследует от класса ниже, который является просто словарем

class Data(object):
    def __init__(self):
        self.data = {}

    def __copy__(self):
        new = type(self)
        new.data = self.data.copy()
        return new

моя функция таймера декоратора:

def timer(func):
    """Print the runtime of the decorated function"""
    @functools.wraps(func)
    def wrapper_timer(*args, **kwargs):
        start_time = time.time()    # 1
        value = func(*args, **kwargs)
        end_time = time.time()      # 2
        run_time = end_time - start_time    # 3
        print "Finished {} in {:.4f} secs".format(func.__name__, run_time)
        return value
    return wrapper_timer

Это звучит долго для вас, так что потратьте почти 3 se c на генерацию объект BeautifulSoup, что я могу сделать, чтобы ускорить его?

Спасибо за ваш вклад

Хороших выходных

Примечание : I сделал небольшой тест BeautifulSoup против l xml, и последний показал лучшие сроки. Для каждого объекта я выполнил 100 унитарных тестов (urlopen + создание объекта, представляющего веб-страницу)

Для BeautifulSoup у меня есть

mean: 2.37027
std: 0.4379433948582853
var: 0.1917944171

Для l xml у меня есть

mean: 2.27229
std: 0.3342248433315513
var: 0.11170624589999999
...