Дублирующиеся данные в результате парсинга

Рейтинг: 0Ответов: 1Опубликовано: 28.03.2023

Вот здесь, собственно, и был написан код.

import json
import codecs
import re
import time
from urllib.parse import quote, unquote
from urllib.request import urlopen 
import requests
from bs4 import BeautifulSoup
from sys import getdefaultencoding
import yaml
import requests
import bleach

url = "https://fasie.ru"
page = urlopen(url)
html = page.read().decode("utf-8")
soup = BeautifulSoup(html, "html.parser")
div = soup.find_all('div', class_ = 'wrap')
programms_list = div[1].find('ul', class_='').find_all('ul', class_='')[1]
hrefs = programms_list.find_all('a')
download_links = set()
response = requests.get(url+'/programs')
parse_text = BeautifulSoup(response.text, 'html.parser')
links = set([x.get('href') for x in parse_text.find_all(href=re.compile('^/programs/'))])
programs = []

def main():
    for h in hrefs:
        program = {}
        url_h = f"https://fasie.ru{h.get('href')}"
        page_h = urlopen(url_h)
        html_h = page_h.read().decode("utf-8")
        soup_h = BeautifulSoup(html_h, "html.parser")
        soup_b = BeautifulSoup(html_h, 'lxml')
        description = soup_h.find('section', {'id': 'content-tab3'})
        program['source'] = url_h
        program['name'] = h.text.strip()
        program['description'] = description.text.strip().replace('\n', '').replace('\t', '').replace('\r', '') if description else ''
        program['program'] = str(soup_h.find('section', {'id': 'content-tab1'}).get_text()).replace('\n', ' ').replace('\t', ' ').replace('\r', ' ')
        try:
            notag = soup_b.find('div', class_='tabs').find('section', id='content-tab5').find_all('tr') 
        except AttributeError:
            notag = soup_b.find('div', class_='tabs').find('section', id='content-tab4').find_all('p')
        for n in notag:
            nams = []
            tels = []
            emails = []
            contacts = []
            contact = {}
            try:
                nam=[i.text.replace('\n', ' ').replace('\t', ' ').replace('\r', ' ').replace(u'\xa0', u' ').replace('   ', '') for i in n.find_all('h4')]
                if nam==[]:
                    nam=[i.text.replace('\n', ' ').replace('\t', ' ').replace('\r', ' ').replace(u'\xa0', u' ').replace('   ', '') for i in n.find_all('b')]
                for i in nam:
                    if i==' ':
                        pass
                    else:
                        nams.append(i)
                email = n.find('a').text.replace('\n', ' ').replace('\t', ' ').replace('\r', ' ').replace(' ', '')
                if email=='':
                    pass
                else:
                    emails.append(email)
                tel = [i.text.replace('\n', ' ').replace('\t', ' ').replace('\r', ' ').replace(u'\xa0', u' ').replace('   ', '') for i in n.find_all('nobr')]
                if tel==[]:
                    tel=[i.text.replace('\n', ' ').replace('\t', ' ').replace('\r', ' ').replace(u'\xa0', u' ').replace('   ', '') for i in n.find_all('td')]
                for i in tel:
                    if i=='':
                        pass
                    else:
                        tels.append(i)
            except AttributeError:
                pass
        contact['namе'] = nams
        contact['email'] = emails
        contact['tel'] = tels
        contacts.append(contact)
        program['contacts'] = contacts
            

        sections = soup_h.find_all('section')
        documents = []
        for s in sections:
            download_links.update(set([x.get('href') for x in s.find_all(href=re.compile('^/upload/docs'))]))
        for link in download_links:
            file_name = unquote(link).replace('%20', '').split('/')[-1]
            response = requests.get(url+quote(link))
            with open(file_name, 'wb') as f:
                f.write(response.content)
            document = {}
            document['source'] = url+link.replace('%20', ' ')
            document['path'] = file_name
            document['name'] = file_name
            document['extension'] = file_name.split('.')[-1]
            document['size'] = len(response.content)
            documents.append(document)
        program['documents'] = documents
        programs.append(program)
    with open('output.json', 'w', encoding="utf-8") as f:
        f.write(json.dumps(programs, indent=2, ensure_ascii=False))

main()

Заметил одну странность. Когда выводится в JSON, некоторые из контактов, взятых с каждого раздела "#kontaktu", дублируются. При том, что в разделе, откуда они извлечены, всего один контакт. Но почему-то несколько контактов из остальных разделов, где их несколько, не выводится в том же количестве, откуда взяты. Только один контакт. Привожу отрывок кода.

{
    "source": "https://fasie.ru/programs/programma-studstartup/",
    "name": "Студенческий стартап",
    "description": "Первая очередь приема заявок проходила с 22.02.2022 по 11.04.2022. Вторая очередь приема заявок проходила с 17.05.2022 по 15.07.2022. Третья очередь приема заявок проходит с 26.01.2023 по 03.04.2023.",
    "program": "     Программа направлена на выполнение работ студентами по разработке новых товаров, изделий, технологий или услуг с использованием результатов собственных научно-технических и технологических исследований, имеющих потенциал коммерциализации и находящихся на самой ранней стадии развития.    Принимать участие в конкурсе по данной программе могут физические лица, являющиеся гражданами РФ и обучающиеся в образовательных организациях высшего образования Российской Федерации по программам бакалавриата, специалитета, магистратуры или аспирантуры, не имеющие действующих договоров с Фондом (за исключением грантополучателей второго года программы «УМНИК»).    Параметры поддержки:          размер гранта – 1 млн рублей;             срок выполнения НИР – 12 месяцев (1 этап – 2 месяца, 2 этап – 10 месяцев);                     Направления программы:            Н1. Цифровые технологии;           Н2. Медицина и технологии здоровьесбережения;           Н3. Новые материалы и химические технологии;           Н4. Новые приборы и интеллектуальные производственные технологии;           Н5. Биотехнологии;           Н6. Ресурсосберегающая энергетика.           Н7. Креативные индустрии.           Ожидаемые результаты:              создано юридическое лицо, где доля грантополучателя в уставном капитале составляет более 50% и он является генеральным директором,           разработан бизнес-план инновационного проекта;           разработан сайт стартапа;           представлен отчет о развитии стартапа.           При невыполнении очередного этапа Работ, а также при отсутствии подтверждения целевого использования средств гранта Фонд вправе потребовать возврата средств гранта.       Подробная информация о программе представлена в разделе «Документы».   ",
    "contacts": [
      {
        "namе": [
          "ПОЗДНЯКОВА ЕЛЕНА НИКОЛАЕВНА"
        ],
        "email": [
          "pozdnyakova.en@fasie.ru"
        ],
        "tel": [
          "  ПОЗДНЯКОВА ЕЛЕНА НИКОЛАЕВНАГлавный специалист отдела молодежных инновационных программ и проектов  ",
          " (495) 249-249-2 доб.184  ",
          " pozdnyakova.en@fasie.ru  "
        ]
      },
      {
        "namе": [
          "ПОЗДНЯКОВА ЕЛЕНА НИКОЛАЕВНА"
        ],
        "email": [
          "pozdnyakova.en@fasie.ru"
        ],
        "tel": [
          "  ПОЗДНЯКОВА ЕЛЕНА НИКОЛАЕВНАГлавный специалист отдела молодежных инновационных программ и проектов  ",
          " (495) 249-249-2 доб.184  ",
          " pozdnyakova.en@fasie.ru  "
        ]
      }
    ], 

Как решить эту проблему?

Вот как должен выглядеть сам JSON

[
  {
    "source": "Ссылка, откуда взята информация", // в данном случае ссылка fasie.ru
    "name": "ИнноШкольник",
    "description": "Информация из вкладки `О программе`",
    "program": "Данные из вкладки `Конкурсы, программы` в формате HTML",
    "contacts": [
      {
        "name": "Имя контакта",
        "tel": "Телефон",
        "email": "Почта контакта"
      }
    ],
    "documents": [
      {
        "source": "Ссылка на файл оригинальная, т.е откуда скачали",
        "path": "Относительный путь к файлу (уже скачанного)",
        "name": "Название файла",
        "extension": "Расширение файла (напр. pdf)",
        "size": 123 // Размер в байтах
      }
    ]
  }
]

Ответы

▲ 1Принят

Попробуйте вот так как нибудь

from requests import Session
from pprint import pp
from unicodedata import normalize
from bs4 import BeautifulSoup as Soup

if __name__ == '__main__':
    ss = Session()
    response = ss.get('https://fasie.ru/programs/programma-studstartup')

    soup = Soup(response.content, 'html.parser')

    contacts_tab = soup.find(id='content-tab5')

    contacts = []
    for item in contacts_tab.find_all('tr'):
        contacts.append(
            dict(
                zip(
                    ('name', 'position', 'phone', 'email'),
                    map(lambda x: normalize('NFKC', x), item.stripped_strings)
                )
            )
        )
    pp(
        contacts
    )

[{'name': 'ПОЗДНЯКОВА ЕЛЕНА НИКОЛАЕВНА',
  'position': 'Главный специалист отдела молодежных инновационных программ и '
              'проектов',
  'phone': '(495) 249-249-2 доб.184',
  'email': 'pozdnyakova.en@fasie.ru'}]

Вывод с url https://fasie.ru/programs/programma-umnik:

[{'name': 'Полянов Всеволод Игоревич',
  'position': 'Руководитель группы «УМНИК»/куратор отборов по НТИ и '
              'партнерским конкурсам',
  'phone': '(495) 249-249-2 доб.106',
  'email': 'polyanov.vi@fasie.ru'},
 {'name': 'Нечаева Виктория Леоноровна',
  'position': 'Куратор по Москве, СКФО, СЗФО, СФО, УФО и ДФО',
  'phone': '(495) 249-249-2 доб.224',
  'email': 'nechaeva.vl@fasie.ru'},
 {'name': 'Киселев Виталий Юрьевич',
  'position': 'Куратор по ЦФО (кроме Москвы), ПФО, ЮФО и отборам в рамках '
              '"Цифровой экономики"',
  'phone': '(495) 249-249-2 доб.189',
  'email': 'kiselev.vyu@fasie.ru'}]