Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 22, 2019 01:00:56

barbiturat
Зарегистрирован: 2019-09-22
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема со словарем

Здравствуйте.

Пишу парсер. Нужно сохранять результат в 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 по умолчанию?

Отредактировано barbiturat (Сен. 22, 2019 01:08:05)

Офлайн

#2 Сен. 22, 2019 01:40:55

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Проблема со словарем

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')



Отредактировано FishHook (Сен. 22, 2019 01:41:24)

Офлайн

#3 Сен. 22, 2019 16:12:32

barbiturat
Зарегистрирован: 2019-09-22
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема со словарем

FishHook,
Я сначала беру url из словаря, чтобы спарсить первую страницу. А тут

 url = soup.find('ul', class_='ipsPagination').find('li', class_='ipsPagination_next').find('a').get('href')
получаю ссылку на следующую страницу пагинации и перезаписываю переменную url.

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

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

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

Отредактировано barbiturat (Сен. 22, 2019 16:22:30)

Офлайн

#4 Сен. 22, 2019 16:26:34

barbiturat
Зарегистрирован: 2019-09-22
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема со словарем

Сам спросил, сам ответил Так надо:

 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

Офлайн

#5 Сен. 22, 2019 17:50:28

barbiturat
Зарегистрирован: 2019-09-22
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема со словарем

В общем, теперь все работает.

 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',}

Отредактировано barbiturat (Сен. 22, 2019 17:53:04)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version