Как улучшить вложенные циклы в Python

232 просмотра
0
0 Комментариев

Доброго дня.
С питоном дружу совсем недавно. И ввязался в парсинг сайта. У сайта есть таблица несколько колонок и несколько строк. Нужно обойти все строки и колонки и вывести их как надо. И не придумал ничего лучшего кроме как вложенного цикла. Но чую душой и сердцем что в таком замечательном языке как Python можно сделать это куда более красивее. Подскажите пожалуйста, ну или хотя бы намекните, в какую сторону думать? Я из каждой строки исходных данных получаю то что мне надо и потом уже буду их обрабатывать как нужно.

from bs4 import BeautifulSoup
import requests
 
def startGrab():
    url = 'http:/site.net'
 
    try:
        page = requests.get(url)
    except:
        print(url)
 
    soup = BeautifulSoup(page.content, "html5lib")
 
    for row in soup.find_all("tr", {"class" : "belowHeader"}):
        i = 0
        x = 0
        for row2 in row.find_all("td", {"class" : "tdteamname2"}):
            if i==0:
                team1 = row2.get_text()
            else:
                team2 = row2.get_text()
            i += 1
        for row3 in row.find_all("td", {"class" : "tdpercentmw1"}):
            if x == 0:
                coef1 = row3.get_text()
            elif x == 1:
                coef2 = row3.get_text()
            else:
                coef3 = row3.get_text()
            x += 1
        print(team1+" "+team2+" "+coef1+" "+coef2+" "+coef3)
 
if __name__ == '__main__':
    startGrab()


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

1 Ответы

Python Опубликовано 12.12.2018
0

Построчные комментарии к коду:

Поиск элемента по имени элемента и его класса

Вместо:

soup.find_all("tr", {"class" : "belowHeader"})

Можно просто:

soup.find_all("tr", "belowHeader")

Используйте enumerate() чтобы индекс цикла получить

Вместо:

i = 0
for td in tr.find_all('td', 'tdteamname2'):
    ...
    i += 1

Следует писать:

for i, td in enumerate(row.find_all('td', 'tdteamname2')):
    ...

Можно использовать имена элементов tr, td вместо row, row1, row2

Используйте явные коллекции вместо имён с номерами

Вместо:

x = 0
for row3 in row.find_all("td", {"class" : "tdpercentmw1"}):
    if x == 0:
        coef1 = row3.get_text()
    elif x == 1:
        coef2 = row3.get_text()
    else:
        coef3 = row3.get_text()
    x += 1

Используйте:

coef = [td.get_text() for td in tr.find_all('td', 'tdpercentmw1')]

Аналогично для team:

team = [td.get_text() for td in tr.find_all('td', 'tdteamname2')]

[опционально] Можно использовать print(*коллекция)

Вместо:

print(team1+" "+team2+" "+coef1+" "+coef2+" "+coef3)

Можно написать:

print(*team, *coef)

Передавайте кодировку, если она известна из http-заголовков

Вместо:

soup = BeautifulSoup(page.content, "html5lib")

Можно писать:

soup = BeautifulSoup(page.content, "html5lib", from_encoding=page.encoding)

[опционально] используйте stdlib если нет причин к обратному

К примеру, если c разметкой особых проблем нет, то можно 'html.parser' вместо 'html5lib' парсер использовать.

Или если в вашем случае достаточно возможностей, urlopen(), то можно не использовать requests—это может быть менее безопасно (requests чаще обновляется), но и баги более стабильные.

Не используйте чистый (bare) except:

В вашем случае, можно позволить скрипту просто умереть, так как если страница не загружена, то ему нечего делать. Можно перехватить ожидаемые типы исключений и завершиться с информативным сообщением об ошибке (по опыту использования ясно какие типы ожидать, например, можно с OSError начать). Слишком много не ловите, чтобы баги в коде не скрывать.

Чтобы в консоль не мусорить, можно sys.excepthook свой установить.

Используйте shebang #! для исполняемых модулей

Если собрать весь код в одно место:

#!/usr/bin/env python3
from urllib.request import urlopen
from bs4 import BeautifoulSoup  # $ pip install beautifulsoup4
 
soup = BeautifulSoup(urlopen('http://example.com'), 'html.parser')
for tr in soup.find_all('tr', 'belowHeader'):
    team = (td.get_text() for td in tr.find_all('td', 'tdteamname2'))
    coef = (td.get_text() for td in tr.find_all('td', 'tdpercentmw1'))
    print(*team, *coef)

Если проблемы с кодировкой возникнут, то можно response.headers.get_content_charset(default) передать в качестве from_encoding параметра.

Если проблемы с быстродействием распознавания html (не загрузки), то можно попробовать 'lxml' парсер, вместо 'html.parser'.

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

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up