Лирическое отступление


В рамках научно-исследовательской работы в вузе я столкнулся с такой задачей, как классификация текстовой информации. По сути, мне нужно было создать алгоритм, который, обрабатывая определенный текстовый документ на входе, вернул бы мне на выходе массив, каждый элемент которого являлся бы мерой принадлежности этого текста (вероятностью или степенью уверенности) к одной из заданных тематик.

В данной статье речь пойдет не о решении задачи классификации конкретно, а о попытке автоматизировать наиболее скучный этап разработки рубрикатора — создание обучающей выборки.

Когда лень работать руками


Первая и самая очевидная для меня мысль – написать простой метапоисковый алгоритм на Python. Другими словами, вся автоматизация сводится к использованию выдачи другой поисковой машины (Google Search) за неимением своих баз данных. Сразу оговорюсь, есть уже готовые библиотеки, решающие подобную задачу, например pygoogle.

Ближе к делу


Для HTTP-запросов я использовал requests, а для извлечения ссылок из поисковой выдачи — библиотеку для парсинга BeautifulSoup. Вот что получилось:

from bs4 import BeautifulSoup
import requests
query = input('What are you searching for?:   ' )
url ='http://www.google.com/search?q='
page = requests.get(url + query)
soup = BeautifulSoup(page.text)
h3 = soup.find_all("h3",class_="r")
for elem in h3:
	elem=elem.contents[0]
	link=("https://www.google.com" + elem["href"])
	print(link)

Я дергал лишь ссылки на сайты, которые на странице результатов поиска Chrome находятся внутри тэгов {h3 class=«r»}.

Чтож, отлично, теперь попробуем забрать ссылки, обойдя несколько страниц браузера:

from bs4 import BeautifulSoup
import requests
query = input('What are you searching for?:  ' )
number = input('How many pages:  ' )
url ='http://www.google.com/search?q='
page = requests.get(url + query)
for index in range(int(number)):
	soup = BeautifulSoup(page.text)
	next_page=soup.find("a",class_="fl")
	next_link=("https://www.google.com"+next_page["href"])
	h3 = soup.find_all("h3",class_="r")
	for elem in h3:
		elem=elem.contents[0]
		link=("https://www.google.com" + elem["href"])
		print(link)
	page = requests.get(next_link)

Адрес следующей страницы Chrome хранит в тэге {a class=«fl»}.

Ну и напоследок попробуем достать информацию с какой-нибудь страницы и сделать из нее словарь для будущего рубрикатора. Забирать необходимую информацию будем с той же Википедии:

from bs4 import BeautifulSoup
import requests
dict=""
query = input('What are you searching for?: ' )
url ='http://www.google.com/search?q='
page = requests.get(url + query)
soup = BeautifulSoup(page.text)
h3 = soup.find_all("h3",class_="r")
for elem in h3:
	elem=elem.contents[0]
	elem = elem["href"]
	if "wikipedia" in elem:
		link=("https://www.google.com" + elem)
		break
page = requests.get(link)
soup = BeautifulSoup(page.text)
text = soup.find(id="mw-content-text")
p= text.find("p")
while p != None:
	dict+=p.get_text()+"\n"
	p = p.find_next("p")
dict=dict.split()

Для запроса «god» получается неплохой такой словарь на 3.500 терминов, который, по правде говоря, придется дорабатывать напильником, удаляя знаки препинания, ссылки, стоп-слова и прочий «мусор».

Вывод


Подводя итог проделанной работы, надо заметить, что словарь конечно получился «сырой» и «натаскивание» парсера на конкретный ресурс требует времени на изучение его структуры. Это наталкивает на простую мысль — генерацию обучающей выборки стоит осуществлять самому, или пользоваться готовыми базами данных.

С другой стороны, при должной внимательности к написанию парсера (очистить html разметку от лишних тегов не составляет большого труда) и большом количестве классов, некоторая степень автоматизации может добавить рубрикатору необходимую гибкость.

Ссылки на используемый инструментарий


BeautifulSoup: www.crummy.com/software/BeautifulSoup
Requests: docs.python-requests.org/en/latest

Комментарии (10)


  1. Kwent
    09.12.2015 13:24
    +1

    Сам занимался похожим, но решил задачу по-другому: брал новостные сайты (там тексты уже размечены человеком :) ), достаточно пары тройки крупных сайтов для нескольких десятков тысяч текстов.


    1. livid_hour
      09.12.2015 17:48

      А о каком виде разметки идет речь? Ключевые слова являются ссылками на другие ресурсы, или же это встраиваемая в сайт разметка, которую тот же гугл предлагает в целях «правильной интерпретации информации»?


      1. Kwent
        09.12.2015 18:22

        z использовал ту штуку, которая, например, на ленте называется «рубрика» (то есть каждая статья отнесена к политике, экономике, спорту и т.п.), ее можно получить как просто качая статьи из категорий, и так же она есть непосредственно в html разметке страницы статьи


        1. livid_hour
          10.12.2015 14:43

          Если у вас была цель сделать качественную выборку большого объема, плюс сделать это быстро и просто — вы выбрали наиболее правильный вариант)
          Мне не удалось в полной мере отразить свою задумку в статье, но подход у меня был скорее исследовательский, чем направленный на извлечение практической пользы
          Я хотел бы сделать нечто универсальное, дабы минимизировать участие человека в составлении выборки


          1. Kwent
            10.12.2015 15:04

            Я не думаю, что эта выборка является качественной, она не репрезентативна в том плане, что по факту используется ограниченное число авторов текстов (журналисты сайтов, их сравнительно мало), из-за чего могут быть ошибки связанные с «обучился на стиль», а по поводу участия человека, так его тут нет, только запуск программы.


            1. livid_hour
              10.12.2015 21:19

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


  1. JIghtuse
    09.12.2015 16:49

    Хотел было написать про googlecl, но он, оказывается, всё. Зато нашёл пакет duckduckgo для одноименного поисковика (есть в репозитории Fedora). По-видимому, не первой свежести проект, но работает. Исходник здесь.

    Скрытый текст
    $ duckduckgo cat
    WWW::DuckDuckGo HTTP request failed: 501 Protocol scheme 'https' is not supported (LWP::Protocol::https not installed) at /usr/share/perl5/vendor_perl/WWW/DuckDuckGo.pm line 116.
    WWW::DuckDuckGo Can't access https://api.duckduckgo.com/ falling back to: http://api.duckduckgo.com/ at /usr/share/perl5/vendor_perl/WWW/DuckDuckGo.pm line 117.
    
    Cat (disambiguation)
    
    Related Topics:
     - Cat A small, typically furry, domesticated, and carnivorous mammal. They are often called house...
       https://duckduckgo.com/Cat
     - Cat ZinganoAn American mixed martial artist who competes in the UFC. On April 13, 2013, she became the first...
       https://duckduckgo.com/Cat_Zingano
     - Cat Stevens A British singer-songwriter, multi-instrumentalist, humanitarian, and education philanthropist.
       https://duckduckgo.com/Cat_Stevens
    $
    


  1. 10.12.2015 09:25
    +1

    Могу также порекомендовать GoogleScrapper для извлечения ссылок, заголовков и сниппетов из поисковой выдачи. Хотя свой корпус новостных текстов собирал так же как и Kwent, кроулер ходил по рубрикам крупных новостных сайтов, а newspaper делал всю остальную работу.

    Если можно в двух словах, что будете использовать непосредственно для классификации текстов?


    1. Kwent
      10.12.2015 11:23

      Надеюсь, решение будет в тренде =)


    1. livid_hour
      10.12.2015 14:55

      Для обучения модели я выбрал два наиболее часто используемых подхода — Метод опорных векторов и Наивный Байесовский алгоритм классификации (два опять же для сравнения)
      В в планах также применить нейронные сети