Учитывая HTML-абзац и ссылку, есть ли способ получить текст до и текст после ссылки внутри абзаца в Python? - PullRequest
0 голосов
/ 18 июня 2019

Я использую urllib3 для получения html некоторых страниц.

Я хочу получить текст из абзаца, где находится ссылка, с текстом до и после ссылки, сохраненным отдельно.

Например:

import urllib3
from bs4 import BeautifulSoup

http = urllib3.PoolManager()
r = http.request('get', "https://www.snopes.com/fact-check/michael-novenche/")
body = r.data
soup = BeautifulSoup(body, 'lxml')
for a in soup.findAll('a'):
    if a.has_attr('href'):
        if (a['href'] == "http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"):
            link_text = a
            link_para = a.find_parent("p")
            print(link_text)
            print(link_para)

Абзац

<p>The message quoted above about Michael Novenche, a two-year-old boy 
undergoing chemotherapy to treat a brain tumor, was real, but keeping up with 
all the changes in his condition proved a challenge.  The message quoted above 
stated that Michael had a large tumor in his brain, was operated upon to 
remove part of the tumor, and needed prayers to help him through chemotherapy 
to a full recovery.  An <nobr>October 2000</nobr> article in <a 
href="http://web.archive.org/web/20040330161553/http://newyork.local.ie/conten
t/31666.shtml/albany/news/newsletters/general" 
onmouseout="window.status='';return true" onmouseover="window.status='The
Local Albany Weekly';return true" target="_blank"><i>The Local Albany 
Weekly</i></a> didn’t mention anything about little Michael’s medical 
condition but said that his family was “in need of funds to help pay for the
 transportation to the hospital and other costs not covered by their 
insurance.”  A June 2000 message posted to the <a 
href="http://www.ecunet.org/whatisecupage.html" 
onmouseout="window.status='';return true" 
onmouseover="window.status='Ecunet';return true" target="_blank">Ecunet</a> 
mailing list indicated that Michael had just turned <nobr>3 years</nobr> old, 
mentioned that his tumor appeared to be shrinking, and provided a mailing 
address for him:</p>

Ссылка

<a href="http://web.archive.org/web/20040330161553/http://newyork.local.ie/conten
t/31666.shtml/albany/news/newsletters/general"
onmouseout="window.status='';return true" onmouseover="window.status='The 
Local Albany Weekly';return true" target="_blank"><i>The Local Albany 
Weekly</i></a>

Текст для извлечения (2 части)

The message quoted above about Michael Novenche, a two-year-old boy 
undergoing chemotherapy ... was operated upon to 
remove part of the tumor, and needed prayers to help him through chemotherapy 
to a full recovery.  An October 2000 article in
didn’t mention anything about little Michael’s medical 
condition but said that his family was ... turned 3 years old, 
mentioned that his tumor appeared to be shrinking, and provided a mailing 
address for him:

Я не могу просто get_text (), а затем использовать split, поскольку текст ссылки может повторяться.

Я подумал, что мог бы просто добавить счетчик, чтобы увидеть, сколько раз текст ссылки повторяется, использовать split (), а затем использовать цикл, чтобы получить нужные части.

Буду признателенлучше, менее грязный метод.

Ответы [ 4 ]

1 голос
/ 18 июня 2019

Вы можете перебирать содержимое родительского тега a и сравнивать, если фактическим значением является наш тег a.Если это так, мы нашли одну часть и продолжаем строить другую:

data = '''<p>The message quoted above about Michael Novenche, a two-year-old boy
undergoing chemotherapy to treat a brain tumor, was real, but keeping up with
all the changes in his condition proved a challenge.  The message quoted above
stated that Michael had a large tumor in his brain, was operated upon to
remove part of the tumor, and needed prayers to help him through chemotherapy
to a full recovery.  An <nobr>October 2000</nobr> article in <a
href="http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"
onmouseout="window.status='';return true" onmouseover="window.status='The
Local Albany Weekly';return true" target="_blank"><i>The Local Albany
Weekly</i></a> didn’t mention anything about little Michael’s medical
condition but said that his family was “in need of funds to help pay for the
 transportation to the hospital and other costs not covered by their
insurance.”  A June 2000 message posted to the <a
href="http://www.ecunet.org/whatisecupage.html"
onmouseout="window.status='';return true"
onmouseover="window.status='Ecunet';return true" target="_blank">Ecunet</a>
mailing list indicated that Michael had just turned <nobr>3 years</nobr> old,
mentioned that his tumor appeared to be shrinking, and provided a mailing
address for him:</p>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'lxml')

link_url='http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general'
a = soup.find('a', href=link_url)

s, parts = '', []
for t in a.parent.contents:
    if t == a:
        parts += [s]
        s = ''
        continue
    s += str(t)
parts += [s]

for part in parts:
    print(BeautifulSoup(part, 'lxml').body.text.strip())
    print('*' * 80)

Отпечатки:

The message quoted above about Michael Novenche, a two-year-old boy
undergoing chemotherapy to treat a brain tumor, was real, but keeping up with
all the changes in his condition proved a challenge.  The message quoted above
stated that Michael had a large tumor in his brain, was operated upon to
remove part of the tumor, and needed prayers to help him through chemotherapy
to a full recovery.  An October 2000 article in
********************************************************************************
didn’t mention anything about little Michael’s medical
condition but said that his family was “in need of funds to help pay for the
 transportation to the hospital and other costs not covered by their
insurance.”  A June 2000 message posted to the Ecunet
mailing list indicated that Michael had just turned 3 years old,
mentioned that his tumor appeared to be shrinking, and provided a mailing
address for him:
********************************************************************************
0 голосов
/ 19 июня 2019

Я нашел решение, основанное на решении @Andrej kesely.

Имеется две проблемы:

  1. что до / после ссылки нет текста

  2. То, что ссылка не является прямым потомком абзаца

Вот оно (как функция) :

import urllib3
from bs4 import BeautifulSoup
import lxml

def get_info(page,link):
    r = http.request('get', page)
    body = r.data
    soup = BeautifulSoup(body, 'lxml')
    a = soup.find('a', href=link)
    s, parts = '', []

    if a.parent.name=="p":
        for t in a.parent.contents:
            if t == a:
                parts += [s]
                s = ''
                continue
            s += str(t)
        parts += [s]
    else:
        prnt = a.find_parents("p")[0]
        for t in prnt.contents:
            if t == a or (str(a) in str(t)):
                parts+=[s]
                s=''
                continue
            s+=str(t)
        parts+=[s]

    try:
        text_before_link = BeautifulSoup(parts[0], 'lxml').body.text.strip()
    except AttributeError as error:
        text_before_link = ""

    try:
        text_after_link = BeautifulSoup(parts[1], 'lxml').body.text.strip()
    except AttributeError as error:
        text_after_link = ""

    return text_before_link, text_after_link

Предполагается, что внутри другого абзаца нет абзаца.

Если у кого-то есть идеи относительно сценариев, когда это не удается, пожалуйста, не стесняйтесь упоминать об этом.

0 голосов
/ 18 июня 2019

Вы можете легко сделать это с помощью BS4 4.7.1. Используйте :has и селектор attribute = value, чтобы получить родительский тег p, затем разделите его html на html тега a. Затем выполните повторный анализ с помощью bs для тегов p. Это позволяет обойти проблему с повторяющимися фразами. Проблема возникает только в том случае, если весь html тега a может повторяться внутри блока, что кажется маловероятным.

import requests
from bs4 import BeautifulSoup as bs

r = requests.get('https://www.snopes.com/fact-check/michael-novenche/')
soup = bs(r.content, 'lxml')
data = soup.select_one('p:has(>[href="http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"])').encode_contents().split(soup.select_one('[href="http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"]').encode_contents())
items = [bs(i, 'lxml').select_one('p').text for i in data]
print(items)
0 голосов
/ 18 июня 2019

Вы можете уточнить, что вы подразумеваете под:

Я не могу просто получить get_text (), а затем использовать split, поскольку текст ссылки может быть повторил

Когда я бегу:

import urllib3
from bs4 import BeautifulSoup
import certifi

http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())

r = http.request('GET', "https://www.snopes.com/fact-check/michael-novenche/")
body = r.data
soup = BeautifulSoup(body, 'lxml')
for a in soup.findAll('a'):
    if a.has_attr('href'):
        if (a['href'] == "http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"):
            link_text = a
            link_para = a.find_parent("p")
            print(link_para.get_text())

Я получаю:

Сообщение, приведенное выше о Майкле Новенше, двухлетнем мальчике, проходящем химиотерапию для лечения опухоли головного мозга, было реальным, но не отставать от всех изменений в его состоянии оказалось проблемой. В приведенном выше сообщении говорилось, что у Майкла была большая опухоль в его мозге, ему сделали операцию по удалению части опухоли, и ему потребовались молитвы, чтобы помочь ему пройти химиотерапию до полного выздоровления. В октябрьской статье 2000 года в The Local Albany Weekly ничего не упоминалось о состоянии здоровья маленького Майкла, но говорилось, что его семье «нужны средства, чтобы оплатить транспортировку в больницу и другие расходы, не покрываемые их страховкой». A В сообщении за июнь 2000 года, опубликованном в списке рассылки Ecunet, указывалось, что Майклу только что исполнилось 3 года, он упомянул, что у него уменьшилась опухоль, и указал почтовый адрес для него:

Текст разделяется на «The Local Albany Weekly», который является названием ссылки. Так почему бы не получить имя ссылки и не разделить его?

http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())

r = http.request('GET', "https://www.snopes.com/fact-check/michael-novenche/")
body = r.data
soup = BeautifulSoup(body, 'lxml')
for a in soup.findAll('a'):
    if a.has_attr('href'):
        if (a['href'] == "http://web.archive.org/web/20040330161553/http://newyork.local.ie/content/31666.shtml/albany/news/newsletters/general"):
            link_text = a
            link_para = a.find_parent("p")
            the_link = link_para.find('a')
            #change the name of <i> to something unique
            the_link.string.replace_with('ooqieri')
            name_link = link_text.findAll('i')[0].get_text()
            full_text = link_para.get_text().split(name_link)
            print(full_text)

, что дает:

['Сообщение, приведенное выше о Майкле Новенше, двухлетнем мальчике, проходящем химиотерапию для лечения опухоли головного мозга, было реальным, но не отставать от всех изменений его состояния оказалось проблемой. В приведенном выше сообщении говорилось, что у Майкла была большая опухоль в его мозге, ему сделали операцию по удалению части опухоли, и ему потребовались молитвы, чтобы помочь ему пройти химиотерапию до полного выздоровления. В октябрьской статье 2000 года в «» ничего не упоминалось о состоянии здоровья маленького Майкла, но говорилось, что его семье «нужны средства, чтобы оплатить транспортировку в больницу и другие расходы, не покрываемые их страховкой». Июнь Сообщение 2000 года, отправленное в список рассылки Ecunet, указывало, что Майклу только что исполнилось 3 года, упомянуло, что его опухоль, похоже, уменьшалась, и предоставило ему почтовый адрес: ']

...