Я пытаюсь восстановить сообщения в Интернете, и мне удалось добиться успеха на большинстве сайтов, используя приведенный ниже код для очистки текстов.
parent = driver.find_element(By.XPATH, "//*") # main post element
child = parent.find_elements(By.XPATH, ".//*") # child containing texts/emojis/links/images
for i in child:
if i.text is not None:
post.append(i.get_attribute('textContent'))
if i.get_attribute('alt') is not None:
post.append(i.get_attribute('alt'))
text = ''.join(post)
print(text)
По сути, я реконструирую сообщение, получая textContent
и alt
в том виде, в котором они найдены и перечислены с помощью find_elements
. Если ребенок содержит text
, будет получен текст, если нет, будет получен alt
для смайликов/изображений.
Все содержимое публикации можно получить с помощью get_attribute
, поскольку каждый текст и смайлик находятся внутри дочернего элемента. Однако я столкнулся со структурой, в которой есть только один дочерний элемент (<div>
), содержащий все text
и alt
. Пример ниже:
<span class = "post">
<div class = "paragraph1">
<div>
<span class = "html-span link">
<a>#link1 </a>
</span>
"A "
<span class = "html-span emoji">
<img alt = ":)">
</span>
"B "
</div>
</div>
<div class = "paragraph2">
<div>
"C "
<span class = "html-span link">
<a>#link2</a>
</span>
"D "
<span class = "html-span emoji">
<img alt = ":(">
</span>
"E"
</div>
</div>
</span>
Можно ли воплотить идею //text() or //*[@img='alt']
в жизнь? Кажется, использование find_elements
с By.XPATH, //text()
запрещено.
Ожидаемый результат:
#link1 A :) B C#link2 D :( E
Пытался:
parent = driver.find_element(By.XPATH, "//*") # main post element
child = parent.find_elements(By.XPATH, ".//*[contains(@class, 'html-span')]//*") # child containing texts/emojis/links/images
for i in child:
print(i.get_attribute('textContent'))
if i.text is not None:
post.append(i.get_attribute('textContent'))
if i.get_attribute('alt') is not None:
post.append(i.get_attribute('alt'))
print(post)
text = ''.join(post)
print(text)
Результат:
[#link, '', :), '', '', #link2, '', :(, ''] # пропал text
ребенка
parent = driver.find_element(By.XPATH, //span[@class='post']")
print(parent.get_attribute('textContent'))
Результат:
#link1 A B C#link2 D E
# отсутствует атрибут alt
Я пытаюсь сгруппировать каждый абзац class
и составить из них предложения. Но возможность получить и атрибут, и текст всего сообщения по порядку уже достаточно хорошо.
Любая идея о том, как действовать, очень ценится.
это сложно, потому что у вас есть текст в текстовых узлах <div> (есть текстовые узлы и узлы элементов). text() получает текстовый узел (как показано) элемента.... но этот <div> может иметь 2 текстовых узла. Одним из вариантов является атрибут get для InnerHTML или OuterHTML, но он соберет всю разметку/текст внутри, и вам придется анализировать их оттуда.
Спасибо всем! Я буду пробовать их. @LMC — XPATH, которым вы поделились, — это одна из тех вещей, которые я искал. Он находит все нужные мне элементы (или узлы для текста). Хотя узел был для меня тупиком на этом пути, моя проблема все еще остается [object Text]. It should be an element.
. Разве мне не следует использовать find_elements
?
Этот скрипт должен работать:
script = '''
function getText(node){
let text = [];
for (let i = 0; i < node.childNodes.length; i++){
const child = node.childNodes[i];
if (child.alt){
text.push(child.alt);
} else if (child.children){
text.push(getText(child));
} else {
const content = child.textContent.trim();
content && text.push(content);
}
}
return text.join(' ');
}
return getText(arguments[0])
'''
span = driver.find_element(By.CSS_SELECTOR, 'span.post')
text = driver.execute_script(script, span)
print(text)
Редактировать:
Если вам нужно собственное решение на Python, вы можете использовать BeautifulSoup следующим образом:
from bs4 import BeautifulSoup
def getText(soup):
text = []
for child in soup.children:
if child.string:
text.append(child.get_text(strip=True))
elif alt := child.get('alt'):
text.append(alt)
elif child.contents:
text.append(getText(child))
return ' '.join(text).strip()
span = driver.find_element(By.CSS_SELECTOR, 'span.post')
html = span.get_attribute('innerHTML')
text = getText(BeautifulSoup(html, 'html.parser'))
print(text)
Это работает! Большое спасибо! Мне удалось интегрировать script
в свой код. Думаю, мне сейчас нужно изучать JS.
@J_L проверьте редактирование, я добавил собственное решение на Python.
Попробуйте
//span[@class = "post"]//*/text() | //span[@class = "post"]//img/@alt
. Это вернет ВСЕ текстовые узлы, включая те, которые содержат пробельные символы. например0: #text "\n " 1: #text "\n " 2: #text "\n " 3: #text "#link1 "