С Python и BS мне нужно извлечь весь текст, содержащийся между двумя указанными словами
блабла текст мне нужен блибли
Мне удалось извлечь внутри DIV и TAG, но не для конкретного и другого ключевого слова.
спасибо за помощь
Звучит как задача для регулярного выражения, что bs4






Предполагая, что вы извлекли все слова между указанным тегом, теперь у вас есть строка, извлеченная в хронологическом порядке, в соответствии с тем, как был написан текст...
Получив полную текстовую строку, вы можете получить подстроку между двумя разными словами, каждое из которых встречается в тексте только один раз:
text = {text}
def get_textchunk(word1, word2, text):
new_text = text.split(word1)
new_text = new_text[1]
newnew_text = new_text.split(word2)
return newnew_text
print(get_textchunk('word1','word2',text)[0])
Это функция, которая будет разделена на два этапа с использованием двух разных слов.
Если вы хотите получить текст между двумя одинаковыми словами, которые встречаются только дважды (один раз в начале текста и один раз в конце), используйте этот код:
def get_textchunk(word, text):
text = text.split(word)
return text
print(get_textchunk('word', text)[1])
Это даст вам середину текста, который вы только что разделили.
Если вы хотите получить текст между двумя разными словами, которые часто встречаются в тексте, используйте этот код:
def get_textchunk(word1, word2, text):
idx1 = text.index(word1)
idx2 = text.index(word2)
for idx in range(idx1 + len(word1) + 1, idx2):
new_text = new_text + text[idx]
return new_text
Эта функция может быть наиболее полезной для вас.
# from bs4 import BeautifulSoup
# htmlStr = response.text ## if you're fetching with a request
htmlStr = '''
<div>
<h3>Some Section</h3>
Some text from Section 1
<h3> Contact </h3>
Adresse : Address Line One <br/> Address Line Two <br/>
Téléphone : 0X XX XX XX XX <br/>
Site : <a href = "https://example.com/">https://example.com/</a>
<h3>Some Other Section</h3>
field 1 : some info
field 2 : __ <br/> field 3 : some other info
</div>
'''
soup = BeautifulSoup(htmlStr, 'lxml')
def get_section_info(section_header):
hName, hList = section_header.name, 'h1,h2,h3,h4,h5,h6'
hList = [h for h in hList.split(hName)[0].split(',') if h] + [hName]
section_info, cur_key = {}, None
for ns in section_header.next_siblings:
if ns.name in hList: break ## stop if you reach the next section
if not ((isinstance(ns,str) and not ns.PREFIX) or ns.name): continue ## skip
nsStr = ' '.join((ns if isinstance(ns,str) else ns.get_text(' ')).split())
if ':' in nsStr and not nsStr.startswith('http'):
cur_key, nsStr = [s.strip() for s in nsStr.split(':',1)]
ckStr = section_info.get(cur_key, '')
if ns.name == 'br': section_info[cur_key] = ckStr + ' \n'
elif nsStr: section_info[cur_key] = ckStr + ' ' + nsStr
section_info = {k:v.strip() for k,v in section_info.items()}
return section_info[None] if [*section_info]==[None] else section_info
Это может выглядеть излишне запутанно, но вы можете получить всю контактную информацию с помощью
if (contact_h3 := soup.find('h3', string=lambda s: s and s.strip()=='Contact')):
contact_info = get_section_info(contact_h3)
else: contact_info, _ = {}, print('Could not find <h3>Contact</h3>')
и contact_info будет выглядеть
{ 'Adresse': 'Address Line One \n Address Line Two', 'Téléphone': '0X XX XX XX XX', 'Site': 'https://example.com/' }
Вы даже можете получить все разделы h3 так же просто, как
{h3.text.strip(): get_section_info(h3) for h3 in soup.select('h3')}
который бы вернулся
{ 'Some Section': 'Some text from Section 1', 'Contact': { 'Adresse': 'Address Line One \n Address Line Two', 'Téléphone': '0X XX XX XX XX', 'Site': 'https://example.com/' }, 'Some Other Section': { 'field 1': 'some info field 2 : __', 'field 3': 'some other info' } }
Note: field 2 is merged into field 1 value because there's nothing separating them in the HTML, so there's no way to know if the key should be 2 or field 2 or info field 2 or... so the function assumes that there is a maximum of one field per NavigableString; and 'Some Section' only has a string value instead of a dictionary since there doesn't seem to be any :s separating field names from the relevant info.
Если вам действительно нужен только текст между двумя словами, вы можете просто использовать
def get_textchunk(word1, word2, text):
if not (word1 in text and word2 in text): return ''
return text.split(word1)[-1].split(word2)[0]
## can refine with more conditions/string-manipulations/regex/etc
get_textchunk('Adresse :', 'Téléphone :', soup.get_text(' '))
Однако, если вы не уверены в имени следующего поля, но уверены, что имена полей разделены :, вы можете использовать эту версию get_section_info:
def get_text_by_field(soupX, fieldName):
fsCond = lambda s: s and ':' in s and s.split(':')[0].strip()==fieldName
fieldStr = soupX.find(string=fsCond)
hList, myText = [f'h{i}' for i in range(1,7)], fieldStr.split(':',1)[1]
for ns in (fieldStr.next_siblings if fieldStr else []):
if ns.name in hList: break ## stop when you reach the next section
if not ((isinstance(ns,str) and not ns.PREFIX) or ns.name): continue
nsStr = ' '.join((ns if isinstance(ns,str) else ns.get_text(' ')).split())
if ':' in nsStr and not nsStr.startswith('http'): break
if ns.name == 'br': myText += ' \n'
elif nsStr: myText += (' ' + nsStr)
return myText.strip()
то get_text_by_field(soup, 'Adresse') должен вернуться
'Address Line One \n Address Line Two'
Может быть, вы можете попробовать преобразовать строки текста в одну строку. Я думаю, что тип вашего текста на самом деле представляет собой список, а не строку.
print(type(text)) to find the type of your text
Если это список, то:
list = ["Adresse : fffgdfdgfrrrere",
"rrgegreggregr",
"Téléphone : egrrgerererg"]
text = ' '.join(list)
print(text)
Затем:
text = "Adresse: fffgdfdgfrrrere rrgegreggregr Téléphone: egrrgerererg"
def get_textchunk(word1, word2, text):
new_text = text.split(word1)
new_text = new_text[1]
newnew_text = new_text.split(word2)
return newnew_text
print(get_textchunk('Adresse: ',' Téléphone', text)[0])
Ответ: "fffgdfdgfrrrere rrgegreggregr"
Пожалуйста, приведите пример, где это работает, и тот, где это не так.