Веб-скрапинг — это процесс сбора информации из Интернета для автоматизации громоздких задач. Библиотеки Python, запросы и Beautiful Soup — мощные инструменты для извлечения данных из Интернета. В этом уроке мы создадим веб-скрейпер, который извлекает списки вакансий аналитика данных с действительного веб-сайта. Для этого наш парсер будет анализировать HTML-код на сайте, чтобы собрать соответствующую информацию.
Весь код, относящийся к этому руководству, можно найти здесь.
Обратите внимание, что перед очисткой каких-либо данных важно ознакомиться с условиями обслуживания веб-сайта, поскольку некоторые веб-сайты запрещают очистку данных.
Краткое введение в HTML и Beautiful Soup
Прежде чем углубляться в конкретные детали извлечения данных из Действительно, мы сначала узнаем об основах HTML. Как правило, нам нужно очистить часть веб-сайта, написанную на HTML. Базовое понимание HTML поможет нам определить HTML-код, который необходимо удалить.
Beautiful Soup — это библиотека Python, используемая для извлечения информации из файлов HTML и XML. В этом руководстве мы будем использовать анализатор HTML для чтения содержимого веб-сайта Indeed, написанного на HTML. Базовое введение в Beautiful Soup поможет нам понять древовидную структуру объектов Python в Beautiful Soup. Во-первых, давайте начнем с основ HTML.
Основы HTML
Язык разметки гипертекста, или сокращенно HTML, представляет собой систему форматирования для отображения материалов, полученных через Интернет. Используя этот язык, пользователи могут создавать и структурировать разделы, абзацы и ссылки, используя элементы, теги и атрибуты. Веб-браузер, такой как Chrome, считывает эти элементы, теги и атрибуты для отображения содержимого документа на понятном человеку языке (английском). Простая структура HTML-страницы представлена на рисунке ниже.
Давайте скопируем этот код в блокнот и сохраним файл блокнота как page.html. Когда мы открываем файл page.html в Google Chrome, он выглядит так.
Хорошо, но что такое тег, элемент и атрибут в HTML.
Тег.Тег — это скрытое ключевое слово на веб-странице, которое определяет, как веб-браузер должен форматировать и отображать содержимое. В HTML есть теги для заголовков, абзацев, ссылок, таблиц, заголовков и т. д. Тег содержит свое имя в угловых скобках и может быть парным, что составляет начальный и конечный теги, определяющие конкретный фрагмент кода, текст или другие элементы. теги. На рисунке выше каждое ключевое слово, содержащееся в ‹›, является тегом и имеет определенную цель. Например, тег ‹h1› используется для определения заголовков первого уровня в HTML.
Элемент. HTML-элемент — это все, что находится между начальным и конечным тегами. На рисунке выше «‹h1› Заголовок 1 ‹/h1›» является элементом.
Атрибут. Элемент в HTML может иметь атрибуты для предоставления дополнительной информации о нем. Атрибуты всегда определяются в начальном теге и обычно представляют собой пары имя/значение. Например, в последнем коде можно использовать атрибут стиля с тегом ‹p›, чтобы придать этому элементу дополнительные свойства. Строка ниже напечатает текст пункта 1 синим цветом.
‹p style=‘color:blue;’ › Параграф 1 ‹/p›
Двумя наиболее важными атрибутами, которые пригодятся при парсинге веб-контента, являются class и id.
Допустим, мы хотим иметь один и тот же стиль для нескольких элементов (в этом примере один и тот же цвет текста для нескольких абзацев). Это можно сделать, либо поместив атрибут стиля несколько раз для каждого из элементов, либо определив класс в начале и используя его в качестве атрибута для всех элементов. Последний способ более эффективен. Таким образом, один и тот же класс style может использоваться как для абзаца 1, так и для абзаца 2 следующим образом:
‹p class=‘style’ › Параграф 1 ‹/p›
Точно так же атрибут id используется для указания уникального идентификатора элемента, чтобы предоставить ему дополнительные свойства. Идентификатор и класс используются аналогичным образом для элемента, за исключением того, что имя класса может использоваться несколькими элементами, а имя идентификатора должно использоваться только одним элементом HTML на странице.
Основы красивого супа
Чтобы понять основные методы и объекты Beautiful Soup, давайте воспользуемся HTML-кодом, показанным на первом рисунке. Я добавил несколько классов и ссылок в этот код, чтобы лучше понять процесс синтаксического анализа и создания объектов в Beautiful Soup. Наш окончательный HTML-код выглядит так и присваивается переменной html_code.
html_code = """ <html> <head> <title>Page Title</title> <head> <body> <h1> Heading 1 </h1> <p class="style"> Paragraph 1 </p> <p class="style"> Paragraph 2 </p> <a href="https://www.google.com/" class="Alphabet" id="link1"> Google </a> <a href="https://www.google.com/doodles" class="Alphabet" id="link2"> Doodle </a> </body> </html>"""
Теперь давайте проанализируем этот HTML-код с помощью HTML-парсера Beautiful Soup.
soup = bs(html_code, "html.parser")
Суп-объект — это дерево сложных объектов Python. Здесь описаны некоторые из важных объектов, которые используются при очистке веб-страниц.
Тег. Объект тега соответствует тегу HTML в документе. Этот объект является атрибутом (потомком) объекта супа и содержит элемент, связанный с тегом HTML.
soup = bs(r'<p class="style">Paragraph 1</p>', "html.parser") tag = soup.p #the element with html tag p print(tag) print(type(tag)) #tag object of Beautiful Soup
выход
<p class="style">Paragraph 1</p> <class 'bs4.element.Tag'>
Тег может содержать другие теги (элементы). Эти элементы называются дочерними элементами тега. Мы можем перемещаться по этим дочерним элементам, используя цепочку атрибутов.
soup = bs(html_code, "html.parser") soup.body.h1.p <p class="style">Paragraph 1</p> #children of object h1
Атрибуты. Тег может иметь несколько атрибутов. Эти атрибуты могут быть атрибутами с одним значением (например, атрибут id в HTML) или многозначными атрибутами (например, атрибут класса в HTML). Вы можете получить доступ к атрибутам тега, рассматривая его как словарь. Значения многозначных атрибутов возвращаются в виде списка.
print(soup.a['id']) print(soup.a['class']) link1 ['Alphabet']
Из этих примеров видно, что мы можем получить доступ только к одному HTML-тегу, используя метод .attribute. Чтобы получить все теги с одинаковыми именами, мы можем использовать функцию find_all из Beautiful Soup. В приведенном ниже примере функция find_all возвращает список тегов с именем a.
soup.find_all('a') [<a class="Alphabet" href="https://www.google.com/" id="link1">Google</a>, <a class="Alphabet" href="https://www.google.com/doodles" id="link2">Doodle</a>]
Мы можем передавать различные аргументы функции find_all для выбора определенных тегов.
#a tag with ref google.com print(soup.find_all('a', attrs={'href':'https://www.google.com/'})) #a tag with id link2 print(soup.find_all('a', attrs={'id':'link2'})) #p tag with class style print(soup.find_all('p', attrs={'class':'style'})) [<a class="Alphabet" href="https://www.google.com/" id="link1">Google</a>] [<a class="Alphabet" href="https://www.google.com/doodles" id="link2">Doodle</a>] [<p class="style">Paragraph 1</p>, <p class="style">Paragraph 2</p>]
Теперь давайте воспользуемся Beautiful Soup для извлечения данных о вакансиях из Indeed.
Сбор списков вакансий аналитика данных с сайта Indeed:
Во-первых, мы должны понимать структуру веб-сайта, чтобы собирать данные, которые имеют отношение к нам. На сайте Indeed мы видим пользовательский интерфейс, как показано на рисунке ниже. Кроме того, мы видим, что когда мы взаимодействуем с веб-сайтом, URL-адрес веб-сайта меняется. Для этого урока я ищу списки вакансий аналитика данных в городе Торонто в радиусе 100 км.
Скопируйте URL-адрес этого поиска работы и используйте библиотеку запросов, чтобы получить содержимое страницы по этому URL-адресу.
URL = 'https://ca.indeed.com/jobs?q=%22data%20Analyst%22&l=Toronto%2C%20ON&radius=100&vjk=b1e75865f696b55e' page = req.get(URL)
Вы можете проверить содержимое этой страницы, используя page.text. Когда мы просматриваем эту страницу, мы видим на рисунке ниже, что часть карточки вакансии с информацией (название компании, должность, местоположение и зарплата) находится внутри тега «td» и класса «resultContent». Давайте сохраним данные с этой карты в списке с именем res. В этом списке хранятся данные обо всех заданиях.
res = soup.find_all('td', 'resultContent')
Теперь давайте найдем часть HTML-кода, представляющую название должности для первой работы. Когда мы наводим указатель мыши на название должности и щелкаем правой кнопкой мыши для проверки, мы видим, что название должности расположено в виде строки в теге span, который является дочерним элементом тега h2. Кроме того, тег h2 является потомком тега td.
res[0].find('h2').text 'newData Analyst'
Здесь res[0] дает нам информацию о должности, компании, местоположении и зарплате. Часть res[0].find(‘h2’) дает нам элемент, связанный с тегом h2. Наконец, res[0].find(‘h2’).text дает нам строковую часть элемента. Строка состоит из двух частей: new и job title. Мы можем удалить из него «новое», используя функцию замены.
res[0].find('h2').text.replace('new','') 'Data Analyst'
Точно так же мы можем найти теги, связанные с местом работы, зарплатой, названием компании и датой публикации вакансии.
print(res[0].find('h2').text.replace('new','')) #job title print(res[0].pre.span.string) #company name print(res[5].find('div', 'salary-snippet').get('aria-label')) #salary print(res[0].find('div', 'companyLocation').text) #job location print(soup.find_all('span', 'date')[0].text) #job posting date Data Analyst Loblaw Companies Limited $22.65 to $24.56 an hour Brampton, ON Posted 1 day ago
Здесь обратите внимание, что я использовал res[5] для получения зарплаты, потому что в первой карточке зарплата не упоминается, поэтому я использовал шестую карточку. Кроме того, дата публикации вакансии находится внизу карточки, поэтому я использовал объект супа, чтобы найти все теги span, имеющие класс даты.
Теперь у нас есть представление о том, как получить необходимую информацию для одной карты. Давайте получим информацию обо всех картах на одной странице. Для этого мы можем перебрать все элементы списка res, содержащего информацию о карточках, на одной странице. Для этого реализована функция one_page().
#store the result of each variable for every job on a page in a list job_title = [] company = [] location = [] salary = [] date = [] def one_page(res, job_title, company, location, salary, date): for element in res: job_title.append(element.find('h2').text.replace('new','')) company.append(element.pre.span.string) location.append(element.find('div', 'companyLocation').text) #use try and except statment to get the salary. If salary is #not mentioned, store it as an empty string try: salary.append(element.find('div', 'salary snippet').get('aria-label')) except AttributeError: salary.append('') #loop through all the cards to get posted date for dat in soup.find_all('span', 'date'): date.append(dat.text) return (job_title, company, location, salary, date)
Эта функция даст нам данные по вакансиям на первой странице. Чтобы получить данные со всех страниц, используйте цикл while до последней страницы.
#let's collect data for all the pages (i am collecting data for #first 20 pages). If you want to collect data for all the pages you #can use while loop instead of for loop. for i in range(20): #data for first page one_page(res, job_title, company, location, salary, date) #use a try statment to get the url of next page try: url = 'https://ca.indeed.com' + soup.find_all('a', {'aria- label':'Next'})[0].get('href') except: break #based on the url for each page update vlaues of page, soup, res page = req.get(url) soup = bs(page.text, "html.parser") res = soup.find_all('td', 'resultContent')
Сохраните эти данные во фрейме данных для дальнейшего анализа. Кроме того, вы можете экспортировать его в файл CSV для последующего использования.
df_jobs = pd.DataFrame(data={'Job_title':job_title, 'Company':company, 'Location':location, 'Salary':salary, 'Date':date}) df_jobs.to_csv(r'address\job_data.csv') df_jobs.head()
Заключение
В этом уроке мы изучили основы HTML и Beautiful Soup для парсинга веб-страниц. Мы использовали Beautiful Soup для сбора списков вакансий, связанных с ролью аналитика данных в Торонто, с сайта Indeed. Здесь я собрал данные только по региону Торонто, вы можете определить местоположение как переменную в URL-адресе, чтобы получить списки вакансий для разных городов. Наконец, данные экспортируются в файл CSV, который можно использовать позже для анализа.
Надеюсь, вам понравился этот урок. Не стесняйтесь комментировать с вашими вопросами и предложениями :)