Как я могу удалить идентификационные теги и их содержимое(текст) с веб-сайта?

#python #beautifulsoup #nlp

Вопрос:

В верхней части этого сайта находятся 17 идентификационных тегов:

 1.Boxed warning
2.Indications
3.Dosage/Administration
4.Dosage forms
5.Contraindications
6.Warnings/Precautions
7.Adverse reactions
8.Drug interactions
9.Specific populations
10.Overdosage
11.Description
12.Clinical pharmacology
13.Nonclinical toxicology
14.Clinical studies
15.How supplied
16.Patient counseling
17.Medication guide
 

Я хочу очистить страницу и создать словарь с этими тегами в качестве ключей. Как я могу это сделать? Вот что я пробовал до сих пор:

 urls = "https://www.drugs.com/pro/abacavir-lamivudine-and-zidovudine-tablets.html"
response = requests.get(urls)
soup = BeautifulSoup(response.text, 'html.parser')
data3 = soup.findAll('h2')
out = {}
y1 = []
y2 = []
for header in data3:
   x0 = header.get('id')
   y1.append(x0)
   nextNode = header
   while True:
      nextNode = nextNode.nextSibling
      if nextNode is None:
          break
      if isinstance(nextNode, NavigableString):
          x1 = nextNode.strip()
      if isinstance(nextNode, Tag):
          if nextNode.name == "h2":
              break

      x2 = nextNode.get_text(strip=True).strip()
      x3 = x1   " "   x2
      y2.append(x3)
 print(y1,y2)
 

Я получаю

 Output I'm Getting: [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None] [content]

Desired Output: ['boxed warning', 'indications', 'dosage/administration', 'dosage forms', 'contraindications', 'warnings/precautions', 'adverse reactions', 'drug interactions', 'specific populations', 'overdosage', 'description', 'clinical pharmacology', 'nonclinical toxicology', 'clinical studies', 'how supplied', 'patient counseling', 'medication guide'] ['content present under boxed warning', 'content present under indications']
 

Как я могу получить словарь или список, который заменяет все имена на список тегов? Я изо всех сил пытаюсь работать со структурой веб-страницы. Спасибо!

Комментарии:

1. Какой код вы уже пробовали?

2. @BLimitless я отредактировал вопрос и добавил код, который я пробовал. с нетерпением жду возможности услышать вас

3. Отлично, спасибо. Увидев ваш код, я, к сожалению, не знаю, как вам помочь. Но теперь я вижу, как изменить вопрос, чтобы вы получили некоторые ответы. Надеюсь, мое редактирование вопроса скоро пройдет, и тогда кто-то, кто лучше разбирается в веб-очистке, сможет вам помочь. Удачи!

4. Каков именно ваш ожидаемый результат? Например, если Boxed warning это ключ, то какова его ценность? Или вместо словаря это просто список всех тегов на странице?

5. @flameline Эй, у тебя есть ответы на некоторые вопросы! Рад, что это сработало. Продолжайте редактировать вопрос, чтобы сделать его более понятным, если ответы не дают вам того, чего вы хотите. Это был сложный первый вопрос для StackOverflow, так что продолжайте в том же духе. Здесь будет проще/быстрее получить помощь. Удачи! И не забудьте проголосовать/принять ответ, который подходит вам, чтобы сообщество знало, когда двигаться дальше (и другие люди с аналогичными вопросами в будущем знают, что они могут найти ответ здесь).

Ответ №1:

Я не уверен на 100%, что вам нужно, но, основываясь на комментариях, я думаю, что это то, что вы ищете. Вы можете легко добавить выходные данные в список или словарь.

 import requests
from bs4 import BeautifulSoup
urls = "https://www.drugs.com/pro/abacavir-lamivudine-and-zidovudine-tablets.html"
response = requests.get(urls)
soup = BeautifulSoup(response.text, 'html.parser')
tags = soup.find('div', {'class': 'ddc-anchor-links'})

available_information = []

for tag in tags.find_all('a'):
    available_information.append(tag.text)
    

print(available_information)
# output
['Boxed Warning', 'Indications and Usage', 'Dosage and Administration', 'Dosage Forms and Strengths', 'Contraindications', 'Warnings and Precautions', 'Adverse Reactions/Side Effects', 'Drug Interactions', 'Use In Specific Populations', 'Overdosage', 'Description', 'Clinical Pharmacology', 'Nonclinical Toxicology', 'Clinical Studies', 'How Supplied/Storage and Handling', 'Patient Counseling Information', 'Medication Guide']


 

Вы можете получить содержимое для каждого TOC, используя этот код:

 anchor_tags = []
soup = BeautifulSoup(response.text, 'html.parser')
tags = soup.find('div', {'class': 'ddc-toc-content'})
for tag in tags.find_all('a'):
    anchor_tag = str(tag['href']).replace('#', '')
    anchor_tags.append(anchor_tag)

for tag in anchor_tags:
    anchor_tag = soup.find("a", {"id": tag})
    header_tag = anchor_tag.find_next_sibling('h2')
    # now you need to figure out how you want to store this information that is being extracted. 
 

Основываясь на нашем разговоре в чате, вы можете запросить несколько страниц, которые имеют различную структуру таким образом. Вам придется изменить параметры поиска и известные теги по мере того, как вы будете очищать все больше страниц с различными структурами.

 import requests
from bs4 import BeautifulSoup

def get_soup(target_url):
    response = requests.get(target_url)
    soup = BeautifulSoup(response.text, 'html.parser')
    return soup

def obtain_toc_content(soup):
    available_information = []
    anchor_tags = []
    known_tags = ['div', 'ul']
    search_terms = ['ddc-toc-content', 'ddc-anchor-links']
    for tag, search_string in zip(known_tags, search_terms):
        tag_found = bool(soup.find(tag, {'class': search_string}))
        if tag_found:
            toc = soup.find(tag, {'class': search_string})
            for toc_tag in toc.find_all('a'):
                available_information.append(toc_tag.text)
                anchor_tag = str(toc_tag['href'])
                anchor_tags.append(anchor_tag)

    return available_information, anchor_tags


urls = ['https://www.drugs.com/pro/abacavir-lamivudine-and-zidovudine-tablets.html',
        'https://www.drugs.com/ajovy.html','https://www.drugs.com/cons/a-b-otic.html']
for url in urls:
    make_soup = get_soup(url)
    results = obtain_toc_content(make_soup)
    table_of_content = results[0]
    toc_tags = results[1]
       
 

Комментарии:

1. Желаемый результат: [«коробочное предупреждение», «показания», «дозировка/применение», «лекарственные формы», «противопоказания», «предупреждения/меры предосторожности», «побочные реакции», «лекарственные взаимодействия», «конкретные группы населения», «передозировка», «описание», «клиническая фармакология», «неклиническая токсикология», «клинические исследования», «как поставлено», «консультирование пациентов», «руководство по лекарствам»] [«содержимое, представленное в коробочном предупреждении», «содержимое, представленное по показаниям»]

2. Я добавил элементы в список. Я не вижу «содержимое, представленное в соответствии с указаниями» или «содержимое, представленное в соответствии с указаниями» на странице?

3. В URL-адресе, если вы нажмете на «Описание», вы попадете в заголовок «Описание таблеток Абакавира, Ламивудина и зидовудина» на странице. Мне также нужен контент под этим заголовком до следующего раздела «Таблетки Абакавира, Ламивудина и Зидовудина — Клиническая фармакология».

4. Итак, вам нужен только текст в разделе «Описание» или вам нужен весь текст для всех элементов TOC?

5. Мне нужен текст для всех элементов TOC

Ответ №2:

Приведенный ниже код должен приблизить вас, по крайней мере, к тому месту, куда, по моему мнению, вы хотите попасть. Я постараюсь объяснить как можно больше по дороге, но вам еще многому предстоит научиться:

 import lxml.html as lh
url = 'https://www.drugs.com/pro/abacavir-lamivudine-and-zidovudine-tablets.html#s-42231-1'
req = requests.get(url)

doc = lh.fromstring(req.text)

headers = doc.xpath('//ul[@class="ddc-anchor-links"]//li')
head_names = [] #when the code is done running, this list will contain the headers
anchors = [] #this list will contain the reference to the text elements for each header
for header in headers:
    head_names.append(header.xpath('a/text()')[0])
    anchors.append(header.xpath('a/@href')[0].replace('#',''))
for anchor in anchors:
    #now to iterate through each reference to get to the actual text:
    target = doc.xpath(f'//a[@id="{anchor}"]')[0] #this uses f-strings; you may need to read up on that
    ind = anchors.index(anchor) 1 #because of the structure of the page, this next block will help us determine when the text for one header ends, and the next one begins; you'll have to play with it to see how it actually works:
    for z in target.xpath('./following-sibling::*'):
        try:
            if (z.xpath('name()'))=="a"  and z.xpath('./@id')[0]==anchors[ind]:
                break
        except:
            continue #this is necessary because the last header doesn't have a "next" header
        else:
            print(z.xpath('.//text()'))
 

Вывод текста не будет красивым, но будет содержать нужную информацию. Вам придется поиграть с зачисткой, форматированием и т. Д., Чтобы он выглядел так, как вы хотите.

Комментарии:

1. Я внес изменение — заголовки = doc.xpath(‘//div[@class=»ddc-toc-содержимое»]’), но он показывает индекс списка вне диапазона в head_names.append(заголовок.xpath(‘a/text()’)[0]). Я отредактировал имя класса, так как предложенное вами не сработало

2. @Flameling Не уверен, в чем проблема; это работает для меня.

3. Я скопировал вставленный тот же код, который вы дали, и он не показывает мне никаких выходных данных. Я не понимаю, почему. Можете ли вы объяснить мне, что делает первый цикл?

4. @Flameling Я вижу, что произошло — сайт фактически изменил структуру html со вчерашнего дня; заголовки теперь под //div[@class="ddc-toc-content"]//ul//li/a/text() и т. Д. Может быть, они испытали слишком много соскабливающей активности…

5. Теперь код работал, но требовалось много работы, чтобы сделать данные красивыми и устранить ненужные вещи