Мой код в настоящее время:
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 ответ
Несколько быстрых комментариев. Поскольку ваш запрос касается удобочитаемости, вы можете сделать как минимум три вещи:
- избавьтесь от неиспользуемых переменных, например:
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 имеет другое поведение и вернет пустой список, если соответствующий элемент не найден.
