Необходимо извлечь содержимое двух html классов с одинаковым именем - PullRequest
1 голос
/ 02 августа 2020

Я хочу извлечь содержимое следующего html кода

<div class="card__content">
<div class="card__title">
Sajjad Haider Khan
<svg class="icon link__icon" height="10" width="10">
<use xlink:href="#icon-arrow-right">
</use>
</svg>
</div>
<div class="card__position">
Student,
<span class="card__text">
Computer Science Engineering (CSE)
</span>
</div>
<div class="card__position">
<span class="card__text">
Career Interests:
</span>
Computer Science; Python; Machine Learning
</div>
</div>

Мне нужно все содержимое обоих классов card__position. Во втором классе card__position после закрытия класса span есть текст в двойных кавычках. Я хочу также извлечь этот текст.

Я могу извлечь только card__title и содержимое только первого класса card__position с помощью следующего кода.

from bs4 import BeautifulSoup as soup
from urllib.request import urlopen as uReq

url = '<url>'

uClient = uReq(url)
page_html = uClient.read()
uClient.close()
page_soup = soup(page_html, "html.parser")

containers = page_soup.find_all("div", {"class": "card__content"})

container = containers[0]

title = container.findAll("div", {"class": "card__title"})
#print(name[0].text)

position = container.findAll("div", {"class": "card__position"})
#print(position[0].text)

Однако я хочу распечатайте результаты следующим образом:

Sajjad Haider Khan
Student
Computer Science Engineering (CSE)
Career Interests: Computer Science; Python; Machine Learning

1 Ответ

0 голосов
/ 03 августа 2020

Код имеет правильный подход. Однако я бы рекомендовал разделить код на получение html и результаты очистки. Код результатов очистки должен возвращать результаты в виде какого-то объекта ответа. В моем примере ниже используется NamedTupple (для простоты использования).

find_all() следует использовать, если вы используете wi sh, чтобы найти более одного элемента html. В противном случае используйте find(), чтобы получить первый элемент. Также есть небольшая опечатка в findAll ().

Также этот вопрос предоставляет только фрагмент содержимого html. Это затрудняет делать предположения. Однако я предполагаю, что html всегда содержит 2 блока с классом card__position. Я использую assert, чтобы вызвать исключение, если это не так.

В любом случае ниже приведен пример, который обеспечивает желаемый результат:

from collections import namedtuple
from bs4 import BeautifulSoup

ExtractResponse = namedtuple('ExtractResponse', ['Name', 'Role', 'Course', 'MiscInfoTitle', 'MiscInfoDetails']) # This is used to store date frome extract. Not too sure on correct namings

html = '''<div class="card__content">
<div class="card__title">
Sajjad Haider Khan
<svg class="icon link__icon" height="10" width="10">
<use xlink:href="#icon-arrow-right">
</use>
</svg>
</div>
<div class="card__position">
Student,
<span class="card__text">
Computer Science Engineering (CSE)
</span>
</div>
<div class="card__position">
<span class="card__text">
Career Interests:
</span>
Computer Science; Python; Machine Learning
</div>
</div>'''

def extract(soup):
    card_container_soup = soup.find("div", {"class": "card__content"}) # use find() if you know there is 1 instance (e.g <div class="card__content">)
    title_soup = card_container_soup.find("div", {"class": "card__title"})

    card_positions_soup = card_container_soup.find_all("div", {"class": "card__position"})
    assert len(card_positions_soup) == 2 # Validate that there are always 2 card__position. If theres is not, the scrape results will be wrong.
    
    # This code assumes the first card__position contains course data and the second contains intrest
    card_text_1_soup = card_positions_soup[0].find('span', {'class': 'card__text'})
    card_text_1 = card_text_1_soup.text.strip()
    card_text_1_soup.extract() # remove card text. This is so that the non span text can be scraped.

    card_text_2_soup = card_positions_soup[1].find('span', {'class': 'card__text'})
    card_text_2 = card_text_2_soup.text.strip()
    card_text_2_soup.extract()

    response = ExtractResponse(title_soup.text.strip(), card_positions_soup[0].text.strip().replace(',', ''), card_text_1, card_text_2, card_positions_soup[1].text.strip())
    return response

soup = BeautifulSoup(html, "html.parser")
results = extract(soup)

print(results.Name)
print(results.Role)
print(results.Course)
print(f"{results.MiscInfoTitle} {results.MiscInfoDetails}")

Вывод:

Sajjad Haider Khan
Student
Computer Science Engineering (CSE)
Career Interests: Computer Science; Python; Machine Learning
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...