Зацикливание при парсинге википедии

Задача спарсить названия животных и вывести общее количество животных на каждую букву.

import requests
from bs4 import BeautifulSoup

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.143 YaBrowser/22.5.0.1884 Yowser/2.5 Safari/537.36"
}
url = 'https://ru.wikipedia.org/wiki/Категория:Животные_по_алфавиту'

req = requests.get(url, headers=headers).text

while True:
    soup = BeautifulSoup(req, 'lxml')

    block = soup.find('div', class_='mw-category mw-category-columns')
    category_letter = block.find('div', class_='mw-category-group')
    category = category_letter.find_next('h3').text
    animal_names = block.find_all('li')

    animals_names = []
    for animal in animal_names:
        animal_name = animal.text
        animals_names.append(animal_name)

    names = 0
    for name in animals_names:
        if name.startswith(category):
            names += 1
    names_dict = {}
    names_dict.update({category: names})

    order = {}
    for key in names_dict:
        try:
            order[key] += int(names_dict[key])
        except:
            order[key] = int(names_dict[key])

    for key, value in order.items():
        print(key, value)

    links = soup.find('div', id='mw-pages').find_all('a')
    for a in links:
        if a.text == 'Следующая страница':
            url = 'https://ru.wikipedia.org/' + a.get('href')
            req = requests.get(url).text

Ошибка в том, что на букве Z код зацикливается, как исправить?


Ответы (2 шт):

Автор решения: CrazyElf

Чтобы не зацикливалось нужно прерывать цикл:

    for a in links:
        if a.text == 'Следующая страница':
            url = 'https://ru.wikipedia.org/' + a.get('href')
            req = requests.get(url).text
            break # нужен для правильной работы else
    else:
        break # прерывает цикл while

К вашему коду добавлены в конце мои три строчки:

  • чтобы правильно сработало else у цикла for нужен break внутри for, ну он в любом случае там нужен для оптимизации - если вы уже нашли ссылку на следующую страницу, то перебирать страницы дальше нет смысла
  • Ну и второй break, который в else, прерывает цикл while в случае, если не найдена ссылка на следующую страницу
→ Ссылка
Автор решения: Сергей Ш
import requests
from bs4 import BeautifulSoup

url = 'https://ru.wikipedia.org/wiki/Категория:Животные_по_алфавиту'

names_dict = {}
while True:
    req = requests.get(url)

    soup = BeautifulSoup(req.text, 'lxml')
    fragment = soup.find('div', id='mw-pages')

    for nam in fragment.find_all('div', class_='mw-category-group'):
        category = nam.h3.text
        animal_names = [[x.text, f"https://ru.wikipedia.org{x.a['href']}"] for x in nam.find_all('li')]
        if not names_dict.get(category):
            names_dict[category] = []
        names_dict[category] = names_dict[category] + animal_names

    hrf = fragment.find_all('a')[-1]
    # *_, tmp = soup.find('div', id='mw-pages').find_all('a')
    url = f"https://ru.wikipedia.org{hrf['href']}"
    if hrf.text != 'Следующая страница':
        break

# выводим количество запмсей на букву
for x, y in names_dict.items():
    print(x, len(y))

# выводим название и ссылку по букве 'Й'
for name, link in names_dict['Й']:
    print(name)
    print(link)
→ Ссылка