Сбор игровых данных из Интернета

Мой код в настоящее время:

import os
import pandas as pd
from selenium import webdriver
from tabulate import tabulate
from datetime import datetime
import time
from bs4 import BeautifulSoup as bs

start = datetime.now()

browser = webdriver.Chrome()


class GameData:

    def __init__(self):
        self.date = []
        self.time = []
        self.game = []
        self.score = []
        self.home_odds = []
        self.draw_odds = []
        self.away_odds = []


def parse_data(url):
    browser.get(url)
    df = pd.read_html(browser.page_source, header=0)[0]
    time.sleep(3)
    html = browser.page_source
    soup = bs(html,"lxml")
    cont = soup.find('div', {'id':'wrap'})
    conti = cont.find('div', {'id':'col-content'})
    content = conti.find('table', {'class':'table-main'}, {'id':'tournamentTable'})
    main = content.find('th', {'class':'first2 tl'})
    count = main.findAll('a')
    country = count[1].text
    league = count[2].text
    game_data = GameData()
    game_date = None
    for row in df.itertuples():
        if not isinstance(row[1], str):
            continue
        elif ':' not in row[1]:
            game_date = row[1].split('-')[0]
            continue
        game_data.date.append(game_date)
        game_data.time.append(row[1])
        game_data.game.append(row[2])
        game_data.score.append(row[3])
        game_data.home_odds.append(row[4])
        game_data.draw_odds.append(row[5])
        game_data.away_odds.append(row[6])
    browser.quit()
    return game_data, country, league

# You can input as many URLs you want
urls = {
"https://www.oddsportal.com/soccer/europe/champions-league/results/"
}

if __name__ == '__main__':

    results = None

    for url in urls:
        game_data, country, competition = parse_data(url)
        result = pd.DataFrame(game_data.__dict__)
        result['country'] = country
        result['competition'] = competition
        if results is None:
            results = result
        else:
            results = results.append(result, ignore_index=True)


results

|    | date        | time   | game                                 | score   |   home_odds |   draw_odds |   away_odds | country   | competition      |
|----|-------------|--------|--------------------------------------|---------|-------------|-------------|-------------|-----------|------------------|
|  0 | 17 Mar 2021 | 20:00  | Bayern Munich - Lazio                | 2:1     |        1.35 |        6.02 |        7.53 | Europe    | Champions League |
|  1 | 17 Mar 2021 | 20:00  | Chelsea - Atl. Madrid                | 2:0     |        2.33 |        3.1  |        3.49 | Europe    | Champions League |
|  2 | 16 Mar 2021 | 20:00  | Manchester City - B. Monchengladbach | 2:0     |        1.28 |        6.25 |       10.17 | Europe    | Champions League |
|  3 | 16 Mar 2021 | 20:00  | Real Madrid - Atalanta               | 3:1     |        2.26 |        3.6  |        3.16 | Europe    | Champions League |
|  4 | 10 Mar 2021 | 20:00  | Liverpool - RB Leipzig               | 2:0     |        2.37 |        3.8  |        2.85 | Europe    | Champions League |

Как я могу улучшить читаемость этого кода?

Кроме того, поскольку CR просит пояснить, (моды могут удалить это)

1 ответ
1

Несколько быстрых комментариев. Поскольку ваш запрос касается удобочитаемости, вы можете сделать как минимум три вещи:

  • избавьтесь от неиспользуемых переменных, например: start = datetime.now()
  • улучшите соглашения об именах для ваших переменных: такие переменные, как cont или же conti are довольно похожи (риск опечаток / путаницы), но названия не интуитивно понятны и не точно описывают данные, которыми вы манипулируете. count также слишком общий, чтобы иметь смысл. Обратите внимание, что game_date выглядит очень похожим на game_data, и у вас даже есть строка: game_data.date.append(game_date). Я думаю, что риск ошибок опечаток здесь немалый.
  • добавьте межстрочный интервал здесь и там, а также несколько комментариев. Вы можете себе это позволить, поскольку код составляет менее 100 строк кода, поэтому реализация разумна и не раздута.

Я не думаю, что класс GameData действительно полезен в том виде, в каком он реализован. Чтобы получить окончательный результат для печати, вы можете придерживаться фрейма данных, он у вас уже есть, поэтому посмотрите, можно ли его преобразовать дальше или перенести на другой.

У тебя есть time.sleep после pd.read_html, но это не гарантирует, что страница будет полностью загружена. В Selenium есть несколько функций, которые можно использовать для ожидания присутствия заданного элемента. Но, возможно, вы могли бы вместо этого использовать модуль запросов. На сайтах, использующих JS / Ajax, у вас может не быть другого выбора, кроме как использовать Selenium, но для того, чтобы сделать это правильно, требуется больше усилий.

Хорошо бы добавить Проверка чтобы убедиться, что результат вашего соскоба не будет недействительным. В противном случае обработка будет неправильной и вернет мусор. BS find функция вернет None, если элемент не найден. Итак, все, что вам нужно сделать, это что-то вроде:

if None in (cont, conti, content, main):

или вы можете использовать any функция для этой цели. Тем не мение, findAll имеет другое поведение и вернет пустой список, если соответствующий элемент не найден.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *