Найти - Пользователи
Полная версия: собрать статью в кучу при парсинге
Начало » Python для новичков » собрать статью в кучу при парсинге
1 2 3
robisho
Добрый день. Python3.8+win7+requests+BeautifulSoup
При парсинге страницы имеем такую архитектуру:
 <article>
  <h2>text</h2>
  <p>text</p>
  <p><img src="pics.jpg"></p>
  <h2>text</h2>
  <p>text
    <ul>
      <li>
        text
      </li>
        text
      <li>
        text
      </li>
    </ul>
  </p>
  <h2>text</h2>
  <p>text</p>
</article>

дерево типичный статейник. нужно собрать в кучу все текстовые кусочки, чтобы не только <p> были, но и <h2>, и <ul>+<li>, и желательно <img>.
пока цикл выглядит так
    article_tags = soup.find_all('p')
    article = ''
    for tag in article_tags:
        try:
            if tag.find('img') is not None:
                article += str(tag.find('img')) + '\n'
            article += tag.text + '\n'
        except Exception as e:
            continue

но сюда не попадают <h2> и <ul>+<li>. и еще присутствуют иногда дубли кусков текста.
xam1816
какой адрес страницы?
robisho
xam1816
какой адрес страницы?
да адрес в данном случае не важен, это парсер статей из гугла по ключу, сайты разные и разметка у них тоже разная, к тегу article/main/content/etc не привяжешься.
py.user.next
robisho
При парсинге страницы имеем такую архитектуру:
Пронумеруй все тексты в исходном XML-коде.
После этого напиши результат, который ты хочешь из него получить.
Как должен быть структурирован результат?

Проблема у тебя в том, что ты ищёшь все теги p, а не все теги article. Поэтому текст из разных тегов и не попадает.

robisho
и еще присутствуют иногда дубли кусков текста
Вот для этого и пронумеруй тексты типа text1, text2 и так далее, чтобы видеть, где дубли, а где не дубли, пока алгоритм реализуешь на экспериментальных вводных данных.
robisho
py.user.next
ну я же сознательно ищу теги р и не ищу теги article) тело статьи почти со 100% вероятностью будет в тегах p, а вместо тега article может быть div, или div, или … да дофига этих стилей в современном многоборье)))
вроде бы нашел вариант решения
 article_tags = soup.find_all(['h2', 'h3', 'h4', 'p', 'li'])
цикл остается тот же, дублей уже нет
вот только осталось отфильтровать li, которые в теге p - их оставить, а которые в меню - убрать
py.user.next
robisho
<article>
<h2>text</h2>
<p>text</p>
<p><img src="pics.jpg"></p>
<h2>text</h2>
<p>text
<ul>
<li>
text
</li>
text
<li>
text
</li>
</ul>
</p>
<h2>text</h2>
<p>text</p>
</article>

robisho
ну я же сознательно ищу теги р и не ищу теги article)
Но теги p не содержат тегов h1, h2 и так далее. Поэтому когда ты ищёшь теги p, а потом ищешь в каждом из тегов p теги h1, h2 и подобные
robisho
  
    article_tags = soup.find_all('p')
    article = ''
    for tag in article_tags:
        ...
то, естественно, ты их там не находишь, потому что их там нет, так как они находятся в теге article.

Весь текст можно найти методом get_text()
  
>>> import bs4
>>> 
>>> text = """
... <article>
...   <h2>text1</h2>
...   <p>text2</p>
...   <p><img src="pics.jpg"></p>
...   <h2>text3</h2>
...   <p>text4
...     <ul>
...       <li>
...         text5
...       </li>
...         text6
...       <li>
...         text7
...       </li>
...     </ul>
...   </p>
...   <h2>text8</h2>
...   <p>text9</p>
... </article>
... """
>>> 
>>> soup = bs4.BeautifulSoup(text, 'lxml')
>>> out = list(filter(None, map(str.strip, soup.get_text().splitlines())))
>>> out
['text1', 'text2', 'text3', 'text4', 'text5', 'text6', 'text7', 'text8', 'text9']
>>>

Но чтобы находить текст и между ним картинки, придётся тебе сделать рекурсивную функцию, которая будет спускаться в узлы и анализировать их детей (если там есть текст, брать текст; если там есть картинка, брать картинку).
robisho
py.user.next
да я прекрасно понимаю, что в теге p нет тегов h2-h3) эти теги обычно одноуровневые с тегом p, поэтому пробовал у p.parent пройти все next_siblings, h2-h3 ловлю, а ul>li нет…
вариант
 article_tags = soup.find_all(['h2', 'h3', 'h4', 'p', 'li'])
работает норм, ищу возможность оставить li и h3-h4, которые относятся только к p, а то тянется все и с меню, и с сайдбара.
py.user.next
robisho
ищу возможность оставить li и h3-h4, которые относятся только к p, а то тянется все и с меню, и с сайдбара.
Ну, как надоест мучиться, тогда придёшь и расскажешь всё. Может, тебе xam1816 решит эту задачу. А если уж совсем тяжело будет, тогда и я подтянусь.

От тебя нужно будет, чтобы ты написал точный входной документ, точные выходные данные, полученные из него, и примерный способ получения выходных данных из входного документа так, как ты его себе представляешь.
robisho
ну если кому интересно, остановился на таком варианте
 p_tags_list = soup.find_all(['h2', 'h3', 'p', 'ul', 'figure', 'img'])
# отобрал теги, что всегда используются в статьях
    p_tags = []
# убрал те, что с атрибутами, они в подавляющем большинстве случаев не относятся к статье
    for tag in p_tags_list:
        if not tag.attrs:
            p_tags.append(tag)
    article = ''
    for t in p_tags:
        try:
            if t.find('img') is not None:
                article += '\n' + str(t.find('img')) + '\n'
            elif t.find('li') is not None:
                article += '\n' + t.text + '\n'
            elif t.find('h4') is not None:
                article += '\n' + t.text + '\n'
            else:
                article += '\n' + t.text + '\n'
'
        except Exception as e:
            continue

наудачу из 5 рандомных сайтов работает на 4х, правда вверху и внизу нужно иногда чистить немного мусора ручками

конечно результат не 100%, бывает разметка, где все теги р имеют атрибуты, но это редкость

критика/дополнения/исправления приветствуются)
xam1816
Вы наверное делаете что-то типа “режим для чтения” который в браузерах,только на python
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB