Найти - Пользователи
Полная версия: собрать статью в кучу при парсинге
Начало » Python для новичков » собрать статью в кучу при парсинге
1 2 3
robisho
xam1816
Вы наверное делаете что-то типа “режим для чтения” который в браузерах,только на python
нет, это типа х-парсера, загружаем в скрипт ключи, скрипт тянет из гугла выдачу по этому ключу и парсит статьи из топа
robisho
py.user.next
воспользовался вашим вариантом
 out = list(filter(None, map(str.strip, soup.get_text().splitlines())))

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

 main_tag = soup.find(class_=[re.compile('[Cc]ontent'), 'article',   'main',  'entry'])
p_tags_list = main_tag.find_all(['h2', 'h3', 'p', 'ul', 'figure', 'img'])
outs = list(filter(None, map(get_text_in_tag, p_tags_list)))
def get_text_in_tag(tag):
    if tag.find('img') is not None:
        return str(tag.find('img'))
    elif tag.find('li') is not None:
        return str(tag.get_text()).strip()
    else:
        return str(tag.get_text()).strip()

но пока с получением main_tag сыровато выходит…
py.user.next
1. Сначала надо определить, какие данные у тебя на входе.
2. Затем надо определить, какие данные нужно получить на выходе.
3. И после этого нужно описать процедуру получения из данных со входа данных на выходе.
И после этого только надо начинать программировать.

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

Задача эта простая, но ты её ставишь неточно, поэтому на неё и уходит столько времени.
robisho
ну идею для себя я определил до того, как садиться за код) прошу прощения, если я неявно нарисовал свои цели) цель одна - получить статью с любого(по возможности) статейного сайта, без привязки к конкретной верстке, со всеми разметками(тегами h2-h3-h4, p, ul>li, ol>li) и сохранив в тексте теги картинок вида <img src=“//pic.jpg” title=“”/>. т.е. изначально неизвестно, какие теги содержатся в исходном коде страницы, но теги h2, h3, h4, p, ul>li, ol>li есть априори. понимаю, что невозможно сделать универсальный, покрывающий 100% сайтов, парсер, но надеюсь, что для 70-80% сайтов такой скрипт сделать можно.
py.user.next
robisho
цель одна - получить статью с любого(по возможности) статейного сайта, без привязки к конкретной верстке, со всеми разметками(тегами h2-h3-h4, p, ul>li, ol>li) и сохранив в тексте теги картинок вида <img src=“//pic.jpg” title=“”/>.
А “статья” - это что? Как ты понимаешь, что является статьёй, а что не является статьёй?
Я могу статью собрать из одних div'ов, в которой кроме div'ов ничего не будет, при этом она будет выглядеть так, будто в ней есть и h2, и h3, и p, и ul>li, и даже img.

Думаю, у тебя нарушено “правило достижимости” цели. При постановке цели необходимо, чтобы она была достижима. Можно поставить себе цель, например, слетать на Марс, но вряд ли ты когда-нибудь слетаешь на Марс. Это недостижимая цель.

Разобрать все сайты вряд ли возможно, так как множество входных данных бесконечно. Можно лишь выделить подмножество из этого множества, хорошо детерминировать каждую структуру статьи и потом из доступных структур выбирать подходящую и алгоритмом, зарегистрированным как раз для этой структуры, разбирать статью надёжно.

Вот эта твоя структура вполне определённая
<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>
Для неё можно написать конкретный алгоритм разбора. И BeautifulSoup совсем не обязательно для этого использовать. Можно использовать лишь встроенные средства питона. Когда используешь только встроенные средства, при попадании скрипта на любой компьютер, где установлен питон, этот скрипт будет применим без дополнительной установки модулей.

Но вот когда придёт другая структура статьи, то к ней надо будет другой алгоритм применять, который соответствует ей. Далеко не во всех статьях есть тег article, далеко не во всех статьях заголовки делаются через теги hN и далеко не во всех статьях списки делаются через ul. Соответственно, для каждого распознанного типа статьи должен быть свой конкретный алгоритм разбора, не зависящий от других алгоритмов разбора. Тогда всё будет точно.

Вообще, если уж ты собрался множество структур разбирать, то сначала его надо определить с помощью формы Бэкуса-Наура (wiki. bnf) и потом уже под это делать распознаватель. Но так как код у тебя слабенький, то, думаю, сначала тебе несколько лет придётся изучать синтаксические анализаторы, прежде чем написать что-то вменяемое. Так что на данном этапе можешь только определить вид статьи и применить к ней алгоритм разбора, соответствующий этому виду статьи, и сделать такие пары <распознаватель, разбиратель> для всех статей, которые тебе встречались.
robisho
py.user.next
спасибо, что увидели такую глубину в моей идее) не, без шуток, спасибо, я так глубоко и не думал копать. была простая утилитарная задумка для сео задач. вы хорошо описали направление движения. на самом деле на начальном этапе я тоже думал об этом, даже на xpath составил болванку тегов, с которых начинаются многие статьи

 tags1 = tree.xpath("//*[starts-with(@class, 'entry')]/descendant-or-self::node()")
tags2 = tree.xpath("//div[starts-with(@class, 'content')]/descendant-or-self::node()")
tags3 = tree.xpath("//*[contains(@id, 'content')]/descendant-or-self::node()")
tags4 = tree.xpath('//h1/parent::*/descendant-or-self::node()')
думал, как организовать переключение между этими тегами.
но потом зацепился за тег р и понеслось) но ваша мысль
Так что на данном этапе можешь только определить вид статьи и применить к ней алгоритм разбора, соответствующий этому виду статьи, и сделать такие пары <распознаватель, разбиратель> для всех статей, которые тебе встречались.
подтвердила мою изначальную, поэтому будем разбираться дальше)
py.user.next
robisho
даже на xpath составил болванку тегов
Здесь их четыре, а вообще их бесконечное множество. Поэтому нужно определить (создать) тип статьи. Статья - это …

А дальше делается функция, в которую подаётся текст и которая возвращает тип этого текста. Если это статья с article, функция возвращает слово article. Если это статья с div, функция возвращает слово div. Если это не статья, функция возвращает слово undefined. После определения типа текста он передаётся в функцию разбора статьи. Функция разбора статьи для статьи с article вызывает функцию разбора статьи с article, получает результат разбора и возвращает этот результат. Функция разбора статьи для статьи с div вызывает функцию разбора статьи с div, получает результат разбора и возвращает этот результат.

Это набросок
  
>>> def get_text_type(text):
...     out = 'undefined'
...     if text.startswith('<article>'):
...         out = 'article'
...     elif text.startswith('<div>'):
...         out = 'div'
...     return out
... 
>>> def parse_article(text, article_type):
...     out = None
...     if article_type == 'article':
...         out = parse_article_article(text)
...     elif article_type == 'div':
...         out = parse_article_div(text)
...     return out
... 
>>> def parse_article_article(text):
...     out = {'title': text.split('\n')[0][9:], 'content': text.split('\n')[1]}
...     return out
... 
>>> def parse_article_div(text):
...     out = {'title': text.split('\n')[0][5:], 'content': text.split('\n')[1]}
...     return out
... 
>>> def process_text(text):
...     text_type = get_text_type(text)
...     if text_type != 'undefined':
...         article = parse_article(text, text_type)
...         print('{}\n  {}'.format(article['title'], article['content']))
...     else:
...         print('It is not an article.')
... 
>>> process_text('article\ncontent of article')
It is not an article.
>>> process_text('<article>Article\nContent of Article')
Article
  Content of Article
>>> process_text('div\ncontent of div')
It is not an article.
>>> process_text('<div>Div\nContent of Div')
Div
  Content of Div
>>>

Там уже в каждой конкретной функции можешь применять либо lxml, либо BeautifulSoup, либо XPath, либо средства ядра языка, либо всё это вперемешку. Также эти конкретные функции разбора можно ветвить ещё дальше, если разбор становится более сложным.

То, что у тебя в подобных кодах всё слито воедино, рано или поздно закупорит проект при добавлении нового типа статьи. Новый тип не добавишь, потому что старые типы сломаются. А старые типы всегда будут мешать добавлять новые типы. Поэтому надо разделять всё - как для распознавания, так и для разбора. Тогда ты сможешь добавлять новые типы статей к уже существующим.
robisho
Добрый день. получилась такая вот поделка)
     tag1 = soup.find('article')
    tag2 = soup.find('section')
    tag3 = soup.find('div', itemtype='http://schema.org/Article')
    tag4 = soup.find_all('div', class_=re.compile('[Cc]ontent'))
    tag5 = soup.find_all('div', class_=re.compile('entry'))
    tag6 = soup.find('div', id='content')
    tag7 = soup.find_all('div', class_=re.compile('container'))
    if tag1:
        if tag1.has_attr('itemtype') or tag1.find('p'):
            article_tag = tag1
    elif tag2 and tag2.find('p'):
        article_tag = tag2
    elif tag3 and tag3.find('p'):
        article_tag = tag3
    elif tag4:
        for tag in tag4:
            if len(tag.find_all('p')) > 3:
                article_tag = tag
    elif tag5:
        for tag in tag5:
            if len(tag.find_all('p')) > 3:
                article_tag = tag
    elif tag6 and tag6.find('p'):
        article_tag = tag6
    elif tag7:
        for tag in tag7:
            if len(tag.find_all('p')) > 3:
                article_tag = tag
    try:
        article_tags_list = article_tag.find_all(['h2', 'h3', 'h4', 'p', 'ul', 'ol', 'figure'])
        print(article_tag.name, article_tag.attrs)
    except:
        print('Тег статьи не определен!')

а дальше разбор по тегам. вроде бы рабочий вариант, брал наудачу статью с гугла - работает, текст тянет весь, картинки, правда, если они в div спрятаны, не собирает, но это опционально, такое не очень часто бывает. не придумал, как по другому организовать перебор тегов, кроме как через if-elif. tagN и if-elif правил уже по ходу дела, как попадался затык в очередной статье.
robisho
исправил, вроде так норм
     tag1 = soup.find('article')
    tag2 = soup.find_all('section')
    tag3 = soup.find_all('div', itemtype='http://schema.org/Article')
    tag4 = soup.find_all('div', class_=re.compile('[Cc]ontent'))
    tag5 = soup.find_all('div', class_=re.compile('entry'))
    tag6 = soup.find_all('div', id='content')
    tag7 = soup.find_all('div', class_=re.compile('container'))
    tags_list = []
    tags_list.append(tag2)
    tags_list.append(tag3)
    tags_list.append(tag4)
    tags_list.append(tag5)
    tags_list.append(tag6)
    tags_list.append(tag7)
    if tag1:
        if len(tag1.find_all('p')) > 3 or tag1.has_attr(itemtype='http://schema.org/Article'):
            article_tag = tag1
    else:
        for tags in tags_list:
            if tags:
                for tag in tags:
                    if len(tag.find_all('p')) > 3:
                        article_tag = tag
robisho
добрый день. помогите, пожалуйста, понять, где я ошибаюсь

сайт sympaty.net/20160613/chto-delat-posle-solyariya/

 tags_list = soup.find_all('div')
print('tags_list ', len(tags_list))  # 116 тегов
for tag in tags_list:
    if len(tag.find_all('p')) > 5:
        article_tag = tag

тегов div, удовлетворяющих условиям, более чем достаточно, но код не срабатывает.
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