`'а.
# In[15]:
div = page.findAll('div', class_='references-small')[0]
for link in div("a")[0:10]:
print(link['href'])
# Для экономии места я вывел только первые 10 ссылок. Это внутренние ссылки на другие фрагменты страницы, поэтому они начинаются с символа `#`. Легко увидеть, что мы получили то, что требовалось.
#
# ### Некоторые итоги
# Подведём некоторые итоги по поводу поиска информации в HTML-файлах:
#
# - Это всегда творческий процесс: все сайты разные и нет единого рецепта, как извлекать из них нужную информацию.
# - В первую очередь нужно посмотреть в исходник интересующей вас странички. Проще всего это делать с помощью инструментария веб-разработчика типа Firebug или встроенного инспектора кода в Firefox или аналогичных инструментов для других браузеров.
# - В HTML-дереве можно ориентироваться по названиям тегов, их классам, id'ам и другим свойствам.
# - Можно искать нужный элемент итеративно — сначала найти «большой» тег, который включает наш элемент, потом найти в нём элемент поменьше и т.д.
# ### API и XML
# Анализируя веб-страницы и извлекая из них информацию мы пытаемся написать программу, которая бы действовала как человек. Это бывает непросто. К счастью, всё чаще разнообразные сайты предлагают информацию, которую может легко обрабатывать не только человек, но и другая программа. Это называется API — application program interface. Обычный интерфейс — это способ взаимодействия человека с программой, а API — одной программы с другой. Например, вашего скрипта на Python с удалённым веб-сервером.
#
# Для хранения веб-страниц, которые читают люди, используется язык HTML. Для хранения произвольных структурированных данных, которыми обмениваются между собой программы, используются другие языки — в частности, язык XML, похожий на HTML. Вернее было бы сказать, что XML это *метаязык*, то есть способ описания языков. В отличие от HTML, набор тегов в XML-документе может быть произвольным (и определяется разработчиком конкретного диалекта XML). Например, если бы мы хотели описать в виде XML некоторую студенческую группу, это могло бы выглядеть так:
# ```xml
#
# 134
#
# Виталий
# Иванов
#
#
# Мария
# Петрова
#
#
# ```
# Для обработки XML-файлов можно использовать тот же пакет *Beautiful Soup*, который мы уже использовали для работы с HTML. Единственное различие — нужно указать дополнительный параметр `feautres="xml"` при вызове функции `BeautifulSoup` — чтобы он не искал в документе HTML-теги.
# In[17]:
group = """
134
Виталий
Иванов
Мария
Петрова
"""
# In[20]:
obj = BeautifulSoup(group, features="xml")
print(obj.prettify())
# Вот так мы можем найти в нашем XML-документе номер группы:
# In[21]:
obj.group.number.string
# Это значит «в объекте `obj` найти тег `group` в нём найти тег `number` и выдать в виде строки то, что в нём содержится.
#
# А вот так можно перечислить всех студентов:
# In[30]:
for student in obj.group.findAll('student'):
print(student.lastname.string, student.firstname.string)
# ### Получаем список статей из категории в Википедии
# Допустим, нам потребовалось получить список всех статей из некоторой категории в Википедии. Мы могли бы открыть эту категорию в браузере и дальше действовать теми методами, которые обсуждались выше. Однако, на наше счастье разработчики Википедии сделали удобное API. Чтобы научиться с ним работать, придётся познакомиться с [документацией](https://www.mediawiki.org/wiki/API:Main_page) (так будет с любым API), но это кажется сложным только в первый раз. Ну хорошо, в первые 10 раз. Или 20. Потом будет проще.
#
# Итак, приступим. Взаимодействие с сервером при помощи API происходит с помощью отправки специальным образом сформированных запросов и получения ответа в одном из машинночитаемых форматов. Нас будет интересовать формат XML, хотя бывают и другие (позже мы познакомимся с JSONN). А вот такой запрос мы можем отправить:
# https://en.wikipedia.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Physics&cmsort=timestamp&cmdir=desc&format=xmlfm
# Строка `https://en.wikipedia.org/w/api.php` (до знака вопроса) — это *точка входа* в API. Всё, что идёт после знака вопроса — это, собственно, запрос. Он представляет собой что-то вроде словаря и состоит из пар «ключ=значение», разделяемых амперсандом `&`. Некоторые символы приходится кодировать специальным образом.
#
# Например, в адресе выше сказано, что мы хотим сделать запрос (`action=query`), перечислить элементы категории `list=categorymembers`, в качестве категории, которая нас интересует, указана `Category:Physics` (`cmtitle=Category:Physics`) и указаны некоторые другие параметры. Если кликнуть по этой ссылке, откроется примерно такая штука:
# ```xml
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
# ```
# Мы видим здесь разные теги, и видим, что нас интересуют теги `
`, находящиеся внутри тега ``.
#
# Давайте сделаем соответствующий запрос с помощью Python. Для этого нам понадобится уже знакомый модуль `requests`.
# In[23]:
url = "https://en.wikipedia.org/w/api.php"
params = {
'action':'query',
'list':'categorymembers',
'cmtitle': 'Category:Physics',
'format': 'xml'
}
g = requests.get(url, params=params)
# Как видно, список параметров мы передаем в виде обычного словаря. Посмотрим, что получилось.
# In[24]:
g.ok
# Всё хорошо. Теперь используем *Beautiful Soup* для обработки этого XML.
# In[25]:
data = BeautifulSoup(g.text, features='xml')
# In[26]:
print(data.prettify())
# Найдём все вхождения тега `` и выведем их атрибут `title`:
# In[27]:
for cm in data.api.query.categorymembers("cm"):
print(cm['title'])
# Можно было упростить поиск ``, не указывая «полный путь» к ним:
# In[28]:
for cm in data("cm"):
print(cm['title'])
# По умолчанию сервер вернул нам список из 10 элементов. Если мы хотим больше, нужно воспользоваться элементом `continue` — это своего рода гиперссылка на следующие 10 элементов.
# In[29]:
data.find("continue")['cmcontinue']
# Мне пришлось использовать метод `find()` вместо того, чтобы просто написать `data.continue`, потому что `continue` в Python имеет специальный смысл.
#
# Теперь добавим `cmcontinue` в наш запрос и выполним его ещё раз:
# In[30]:
params['cmcontinue'] = data.api("continue")[0]['cmcontinue']
# In[31]:
g = requests.get(url, params=params)
data = BeautifulSoup(g.text, features='xml')
for cm in data.api.query.categorymembers("cm"):
print(cm['title'])
# Мы получили следующие 10 элементов из категории. Продолжая таким образом, можно выкачать её даже целиком (правда, для этого потребуется много времени).
#
# Аналогичным образом реализована работа с разнообразными другими API, имеющимися на разных сайтах. Где-то API является полностью открытым (как в Википедии), где-то вам потребуется зарегистрироваться и получить application id и какой-нибудь ключ для доступа к API, где-то попросят даже заплатить (например, автоматический поиск в Google стоит что-то вроде 5 долларов за 100 запросов). Есть API, которые позволяют только читать информацию, а бывают и такие, которые позволяют её править. Например, можно написать скрипт, который будет автоматически сохранять какую-то информацию в Google Spreadsheets. Всякий раз при использовании API вам придётся изучить его документацию, но это в любом случае проще, чем обрабатывать HTML-код. Иногда удаётся упростить доступ к API, используя специальные библиотеки.