Найти - Пользователи
Полная версия: Проблема со словарем
Начало » Python для новичков » Проблема со словарем
1
barbiturat
Здравствуйте.

Пишу парсер. Нужно сохранять результат в csv файл в виде:
вопрос;категория.

Создал словарь urls в функции main.

 import requests
from bs4 import BeautifulSoup
import csv
import re
def get_html(url):
    r = requests.get(url)
    return r.text
# Преобразуем строку в нижний регистр
def cleaner(data):
    s = data.lower()
    return s
def write_csv(data):
    with open('zonazakona.csv', 'a') as f:
        order = ['question', 'cat']
        writer = csv.DictWriter(f, fieldnames=order, delimiter=';')
        writer.writerow(data)
# Делаем предложения с большой буквы
def uppercase(matchobj):
    return matchobj.group(0).upper()
def capitalize(s):
    return re.sub('^([а-я])|[\.|\?|\!]\s*([а-я])|\s+([а-я])(?=\.)', uppercase, s)
def main():
    urls = {'https://www.zonazakona.ru/forum/forum/28-obschie-voprosy-po-zhilischnomu-pravu/': 'Жилищное право',
            'https://www.zonazakona.ru/forum/forum/27-forum-po-semeynomu-pravu/': 'Семейное право'}
    for url in urls.keys():
        while True:
            html = get_html(url)
            soup = BeautifulSoup(html, 'lxml')
            lis = soup.find('ol', class_='ipsDataList').find_all('li', class_='ipsDataItem')
            for li in lis:
                unclean_question = li.find('div', class_='ipsDataItem_main').find('span', class_='ipsType_break').find('a').text.strip()
                question = capitalize(cleaner(unclean_question))
                cat = urls[url]
                data = {'question': question, 'cat': cat}
                # Если количество слов 4 и выше, то записываем вопрос в csv
                if len(question.split()) > 3:
                    write_csv(data)
            try:
                url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
            except:
                break
if __name__ == '__main__':
    main()

В блоке
 try:
                url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
            except:
                break
нахожу ссылку на следующую страницу. И питон пытается в ней получить значение ключа словаря
 cat = urls[url]

Ошибка:
Traceback (most recent call last):
File "/home/mjeday/Рабочий стол/python/zonazakona/main.py", line 72, in <module>
main()
File "/home/mjeday/Рабочий стол/python/zonazakona/main.py", line 58, in main
cat = urls[url]
KeyError: 'https://www.zonazakona.ru/forum/forum/28-obschie-voprosy-po-zhilischnomu-pravu/page/2/'

Не могу понять, как сделать, чтобы в этом блоке питон не искал этот ключ словаря, а оставлял значение переменной cat по умолчанию?
FishHook
barbiturat
barbiturat
try:
url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
except:
break
в этом блоке вы перехватываете ВСЕ исключения, ваш трейсбек не может быть из этого места.

вот это
cat = urls[url]
у вас по коду выше, чем блок try в котором вы объявлете переменную url. Нижестоящий блок не может определять вышестоящий.

ваша ошибка в том, что у вас счетчик цикла

for url in urls.keys():
объявлен так же как локальная переменная цикла
url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
barbiturat
FishHook,
Я сначала беру url из словаря, чтобы спарсить первую страницу. А тут
 url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
получаю ссылку на следующую страницу пагинации и перезаписываю переменную url.

Проверка нужна для того чтобы пока ссылка на страницу “Далее” есть цикл выполнялся.

То есть переменную url мне перезаписывать надо, но переменную cat надо оставить ту, которая на первой итерации цикла while.

Может быть, какой-то другой способ есть как сделать? Просто язык несколько дней как начал изучать, все что придумал - это со словарем. Но может какие-то другие варианты посоветуете?
barbiturat
Сам спросил, сам ответил Так надо:

 def main():
    urls = {'https://www.zonazakona.ru/forum/forum/28-obschie-voprosy-po-zhilischnomu-pravu/': 'Жилищное право',
            'https://www.zonazakona.ru/forum/forum/27-forum-po-semeynomu-pravu/': 'Семейное право'}
    for url in urls.keys():
        cat = urls[url]
        while True:
            html = get_html(url)
            soup = BeautifulSoup(html, 'lxml')
            lis = soup.find('ol', class_='ipsDataList').find_all('li', class_='ipsDataItem')
            for li in lis:
                unclean_question = li.find('div', class_='ipsDataItem_main').find('span', class_='ipsType_break').find('a').text.strip()
                question = capitalize(cleaner(unclean_question))
                data = {'question': question, 'cat': cat}
                # Если количество слов 4 и выше, то записываем вопрос в csv
                if len(question.split()) > 3:
                    write_csv(data)
            try:
                url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
            except:
                break
barbiturat
В общем, теперь все работает.

 def main():
    urls = {'https://www.zonazakona.ru/forum/forum/28-obschie-voprosy-po-zhilischnomu-pravu/': 'Жилищное право',
            'https://www.zonazakona.ru/forum/forum/27-forum-po-semeynomu-pravu/': 'Семейное право'}
    for url in urls.keys():
        cat = urls[url]
        while True:
            html = get_html(url)
            soup = BeautifulSoup(html, 'lxml')
            lis = soup.find('ol', class_='ipsDataList').find_all('li', class_='ipsDataItem')
            for li in lis:
                unclean_question = li.find('div', class_='ipsDataItem_main').find('span', class_='ipsType_break').find('a').text.strip()
                question = capitalize(cleaner(unclean_question))
                data = {'question': question, 'cat': cat}
                # Если количество слов 4 и выше, то записываем вопрос в csv
                if len(question.split()) > 3:
                    write_csv(data)
            # Проверяем, есть ли ссылка "Вперёд"
            pattern = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').get('class')
            s_pattern = ' '.join(pattern) # Преобразуем список в строку
            if s_pattern == 'ipsPagination_next ipsPagination_inactive':
                break
            url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')

Интересно, а если бы мне надо было записывать не 2 значения из словаря, а 3 и больше, то как тогда быть? В словаре же только пара ключ:значение. Как мне сопоставить чт-то типа:
 {'url': 'cat': '1', 'url2': 'cat2': '2', 'url3': 'cat3': '3',}
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB